19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*11832Slinton static char sccsid[] = "@(#)process.c 1.7 04/03/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 */ 6111768Slinton int mask; /* process status word */ 6211768Slinton 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 */ 6911768Slinton 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 } 369*11832Slinton if (p->status != STOPPED) { 370*11832Slinton error("program unexpectedly exited with %d", p->exitval); 371*11832Slinton } 3729677Slinton } 3739677Slinton 3749677Slinton /* 3759677Slinton * Continue execution up to the next source line. 3769677Slinton * 3779677Slinton * There are two ways to define the next source line depending on what 3789677Slinton * is desired when a procedure or function call is encountered. Step 3799677Slinton * stops at the beginning of the procedure or call; next skips over it. 3809677Slinton */ 3819677Slinton 3829677Slinton /* 3839677Slinton * Stepc is what is called when the step command is given. 3849677Slinton * It has to play with the "isstopped" information. 3859677Slinton */ 3869677Slinton 3879677Slinton public stepc() 3889677Slinton { 3899677Slinton if (not isstopped) { 3909677Slinton error("can't continue execution"); 3919677Slinton } 3929677Slinton isstopped = false; 3939677Slinton dostep(false); 3949677Slinton isstopped = true; 3959677Slinton } 3969677Slinton 3979677Slinton public next() 3989677Slinton { 3999677Slinton if (not isstopped) { 4009677Slinton error("can't continue execution"); 4019677Slinton } 4029677Slinton isstopped = false; 4039677Slinton dostep(true); 4049677Slinton isstopped = true; 4059677Slinton } 4069677Slinton 4079677Slinton public step() 4089677Slinton { 4099677Slinton dostep(false); 4109677Slinton } 4119677Slinton 4129677Slinton /* 4139677Slinton * Resume execution up to the given address. It is assumed that 4149677Slinton * no breakpoints exist between the current address and the one 4159677Slinton * we're stepping to. This saves us from setting all the breakpoints. 4169677Slinton */ 4179677Slinton 4189677Slinton public stepto(addr) 4199677Slinton Address addr; 4209677Slinton { 4219677Slinton setbp(addr); 4229677Slinton resume(); 4239677Slinton unsetbp(addr); 4249677Slinton if (not isbperr()) { 4259677Slinton printstatus(); 4269677Slinton } 4279677Slinton } 4289677Slinton 4299677Slinton /* 4309677Slinton * Print the status of the process. 4319677Slinton * This routine does not return. 4329677Slinton */ 4339677Slinton 4349677Slinton public printstatus() 4359677Slinton { 4369843Slinton if (process->status == FINISHED) { 4379843Slinton exit(0); 4389843Slinton } else { 4399843Slinton curfunc = whatblock(pc); 4409677Slinton getsrcpos(); 4419843Slinton if (process->signo == SIGINT) { 4429843Slinton isstopped = true; 4439843Slinton printerror(); 4449843Slinton } else if (isbperr() and isstopped) { 4459843Slinton printf("stopped "); 44611172Slinton printloc(); 44711172Slinton putchar('\n'); 4489843Slinton if (curline > 0) { 4499843Slinton printlines(curline, curline); 4509843Slinton } else { 4519843Slinton printinst(pc, pc); 4529843Slinton } 4539843Slinton erecover(); 4549677Slinton } else { 4559843Slinton fixbps(); 4569843Slinton fixintr(); 4579677Slinton isstopped = true; 4589677Slinton printerror(); 4599677Slinton } 4609677Slinton } 4619677Slinton } 4629677Slinton 4639677Slinton /* 46411172Slinton * Print out the current location in the debuggee. 46511172Slinton */ 46611172Slinton 46711172Slinton public printloc() 46811172Slinton { 46911172Slinton printf("in "); 47011172Slinton printname(stdout, curfunc); 47111172Slinton putchar(' '); 47211172Slinton if (curline > 0) { 47311172Slinton printsrcpos(); 47411172Slinton } else { 47511172Slinton printf("at 0x%x", pc); 47611172Slinton } 47711172Slinton } 47811172Slinton 47911172Slinton /* 4809677Slinton * Some functions for testing the state of the process. 4819677Slinton */ 4829677Slinton 4839677Slinton public Boolean notstarted(p) 4849677Slinton Process p; 4859677Slinton { 4869677Slinton return (Boolean) (p->status == NOTSTARTED); 4879677Slinton } 4889677Slinton 4899677Slinton public Boolean isfinished(p) 4909677Slinton Process p; 4919677Slinton { 4929677Slinton return (Boolean) (p->status == FINISHED); 4939677Slinton } 4949677Slinton 4959677Slinton /* 4969677Slinton * Return the signal number which stopped the process. 4979677Slinton */ 4989677Slinton 4999677Slinton public Integer errnum(p) 5009677Slinton Process p; 5019677Slinton { 5029677Slinton return p->signo; 5039677Slinton } 5049677Slinton 5059677Slinton /* 5069677Slinton * Return the termination code of the process. 5079677Slinton */ 5089677Slinton 5099677Slinton public Integer exitcode(p) 5109677Slinton Process p; 5119677Slinton { 5129677Slinton return p->exitval; 5139677Slinton } 5149677Slinton 5159677Slinton /* 5169677Slinton * These routines are used to access the debuggee process from 5179677Slinton * outside this module. 5189677Slinton * 5199677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 52011560Slinton * The system generates an I/O error when a ptrace fails, we assume 52111560Slinton * during a read/write to the process that such an error is due to 52211560Slinton * a misguided address and ignore it. 5239677Slinton */ 5249677Slinton 5259677Slinton extern Intfunc *onsyserr(); 5269677Slinton 5279677Slinton private badaddr; 5289677Slinton private rwerr(); 5299677Slinton 5309677Slinton /* 5319677Slinton * Read from the process' instruction area. 5329677Slinton */ 5339677Slinton 5349677Slinton public iread(buff, addr, nbytes) 5359677Slinton char *buff; 5369677Slinton Address addr; 5379677Slinton int nbytes; 5389677Slinton { 5399677Slinton Intfunc *f; 5409677Slinton 5419677Slinton f = onsyserr(EIO, rwerr); 5429677Slinton badaddr = addr; 5439677Slinton if (coredump) { 5449677Slinton coredump_readtext(buff, addr, nbytes); 5459677Slinton } else { 5469677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 5479677Slinton } 5489677Slinton onsyserr(EIO, f); 5499677Slinton } 5509677Slinton 5519677Slinton /* 5529677Slinton * Write to the process' instruction area, usually in order to set 5539677Slinton * or unset a breakpoint. 5549677Slinton */ 5559677Slinton 5569677Slinton public iwrite(buff, addr, nbytes) 5579677Slinton char *buff; 5589677Slinton Address addr; 5599677Slinton int nbytes; 5609677Slinton { 5619677Slinton Intfunc *f; 5629677Slinton 5639677Slinton if (coredump) { 5649677Slinton error("no process to write to"); 5659677Slinton } 5669677Slinton f = onsyserr(EIO, rwerr); 5679677Slinton badaddr = addr; 5689677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 5699677Slinton onsyserr(EIO, f); 5709677Slinton } 5719677Slinton 5729677Slinton /* 5739677Slinton * Read for the process' data area. 5749677Slinton */ 5759677Slinton 5769677Slinton public dread(buff, addr, nbytes) 5779677Slinton char *buff; 5789677Slinton Address addr; 5799677Slinton int nbytes; 5809677Slinton { 5819677Slinton Intfunc *f; 5829677Slinton 5839677Slinton f = onsyserr(EIO, rwerr); 5849677Slinton badaddr = addr; 5859677Slinton if (coredump) { 5869677Slinton coredump_readdata(buff, addr, nbytes); 5879677Slinton } else { 5889677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 5899677Slinton } 5909677Slinton onsyserr(EIO, f); 5919677Slinton } 5929677Slinton 5939677Slinton /* 5949677Slinton * Write to the process' data area. 5959677Slinton */ 5969677Slinton 5979677Slinton public dwrite(buff, addr, nbytes) 5989677Slinton char *buff; 5999677Slinton Address addr; 6009677Slinton int nbytes; 6019677Slinton { 6029677Slinton Intfunc *f; 6039677Slinton 6049677Slinton if (coredump) { 6059677Slinton error("no process to write to"); 6069677Slinton } 6079677Slinton f = onsyserr(EIO, rwerr); 6089677Slinton badaddr = addr; 6099677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 6109677Slinton onsyserr(EIO, f); 6119677Slinton } 6129677Slinton 6139677Slinton /* 6149677Slinton * Error handler. 6159677Slinton */ 6169677Slinton 6179677Slinton private rwerr() 6189677Slinton { 61911560Slinton /* 62011560Slinton * Current response is to ignore the error and let the result 62111560Slinton * (-1) ripple back up to the process. 62211560Slinton * 6239677Slinton error("bad read/write process address 0x%x", badaddr); 62411560Slinton */ 6259677Slinton } 6269677Slinton 6279677Slinton /* 6289677Slinton * Ptrace interface. 6299677Slinton */ 6309677Slinton 6319677Slinton /* 6329677Slinton * This magic macro enables us to look at the process' registers 6339677Slinton * in its user structure. Very gross. 6349677Slinton */ 6359677Slinton 6369677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 6379677Slinton 6389677Slinton #define WMASK (~(sizeof(Word) - 1)) 6399677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 6409677Slinton 6419677Slinton #define FIRSTSIG SIGINT 6429677Slinton #define LASTSIG SIGQUIT 6439677Slinton #define ischild(pid) ((pid) == 0) 6449677Slinton #define traceme() ptrace(0, 0, 0, 0) 6459677Slinton #define setrep(n) (1 << ((n)-1)) 6469677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 6479677Slinton 6489677Slinton /* 6499677Slinton * Ptrace options (specified in first argument). 6509677Slinton */ 6519677Slinton 6529677Slinton #define UREAD 3 /* read from process's user structure */ 6539677Slinton #define UWRITE 6 /* write to process's user structure */ 6549677Slinton #define IREAD 1 /* read from process's instruction space */ 6559677Slinton #define IWRITE 4 /* write to process's instruction space */ 6569677Slinton #define DREAD 2 /* read from process's data space */ 6579677Slinton #define DWRITE 5 /* write to process's data space */ 6589677Slinton #define CONT 7 /* continue stopped process */ 6599677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 6609677Slinton #define PKILL 8 /* terminate the process */ 6619677Slinton 6629677Slinton /* 6639677Slinton * Start up a new process by forking and exec-ing the 6649677Slinton * given argument list, returning when the process is loaded 6659677Slinton * and ready to execute. The PROCESS information (pointed to 6669677Slinton * by the first argument) is appropriately filled. 6679677Slinton * 6689677Slinton * If the given PROCESS structure is associated with an already running 6699677Slinton * process, we terminate it. 6709677Slinton */ 6719677Slinton 6729677Slinton /* VARARGS2 */ 6739677Slinton private pstart(p, argv, infile, outfile) 6749677Slinton Process p; 6759677Slinton String argv[]; 6769677Slinton String infile; 6779677Slinton String outfile; 6789677Slinton { 6799677Slinton int status; 6809677Slinton 6819677Slinton if (p->pid != 0) { /* child already running? */ 6829677Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 6839677Slinton } 6849677Slinton psigtrace(p, SIGTRAP, true); 68511172Slinton if ((p->pid = vfork()) == -1) { 6869677Slinton panic("can't fork"); 6879677Slinton } 6889677Slinton if (ischild(p->pid)) { 68911172Slinton Fileid in, out; 69011172Slinton 6919677Slinton traceme(); 6929677Slinton if (infile != nil) { 69311172Slinton in = open(infile, 0); 69411172Slinton if (in == -1) { 69511172Slinton write(2, "can't read ", 11); 69611172Slinton write(2, infile, strlen(infile)); 69711172Slinton write(2, "\n", 1); 69811172Slinton _exit(1); 6999677Slinton } 70011172Slinton fswap(0, in); 7019677Slinton } 7029677Slinton if (outfile != nil) { 70311172Slinton out = creat(outfile, 0666); 70411172Slinton if (out == -1) { 70511172Slinton write(2, "can't write ", 12); 70611172Slinton write(2, outfile, strlen(outfile)); 70711172Slinton write(2, "\n", 1); 70811172Slinton _exit(1); 7099677Slinton } 71011172Slinton fswap(1, out); 7119677Slinton } 712*11832Slinton execv(argv[0], argv); 71311172Slinton write(2, "can't exec ", 11); 71411172Slinton write(2, argv[0], strlen(argv[0])); 71511172Slinton write(2, "\n", 1); 71611172Slinton _exit(1); 7179677Slinton } 7189677Slinton pwait(p->pid, &status); 7199677Slinton getinfo(p, status); 7209677Slinton if (p->status != STOPPED) { 7219677Slinton error("program could not begin execution"); 7229677Slinton } 7239677Slinton } 7249677Slinton 7259677Slinton /* 7269677Slinton * Continue a stopped process. The argument points to a PROCESS structure. 7279677Slinton * Before the process is restarted it's user area is modified according to 7289677Slinton * the values in the structure. When this routine finishes, 7299677Slinton * the structure has the new values from the process's user area. 7309677Slinton * 7319677Slinton * Pcont terminates when the process stops with a signal pending that 7329677Slinton * is being traced (via psigtrace), or when the process terminates. 7339677Slinton */ 7349677Slinton 7359677Slinton private pcont(p) 7369677Slinton Process p; 7379677Slinton { 7389677Slinton int status; 7399677Slinton 7409677Slinton if (p->pid == 0) { 7419677Slinton error("program not active"); 7429677Slinton } 7439677Slinton do { 7449677Slinton setinfo(p); 7459677Slinton sigs_off(); 7469677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 7479677Slinton panic("can't continue process"); 7489677Slinton } 7499677Slinton pwait(p->pid, &status); 7509677Slinton sigs_on(); 7519677Slinton getinfo(p, status); 7529677Slinton } while (p->status == STOPPED and not istraced(p)); 7539677Slinton } 7549677Slinton 7559677Slinton /* 7569677Slinton * Single step as best ptrace can. 7579677Slinton */ 7589677Slinton 7599677Slinton public pstep(p) 7609677Slinton Process p; 7619677Slinton { 7629677Slinton int status; 7639677Slinton 7649677Slinton setinfo(p); 7659677Slinton sigs_off(); 7669677Slinton ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 7679677Slinton pwait(p->pid, &status); 7689677Slinton sigs_on(); 7699677Slinton getinfo(p, status); 7709677Slinton } 7719677Slinton 7729677Slinton /* 7739677Slinton * Return from execution when the given signal is pending. 7749677Slinton */ 7759677Slinton 7769677Slinton public psigtrace(p, sig, sw) 7779677Slinton Process p; 7789677Slinton int sig; 7799677Slinton Boolean sw; 7809677Slinton { 7819677Slinton if (sw) { 7829677Slinton p->sigset |= setrep(sig); 7839677Slinton } else { 7849677Slinton p->sigset &= ~setrep(sig); 7859677Slinton } 7869677Slinton } 7879677Slinton 7889677Slinton /* 7899677Slinton * Don't catch any signals. 7909677Slinton * Particularly useful when letting a process finish uninhibited. 7919677Slinton */ 7929677Slinton 7939677Slinton public unsetsigtraces(p) 7949677Slinton Process p; 7959677Slinton { 7969677Slinton p->sigset = 0; 7979677Slinton } 7989677Slinton 7999677Slinton /* 8009677Slinton * Turn off attention to signals not being caught. 8019677Slinton */ 8029677Slinton 8039677Slinton private Intfunc *sigfunc[NSIG]; 8049677Slinton 8059677Slinton private sigs_off() 8069677Slinton { 8079677Slinton register int i; 8089677Slinton 8099677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8109677Slinton if (i != SIGKILL) { 8119677Slinton sigfunc[i] = signal(i, SIG_IGN); 8129677Slinton } 8139677Slinton } 8149677Slinton } 8159677Slinton 8169677Slinton /* 8179677Slinton * Turn back on attention to signals. 8189677Slinton */ 8199677Slinton 8209677Slinton private sigs_on() 8219677Slinton { 8229677Slinton register int i; 8239677Slinton 8249677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8259677Slinton if (i != SIGKILL) { 8269677Slinton signal(i, sigfunc[i]); 8279677Slinton } 8289677Slinton } 8299677Slinton } 8309677Slinton 8319677Slinton /* 8329677Slinton * Get process information from user area. 8339677Slinton */ 8349677Slinton 8359677Slinton private int rloc[] ={ 8369677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 8379677Slinton }; 8389677Slinton 8399677Slinton private getinfo(p, status) 8409677Slinton register Process p; 8419677Slinton register int status; 8429677Slinton { 8439677Slinton register int i; 8449677Slinton 8459677Slinton p->signo = (status&0177); 8469677Slinton p->exitval = ((status >> 8)&0377); 8479677Slinton if (p->signo != STOPPED) { 8489677Slinton p->status = FINISHED; 8499677Slinton } else { 8509677Slinton p->status = p->signo; 8519677Slinton p->signo = p->exitval; 8529677Slinton p->exitval = 0; 8539677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 8549677Slinton for (i = 0; i < NREG; i++) { 8559677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 8569677Slinton p->oreg[i] = p->reg[i]; 8579677Slinton } 85811768Slinton savetty(stdout, &(p->ttyinfo)); 8599677Slinton } 8609677Slinton } 8619677Slinton 8629677Slinton /* 8639677Slinton * Set process's user area information from given process structure. 8649677Slinton */ 8659677Slinton 8669677Slinton private setinfo(p) 8679677Slinton register Process p; 8689677Slinton { 8699677Slinton register int i; 8709677Slinton register int r; 8719677Slinton 8729677Slinton if (istraced(p)) { 8739677Slinton p->signo = 0; 8749677Slinton } 8759677Slinton for (i = 0; i < NREG; i++) { 8769677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 8779677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 8789677Slinton } 8799677Slinton } 88011768Slinton restoretty(stdout, &(p->ttyinfo)); 8819677Slinton } 8829677Slinton 8839677Slinton /* 8849677Slinton * Structure for reading and writing by words, but dealing with bytes. 8859677Slinton */ 8869677Slinton 8879677Slinton typedef union { 8889677Slinton Word pword; 8899677Slinton Byte pbyte[sizeof(Word)]; 8909677Slinton } Pword; 8919677Slinton 8929677Slinton /* 8939677Slinton * Read (write) from (to) the process' address space. 8949677Slinton * We must deal with ptrace's inability to look anywhere other 8959677Slinton * than at a word boundary. 8969677Slinton */ 8979677Slinton 8989677Slinton private Word fetch(); 8999677Slinton private store(); 9009677Slinton 9019677Slinton private pio(p, op, seg, buff, addr, nbytes) 9029677Slinton Process p; 9039677Slinton PioOp op; 9049677Slinton PioSeg seg; 9059677Slinton char *buff; 9069677Slinton Address addr; 9079677Slinton int nbytes; 9089677Slinton { 9099677Slinton register int i; 9109677Slinton register Address newaddr; 9119677Slinton register char *cp; 9129677Slinton char *bufend; 9139677Slinton Pword w; 9149677Slinton Address wordaddr; 9159677Slinton int byteoff; 9169677Slinton 9179677Slinton if (p->status != STOPPED) { 9189677Slinton error("program is not active"); 9199677Slinton } 9209677Slinton cp = buff; 9219677Slinton newaddr = addr; 9229677Slinton wordaddr = (newaddr&WMASK); 9239677Slinton if (wordaddr != newaddr) { 9249677Slinton w.pword = fetch(p, seg, wordaddr); 9259677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 9269677Slinton if (op == PREAD) { 9279677Slinton *cp++ = w.pbyte[i]; 9289677Slinton } else { 9299677Slinton w.pbyte[i] = *cp++; 9309677Slinton } 9319677Slinton nbytes--; 9329677Slinton } 9339677Slinton if (op == PWRITE) { 9349677Slinton store(p, seg, wordaddr, w.pword); 9359677Slinton } 9369677Slinton newaddr = wordaddr + sizeof(Word); 9379677Slinton } 9389677Slinton byteoff = (nbytes&(~WMASK)); 9399677Slinton nbytes -= byteoff; 9409677Slinton bufend = cp + nbytes; 9419677Slinton while (cp < bufend) { 9429677Slinton if (op == PREAD) { 9439677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 9449677Slinton } else { 9459677Slinton store(p, seg, newaddr, *((Word *) cp)); 9469677Slinton } 9479677Slinton cp += sizeof(Word); 9489677Slinton newaddr += sizeof(Word); 9499677Slinton } 9509677Slinton if (byteoff > 0) { 9519677Slinton w.pword = fetch(p, seg, newaddr); 9529677Slinton for (i = 0; i < byteoff; i++) { 9539677Slinton if (op == PREAD) { 9549677Slinton *cp++ = w.pbyte[i]; 9559677Slinton } else { 9569677Slinton w.pbyte[i] = *cp++; 9579677Slinton } 9589677Slinton } 9599677Slinton if (op == PWRITE) { 9609677Slinton store(p, seg, newaddr, w.pword); 9619677Slinton } 9629677Slinton } 9639677Slinton } 9649677Slinton 9659677Slinton /* 9669677Slinton * Get a word from a process at the given address. 9679677Slinton * The address is assumed to be on a word boundary. 9689677Slinton * 9699677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 9709677Slinton * to the instruction space since it is assumed to be pure. 9719677Slinton * 9729677Slinton * It is necessary to use a write-through scheme so that 9739677Slinton * breakpoints right next to each other don't interfere. 9749677Slinton */ 9759677Slinton 9769677Slinton private Integer nfetchs, nreads, nwrites; 9779677Slinton 9789677Slinton private Word fetch(p, seg, addr) 9799677Slinton Process p; 9809677Slinton PioSeg seg; 9819677Slinton register int addr; 9829677Slinton { 9839677Slinton register CacheWord *wp; 9849677Slinton register Word w; 9859677Slinton 9869677Slinton switch (seg) { 9879677Slinton case TEXTSEG: 9889677Slinton ++nfetchs; 9899677Slinton wp = &p->word[cachehash(addr)]; 9909677Slinton if (addr == 0 or wp->addr != addr) { 9919677Slinton ++nreads; 9929677Slinton w = ptrace(IREAD, p->pid, addr, 0); 9939677Slinton wp->addr = addr; 9949677Slinton wp->val = w; 9959677Slinton } else { 9969677Slinton w = wp->val; 9979677Slinton } 9989677Slinton break; 9999677Slinton 10009677Slinton case DATASEG: 10019677Slinton w = ptrace(DREAD, p->pid, addr, 0); 10029677Slinton break; 10039677Slinton 10049677Slinton default: 10059677Slinton panic("fetch: bad seg %d", seg); 10069677Slinton /* NOTREACHED */ 10079677Slinton } 10089677Slinton return w; 10099677Slinton } 10109677Slinton 10119677Slinton /* 10129677Slinton * Put a word into the process' address space at the given address. 10139677Slinton * The address is assumed to be on a word boundary. 10149677Slinton */ 10159677Slinton 10169677Slinton private store(p, seg, addr, data) 10179677Slinton Process p; 10189677Slinton PioSeg seg; 10199677Slinton int addr; 10209677Slinton Word data; 10219677Slinton { 10229677Slinton register CacheWord *wp; 10239677Slinton 10249677Slinton switch (seg) { 10259677Slinton case TEXTSEG: 10269677Slinton ++nwrites; 10279677Slinton wp = &p->word[cachehash(addr)]; 10289677Slinton wp->addr = addr; 10299677Slinton wp->val = data; 10309677Slinton ptrace(IWRITE, p->pid, addr, data); 10319677Slinton break; 10329677Slinton 10339677Slinton case DATASEG: 10349677Slinton ptrace(DWRITE, p->pid, addr, data); 10359677Slinton break; 10369677Slinton 10379677Slinton default: 10389677Slinton panic("store: bad seg %d", seg); 10399677Slinton /* NOTREACHED */ 10409677Slinton } 10419677Slinton } 10429677Slinton 10439677Slinton public printptraceinfo() 10449677Slinton { 10459677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 10469677Slinton } 10479677Slinton 10489677Slinton /* 10499677Slinton * Swap file numbers so as to redirect standard input and output. 10509677Slinton */ 10519677Slinton 10529677Slinton private fswap(oldfd, newfd) 10539677Slinton int oldfd; 10549677Slinton int newfd; 10559677Slinton { 10569677Slinton if (oldfd != newfd) { 10579677Slinton close(oldfd); 10589677Slinton dup(newfd); 10599677Slinton close(newfd); 10609677Slinton } 10619677Slinton } 1062