19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*12484Slinton static char sccsid[] = "@(#)process.c 1.9 05/17/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); 110*12484Slinton pc = process->reg[PROGCTR]; 111*12484Slinton getsrcpos(); 1129677Slinton } 113*12484Slinton arginit(); 1149677Slinton } 1159677Slinton 1169677Slinton /* 1179677Slinton * Routines to get at process information from outside this module. 1189677Slinton */ 1199677Slinton 1209677Slinton public Word reg(n) 1219677Slinton Integer n; 1229677Slinton { 1239677Slinton register Word w; 1249677Slinton 1259677Slinton if (n == NREG) { 1269677Slinton w = process->mask; 1279677Slinton } else { 1289677Slinton w = process->reg[n]; 1299677Slinton } 1309677Slinton return w; 1319677Slinton } 1329677Slinton 1339677Slinton public setreg(n, w) 1349677Slinton Integer n; 1359677Slinton Word w; 1369677Slinton { 1379677Slinton process->reg[n] = w; 1389677Slinton } 1399677Slinton 1409677Slinton /* 1419677Slinton * Begin execution. 1429677Slinton * 1439677Slinton * We set a breakpoint at the end of the code so that the 1449677Slinton * process data doesn't disappear after the program terminates. 1459677Slinton */ 1469677Slinton 1479677Slinton private Boolean remade(); 1489677Slinton 1499677Slinton public start(argv, infile, outfile) 1509677Slinton String argv[]; 1519677Slinton String infile, outfile; 1529677Slinton { 1539677Slinton String pargv[4]; 1549677Slinton Node cond; 1559677Slinton 1569677Slinton if (coredump) { 1579677Slinton coredump = false; 1589677Slinton fclose(corefile); 1599677Slinton coredump_close(); 1609677Slinton } 1619677Slinton if (argv == nil) { 1629677Slinton argv = pargv; 1639677Slinton pargv[0] = objname; 1649677Slinton pargv[1] = nil; 1659677Slinton } else { 1669677Slinton argv[argc] = nil; 1679677Slinton } 1689677Slinton if (remade(objname)) { 1699677Slinton reinit(argv, infile, outfile); 1709677Slinton } 1719677Slinton pstart(process, argv, infile, outfile); 1729677Slinton if (process->status == STOPPED) { 1739677Slinton pc = 0; 1749677Slinton curfunc = program; 1759677Slinton if (objsize != 0) { 1769677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1779677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1789677Slinton } 1799677Slinton } 1809677Slinton } 1819677Slinton 1829677Slinton /* 1839677Slinton * Check to see if the object file has changed since the symbolic 1849677Slinton * information last was read. 1859677Slinton */ 1869677Slinton 1879677Slinton private time_t modtime; 1889677Slinton 1899677Slinton private Boolean remade(filename) 1909677Slinton String filename; 1919677Slinton { 1929677Slinton struct stat s; 1939677Slinton Boolean b; 1949677Slinton 1959677Slinton stat(filename, &s); 1969677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 1979677Slinton modtime = s.st_mtime; 1989677Slinton return b; 1999677Slinton } 2009677Slinton 2019677Slinton /* 2029677Slinton * Set up what signals we want to trace. 2039677Slinton */ 2049677Slinton 2059677Slinton private setsigtrace() 2069677Slinton { 2079677Slinton register Integer i; 2089677Slinton register Process p; 2099677Slinton 2109677Slinton p = process; 2119677Slinton for (i = 1; i <= NSIG; i++) { 2129677Slinton psigtrace(p, i, true); 2139677Slinton } 2149677Slinton psigtrace(p, SIGHUP, false); 2159677Slinton psigtrace(p, SIGKILL, false); 2169677Slinton psigtrace(p, SIGALRM, false); 2179677Slinton psigtrace(p, SIGTSTP, false); 2189677Slinton psigtrace(p, SIGCONT, false); 2199677Slinton psigtrace(p, SIGCHLD, false); 2209677Slinton } 2219677Slinton 2229677Slinton /* 2239677Slinton * Initialize the argument list. 2249677Slinton */ 2259677Slinton 2269677Slinton public arginit() 2279677Slinton { 2289677Slinton infile = nil; 2299677Slinton outfile = nil; 2309677Slinton argv[0] = objname; 2319677Slinton argc = 1; 2329677Slinton } 2339677Slinton 2349677Slinton /* 2359677Slinton * Add an argument to the list for the debuggee. 2369677Slinton */ 2379677Slinton 2389677Slinton public newarg(arg) 2399677Slinton String arg; 2409677Slinton { 2419677Slinton if (argc >= MAXNCMDARGS) { 2429677Slinton error("too many arguments"); 2439677Slinton } 2449677Slinton argv[argc++] = arg; 2459677Slinton } 2469677Slinton 2479677Slinton /* 2489677Slinton * Set the standard input for the debuggee. 2499677Slinton */ 2509677Slinton 2519677Slinton public inarg(filename) 2529677Slinton String filename; 2539677Slinton { 2549677Slinton if (infile != nil) { 2559677Slinton error("multiple input redirects"); 2569677Slinton } 2579677Slinton infile = filename; 2589677Slinton } 2599677Slinton 2609677Slinton /* 2619677Slinton * Set the standard output for the debuggee. 2629677Slinton * Probably should check to avoid overwriting an existing file. 2639677Slinton */ 2649677Slinton 2659677Slinton public outarg(filename) 2669677Slinton String filename; 2679677Slinton { 2689677Slinton if (outfile != nil) { 2699677Slinton error("multiple output redirect"); 2709677Slinton } 2719677Slinton outfile = filename; 2729677Slinton } 2739677Slinton 2749677Slinton /* 2759677Slinton * Start debuggee executing. 2769677Slinton */ 2779677Slinton 2789677Slinton public run() 2799677Slinton { 2809677Slinton process->status = STOPPED; 2819677Slinton fixbps(); 2829677Slinton curline = 0; 2839677Slinton start(argv, infile, outfile); 2849677Slinton just_started = true; 2859677Slinton isstopped = false; 2869677Slinton cont(); 2879677Slinton } 2889677Slinton 2899677Slinton /* 2909677Slinton * Continue execution wherever we left off. 2919677Slinton * 2929677Slinton * Note that this routine never returns. Eventually bpact() will fail 2939677Slinton * and we'll call printstatus or step will call it. 2949677Slinton */ 2959677Slinton 2969677Slinton typedef int Intfunc(); 2979677Slinton 2989677Slinton private Intfunc *dbintr; 2999677Slinton private intr(); 3009677Slinton 3019677Slinton #define succeeds == true 3029677Slinton #define fails == false 3039677Slinton 30411867Slinton public cont(signo) 30511867Slinton int signo; 3069677Slinton { 3079677Slinton dbintr = signal(SIGINT, intr); 3089677Slinton if (just_started) { 3099677Slinton just_started = false; 3109677Slinton } else { 3119677Slinton if (not isstopped) { 3129677Slinton error("can't continue execution"); 3139677Slinton } 3149677Slinton isstopped = false; 31511867Slinton stepover(); 3169677Slinton } 3179677Slinton for (;;) { 3189677Slinton if (single_stepping) { 3199677Slinton printnews(); 3209677Slinton } else { 3219677Slinton setallbps(); 32211867Slinton resume(signo); 3239677Slinton unsetallbps(); 3249677Slinton if (bpact() fails) { 3259677Slinton printstatus(); 3269677Slinton } 3279677Slinton } 32811867Slinton stepover(); 3299677Slinton } 3309677Slinton /* NOTREACHED */ 3319677Slinton } 3329677Slinton 3339677Slinton /* 3349677Slinton * This routine is called if we get an interrupt while "running" px 3359677Slinton * but actually in the debugger. Could happen, for example, while 3369677Slinton * processing breakpoints. 3379677Slinton * 3389677Slinton * We basically just want to keep going; the assumption is 3399677Slinton * that when the process resumes it will get the interrupt 3409677Slinton * which will then be handled. 3419677Slinton */ 3429677Slinton 3439677Slinton private intr() 3449677Slinton { 3459677Slinton signal(SIGINT, intr); 3469677Slinton } 3479677Slinton 3489677Slinton public fixintr() 3499677Slinton { 3509677Slinton signal(SIGINT, dbintr); 3519677Slinton } 3529677Slinton 3539677Slinton /* 3549677Slinton * Resume execution. 3559677Slinton */ 3569677Slinton 35711867Slinton public resume(signo) 35811867Slinton int signo; 3599677Slinton { 3609677Slinton register Process p; 3619677Slinton 3629677Slinton p = process; 3639677Slinton if (traceexec) { 3649677Slinton printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]); 3659677Slinton fflush(stdout); 3669677Slinton } 36711867Slinton pcont(p, signo); 3689677Slinton pc = process->reg[PROGCTR]; 3699677Slinton if (traceexec) { 3709677Slinton printf("execution stops at pc 0x%x on sig %d\n", 3719677Slinton process->reg[PROGCTR], p->signo); 3729677Slinton fflush(stdout); 3739677Slinton } 37411832Slinton if (p->status != STOPPED) { 37511867Slinton if (p->signo != 0) { 37611867Slinton error("program terminated by signal %d", p->signo); 37711867Slinton } else { 37811867Slinton error("program unexpectedly exited with %d", p->exitval); 37911867Slinton } 38011832Slinton } 3819677Slinton } 3829677Slinton 3839677Slinton /* 3849677Slinton * Continue execution up to the next source line. 3859677Slinton * 3869677Slinton * There are two ways to define the next source line depending on what 3879677Slinton * is desired when a procedure or function call is encountered. Step 3889677Slinton * stops at the beginning of the procedure or call; next skips over it. 3899677Slinton */ 3909677Slinton 3919677Slinton /* 3929677Slinton * Stepc is what is called when the step command is given. 3939677Slinton * It has to play with the "isstopped" information. 3949677Slinton */ 3959677Slinton 3969677Slinton public stepc() 3979677Slinton { 3989677Slinton if (not isstopped) { 3999677Slinton error("can't continue execution"); 4009677Slinton } 4019677Slinton isstopped = false; 4029677Slinton dostep(false); 4039677Slinton isstopped = true; 4049677Slinton } 4059677Slinton 4069677Slinton public next() 4079677Slinton { 4089677Slinton if (not isstopped) { 4099677Slinton error("can't continue execution"); 4109677Slinton } 4119677Slinton isstopped = false; 4129677Slinton dostep(true); 4139677Slinton isstopped = true; 4149677Slinton } 4159677Slinton 41611867Slinton /* 41711867Slinton * Single-step over the current machine instruction. 41811867Slinton * 41911867Slinton * If we're single-stepping by source line we want to step to the 42011867Slinton * next source line. Otherwise we're going to continue so there's 42111867Slinton * no reason to do all the work necessary to single-step to the next 42211867Slinton * source line. 42311867Slinton */ 42411867Slinton 42511867Slinton private stepover() 4269677Slinton { 42711867Slinton Boolean b; 42811867Slinton 42911867Slinton if (single_stepping) { 43011867Slinton dostep(false); 43111867Slinton } else { 43211867Slinton b = inst_tracing; 43311867Slinton inst_tracing = true; 43411867Slinton dostep(false); 43511867Slinton inst_tracing = b; 43611867Slinton } 4379677Slinton } 4389677Slinton 4399677Slinton /* 4409677Slinton * Resume execution up to the given address. It is assumed that 4419677Slinton * no breakpoints exist between the current address and the one 4429677Slinton * we're stepping to. This saves us from setting all the breakpoints. 4439677Slinton */ 4449677Slinton 4459677Slinton public stepto(addr) 4469677Slinton Address addr; 4479677Slinton { 4489677Slinton setbp(addr); 44911867Slinton resume(0); 4509677Slinton unsetbp(addr); 4519677Slinton if (not isbperr()) { 4529677Slinton printstatus(); 4539677Slinton } 4549677Slinton } 4559677Slinton 4569677Slinton /* 4579677Slinton * Print the status of the process. 4589677Slinton * This routine does not return. 4599677Slinton */ 4609677Slinton 4619677Slinton public printstatus() 4629677Slinton { 4639843Slinton if (process->status == FINISHED) { 4649843Slinton exit(0); 4659843Slinton } else { 4669843Slinton curfunc = whatblock(pc); 4679677Slinton getsrcpos(); 4689843Slinton if (process->signo == SIGINT) { 4699843Slinton isstopped = true; 4709843Slinton printerror(); 4719843Slinton } else if (isbperr() and isstopped) { 4729843Slinton printf("stopped "); 47311172Slinton printloc(); 47411172Slinton putchar('\n'); 4759843Slinton if (curline > 0) { 4769843Slinton printlines(curline, curline); 4779843Slinton } else { 4789843Slinton printinst(pc, pc); 4799843Slinton } 4809843Slinton erecover(); 4819677Slinton } else { 4829843Slinton fixbps(); 4839843Slinton fixintr(); 4849677Slinton isstopped = true; 4859677Slinton printerror(); 4869677Slinton } 4879677Slinton } 4889677Slinton } 4899677Slinton 4909677Slinton /* 49111172Slinton * Print out the current location in the debuggee. 49211172Slinton */ 49311172Slinton 49411172Slinton public printloc() 49511172Slinton { 49611172Slinton printf("in "); 49711172Slinton printname(stdout, curfunc); 49811172Slinton putchar(' '); 49911172Slinton if (curline > 0) { 50011172Slinton printsrcpos(); 50111172Slinton } else { 50211172Slinton printf("at 0x%x", pc); 50311172Slinton } 50411172Slinton } 50511172Slinton 50611172Slinton /* 5079677Slinton * Some functions for testing the state of the process. 5089677Slinton */ 5099677Slinton 5109677Slinton public Boolean notstarted(p) 5119677Slinton Process p; 5129677Slinton { 5139677Slinton return (Boolean) (p->status == NOTSTARTED); 5149677Slinton } 5159677Slinton 5169677Slinton public Boolean isfinished(p) 5179677Slinton Process p; 5189677Slinton { 5199677Slinton return (Boolean) (p->status == FINISHED); 5209677Slinton } 5219677Slinton 5229677Slinton /* 5239677Slinton * Return the signal number which stopped the process. 5249677Slinton */ 5259677Slinton 5269677Slinton public Integer errnum(p) 5279677Slinton Process p; 5289677Slinton { 5299677Slinton return p->signo; 5309677Slinton } 5319677Slinton 5329677Slinton /* 5339677Slinton * Return the termination code of the process. 5349677Slinton */ 5359677Slinton 5369677Slinton public Integer exitcode(p) 5379677Slinton Process p; 5389677Slinton { 5399677Slinton return p->exitval; 5409677Slinton } 5419677Slinton 5429677Slinton /* 5439677Slinton * These routines are used to access the debuggee process from 5449677Slinton * outside this module. 5459677Slinton * 5469677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 54711560Slinton * The system generates an I/O error when a ptrace fails, we assume 54811560Slinton * during a read/write to the process that such an error is due to 54911560Slinton * a misguided address and ignore it. 5509677Slinton */ 5519677Slinton 5529677Slinton extern Intfunc *onsyserr(); 5539677Slinton 5549677Slinton private badaddr; 5559677Slinton private rwerr(); 5569677Slinton 5579677Slinton /* 5589677Slinton * Read from the process' instruction area. 5599677Slinton */ 5609677Slinton 5619677Slinton public iread(buff, addr, nbytes) 5629677Slinton char *buff; 5639677Slinton Address addr; 5649677Slinton int nbytes; 5659677Slinton { 5669677Slinton Intfunc *f; 5679677Slinton 5689677Slinton f = onsyserr(EIO, rwerr); 5699677Slinton badaddr = addr; 5709677Slinton if (coredump) { 5719677Slinton coredump_readtext(buff, addr, nbytes); 5729677Slinton } else { 5739677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 5749677Slinton } 5759677Slinton onsyserr(EIO, f); 5769677Slinton } 5779677Slinton 5789677Slinton /* 5799677Slinton * Write to the process' instruction area, usually in order to set 5809677Slinton * or unset a breakpoint. 5819677Slinton */ 5829677Slinton 5839677Slinton public iwrite(buff, addr, nbytes) 5849677Slinton char *buff; 5859677Slinton Address addr; 5869677Slinton int nbytes; 5879677Slinton { 5889677Slinton Intfunc *f; 5899677Slinton 5909677Slinton if (coredump) { 5919677Slinton error("no process to write to"); 5929677Slinton } 5939677Slinton f = onsyserr(EIO, rwerr); 5949677Slinton badaddr = addr; 5959677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 5969677Slinton onsyserr(EIO, f); 5979677Slinton } 5989677Slinton 5999677Slinton /* 6009677Slinton * Read for the process' data area. 6019677Slinton */ 6029677Slinton 6039677Slinton public dread(buff, addr, nbytes) 6049677Slinton char *buff; 6059677Slinton Address addr; 6069677Slinton int nbytes; 6079677Slinton { 6089677Slinton Intfunc *f; 6099677Slinton 6109677Slinton f = onsyserr(EIO, rwerr); 6119677Slinton badaddr = addr; 6129677Slinton if (coredump) { 6139677Slinton coredump_readdata(buff, addr, nbytes); 6149677Slinton } else { 6159677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 6169677Slinton } 6179677Slinton onsyserr(EIO, f); 6189677Slinton } 6199677Slinton 6209677Slinton /* 6219677Slinton * Write to the process' data area. 6229677Slinton */ 6239677Slinton 6249677Slinton public dwrite(buff, addr, nbytes) 6259677Slinton char *buff; 6269677Slinton Address addr; 6279677Slinton int nbytes; 6289677Slinton { 6299677Slinton Intfunc *f; 6309677Slinton 6319677Slinton if (coredump) { 6329677Slinton error("no process to write to"); 6339677Slinton } 6349677Slinton f = onsyserr(EIO, rwerr); 6359677Slinton badaddr = addr; 6369677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 6379677Slinton onsyserr(EIO, f); 6389677Slinton } 6399677Slinton 6409677Slinton /* 6419677Slinton * Error handler. 6429677Slinton */ 6439677Slinton 6449677Slinton private rwerr() 6459677Slinton { 64611560Slinton /* 64711560Slinton * Current response is to ignore the error and let the result 64811560Slinton * (-1) ripple back up to the process. 64911560Slinton * 6509677Slinton error("bad read/write process address 0x%x", badaddr); 65111560Slinton */ 6529677Slinton } 6539677Slinton 6549677Slinton /* 6559677Slinton * Ptrace interface. 6569677Slinton */ 6579677Slinton 6589677Slinton /* 6599677Slinton * This magic macro enables us to look at the process' registers 6609677Slinton * in its user structure. Very gross. 6619677Slinton */ 6629677Slinton 6639677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 6649677Slinton 6659677Slinton #define WMASK (~(sizeof(Word) - 1)) 6669677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 6679677Slinton 6689677Slinton #define FIRSTSIG SIGINT 6699677Slinton #define LASTSIG SIGQUIT 6709677Slinton #define ischild(pid) ((pid) == 0) 6719677Slinton #define traceme() ptrace(0, 0, 0, 0) 6729677Slinton #define setrep(n) (1 << ((n)-1)) 6739677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 6749677Slinton 6759677Slinton /* 6769677Slinton * Ptrace options (specified in first argument). 6779677Slinton */ 6789677Slinton 6799677Slinton #define UREAD 3 /* read from process's user structure */ 6809677Slinton #define UWRITE 6 /* write to process's user structure */ 6819677Slinton #define IREAD 1 /* read from process's instruction space */ 6829677Slinton #define IWRITE 4 /* write to process's instruction space */ 6839677Slinton #define DREAD 2 /* read from process's data space */ 6849677Slinton #define DWRITE 5 /* write to process's data space */ 6859677Slinton #define CONT 7 /* continue stopped process */ 6869677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 6879677Slinton #define PKILL 8 /* terminate the process */ 6889677Slinton 6899677Slinton /* 6909677Slinton * Start up a new process by forking and exec-ing the 6919677Slinton * given argument list, returning when the process is loaded 6929677Slinton * and ready to execute. The PROCESS information (pointed to 6939677Slinton * by the first argument) is appropriately filled. 6949677Slinton * 6959677Slinton * If the given PROCESS structure is associated with an already running 6969677Slinton * process, we terminate it. 6979677Slinton */ 6989677Slinton 6999677Slinton /* VARARGS2 */ 7009677Slinton private pstart(p, argv, infile, outfile) 7019677Slinton Process p; 7029677Slinton String argv[]; 7039677Slinton String infile; 7049677Slinton String outfile; 7059677Slinton { 7069677Slinton int status; 7079677Slinton 7089677Slinton if (p->pid != 0) { /* child already running? */ 7099677Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 7109677Slinton } 7119677Slinton psigtrace(p, SIGTRAP, true); 71211172Slinton if ((p->pid = vfork()) == -1) { 7139677Slinton panic("can't fork"); 7149677Slinton } 7159677Slinton if (ischild(p->pid)) { 71611172Slinton Fileid in, out; 71711172Slinton 7189677Slinton traceme(); 7199677Slinton if (infile != nil) { 72011172Slinton in = open(infile, 0); 72111172Slinton if (in == -1) { 72211172Slinton write(2, "can't read ", 11); 72311172Slinton write(2, infile, strlen(infile)); 72411172Slinton write(2, "\n", 1); 72511172Slinton _exit(1); 7269677Slinton } 72711172Slinton fswap(0, in); 7289677Slinton } 7299677Slinton if (outfile != nil) { 73011172Slinton out = creat(outfile, 0666); 73111172Slinton if (out == -1) { 73211172Slinton write(2, "can't write ", 12); 73311172Slinton write(2, outfile, strlen(outfile)); 73411172Slinton write(2, "\n", 1); 73511172Slinton _exit(1); 7369677Slinton } 73711172Slinton fswap(1, out); 7389677Slinton } 73911832Slinton execv(argv[0], argv); 74011172Slinton write(2, "can't exec ", 11); 74111172Slinton write(2, argv[0], strlen(argv[0])); 74211172Slinton write(2, "\n", 1); 74311172Slinton _exit(1); 7449677Slinton } 7459677Slinton pwait(p->pid, &status); 7469677Slinton getinfo(p, status); 7479677Slinton if (p->status != STOPPED) { 7489677Slinton error("program could not begin execution"); 7499677Slinton } 7509677Slinton } 7519677Slinton 7529677Slinton /* 75311867Slinton * Continue a stopped process. The first argument points to a Process 75411867Slinton * structure. Before the process is restarted it's user area is modified 75511867Slinton * according to the values in the structure. When this routine finishes, 7569677Slinton * the structure has the new values from the process's user area. 7579677Slinton * 7589677Slinton * Pcont terminates when the process stops with a signal pending that 7599677Slinton * is being traced (via psigtrace), or when the process terminates. 7609677Slinton */ 7619677Slinton 76211867Slinton private pcont(p, signo) 7639677Slinton Process p; 76411867Slinton int signo; 7659677Slinton { 7669677Slinton int status; 7679677Slinton 7689677Slinton if (p->pid == 0) { 7699677Slinton error("program not active"); 7709677Slinton } 7719677Slinton do { 77211867Slinton setinfo(p, signo); 7739677Slinton sigs_off(); 7749677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 7759677Slinton panic("can't continue process"); 7769677Slinton } 7779677Slinton pwait(p->pid, &status); 7789677Slinton sigs_on(); 7799677Slinton getinfo(p, status); 7809677Slinton } while (p->status == STOPPED and not istraced(p)); 7819677Slinton } 7829677Slinton 7839677Slinton /* 7849677Slinton * Single step as best ptrace can. 7859677Slinton */ 7869677Slinton 7879677Slinton public pstep(p) 7889677Slinton Process p; 7899677Slinton { 7909677Slinton int status; 7919677Slinton 79211867Slinton setinfo(p, 0); 7939677Slinton sigs_off(); 7949677Slinton ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 7959677Slinton pwait(p->pid, &status); 7969677Slinton sigs_on(); 7979677Slinton getinfo(p, status); 7989677Slinton } 7999677Slinton 8009677Slinton /* 8019677Slinton * Return from execution when the given signal is pending. 8029677Slinton */ 8039677Slinton 8049677Slinton public psigtrace(p, sig, sw) 8059677Slinton Process p; 8069677Slinton int sig; 8079677Slinton Boolean sw; 8089677Slinton { 8099677Slinton if (sw) { 8109677Slinton p->sigset |= setrep(sig); 8119677Slinton } else { 8129677Slinton p->sigset &= ~setrep(sig); 8139677Slinton } 8149677Slinton } 8159677Slinton 8169677Slinton /* 8179677Slinton * Don't catch any signals. 8189677Slinton * Particularly useful when letting a process finish uninhibited. 8199677Slinton */ 8209677Slinton 8219677Slinton public unsetsigtraces(p) 8229677Slinton Process p; 8239677Slinton { 8249677Slinton p->sigset = 0; 8259677Slinton } 8269677Slinton 8279677Slinton /* 8289677Slinton * Turn off attention to signals not being caught. 8299677Slinton */ 8309677Slinton 8319677Slinton private Intfunc *sigfunc[NSIG]; 8329677Slinton 8339677Slinton private sigs_off() 8349677Slinton { 8359677Slinton register int i; 8369677Slinton 8379677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8389677Slinton if (i != SIGKILL) { 8399677Slinton sigfunc[i] = signal(i, SIG_IGN); 8409677Slinton } 8419677Slinton } 8429677Slinton } 8439677Slinton 8449677Slinton /* 8459677Slinton * Turn back on attention to signals. 8469677Slinton */ 8479677Slinton 8489677Slinton private sigs_on() 8499677Slinton { 8509677Slinton register int i; 8519677Slinton 8529677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8539677Slinton if (i != SIGKILL) { 8549677Slinton signal(i, sigfunc[i]); 8559677Slinton } 8569677Slinton } 8579677Slinton } 8589677Slinton 8599677Slinton /* 8609677Slinton * Get process information from user area. 8619677Slinton */ 8629677Slinton 8639677Slinton private int rloc[] ={ 8649677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 8659677Slinton }; 8669677Slinton 8679677Slinton private getinfo(p, status) 8689677Slinton register Process p; 8699677Slinton register int status; 8709677Slinton { 8719677Slinton register int i; 8729677Slinton 8739677Slinton p->signo = (status&0177); 8749677Slinton p->exitval = ((status >> 8)&0377); 8759677Slinton if (p->signo != STOPPED) { 8769677Slinton p->status = FINISHED; 8779677Slinton } else { 8789677Slinton p->status = p->signo; 8799677Slinton p->signo = p->exitval; 8809677Slinton p->exitval = 0; 8819677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 8829677Slinton for (i = 0; i < NREG; i++) { 8839677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 8849677Slinton p->oreg[i] = p->reg[i]; 8859677Slinton } 88611768Slinton savetty(stdout, &(p->ttyinfo)); 8879677Slinton } 8889677Slinton } 8899677Slinton 8909677Slinton /* 8919677Slinton * Set process's user area information from given process structure. 8929677Slinton */ 8939677Slinton 89411867Slinton private setinfo(p, signo) 8959677Slinton register Process p; 89611867Slinton int signo; 8979677Slinton { 8989677Slinton register int i; 8999677Slinton register int r; 9009677Slinton 9019677Slinton if (istraced(p)) { 90211867Slinton p->signo = signo; 9039677Slinton } 9049677Slinton for (i = 0; i < NREG; i++) { 9059677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 9069677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 9079677Slinton } 9089677Slinton } 90911768Slinton restoretty(stdout, &(p->ttyinfo)); 9109677Slinton } 9119677Slinton 9129677Slinton /* 9139677Slinton * Structure for reading and writing by words, but dealing with bytes. 9149677Slinton */ 9159677Slinton 9169677Slinton typedef union { 9179677Slinton Word pword; 9189677Slinton Byte pbyte[sizeof(Word)]; 9199677Slinton } Pword; 9209677Slinton 9219677Slinton /* 9229677Slinton * Read (write) from (to) the process' address space. 9239677Slinton * We must deal with ptrace's inability to look anywhere other 9249677Slinton * than at a word boundary. 9259677Slinton */ 9269677Slinton 9279677Slinton private Word fetch(); 9289677Slinton private store(); 9299677Slinton 9309677Slinton private pio(p, op, seg, buff, addr, nbytes) 9319677Slinton Process p; 9329677Slinton PioOp op; 9339677Slinton PioSeg seg; 9349677Slinton char *buff; 9359677Slinton Address addr; 9369677Slinton int nbytes; 9379677Slinton { 9389677Slinton register int i; 9399677Slinton register Address newaddr; 9409677Slinton register char *cp; 9419677Slinton char *bufend; 9429677Slinton Pword w; 9439677Slinton Address wordaddr; 9449677Slinton int byteoff; 9459677Slinton 9469677Slinton if (p->status != STOPPED) { 9479677Slinton error("program is not active"); 9489677Slinton } 9499677Slinton cp = buff; 9509677Slinton newaddr = addr; 9519677Slinton wordaddr = (newaddr&WMASK); 9529677Slinton if (wordaddr != newaddr) { 9539677Slinton w.pword = fetch(p, seg, wordaddr); 9549677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 9559677Slinton if (op == PREAD) { 9569677Slinton *cp++ = w.pbyte[i]; 9579677Slinton } else { 9589677Slinton w.pbyte[i] = *cp++; 9599677Slinton } 9609677Slinton nbytes--; 9619677Slinton } 9629677Slinton if (op == PWRITE) { 9639677Slinton store(p, seg, wordaddr, w.pword); 9649677Slinton } 9659677Slinton newaddr = wordaddr + sizeof(Word); 9669677Slinton } 9679677Slinton byteoff = (nbytes&(~WMASK)); 9689677Slinton nbytes -= byteoff; 9699677Slinton bufend = cp + nbytes; 9709677Slinton while (cp < bufend) { 9719677Slinton if (op == PREAD) { 9729677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 9739677Slinton } else { 9749677Slinton store(p, seg, newaddr, *((Word *) cp)); 9759677Slinton } 9769677Slinton cp += sizeof(Word); 9779677Slinton newaddr += sizeof(Word); 9789677Slinton } 9799677Slinton if (byteoff > 0) { 9809677Slinton w.pword = fetch(p, seg, newaddr); 9819677Slinton for (i = 0; i < byteoff; i++) { 9829677Slinton if (op == PREAD) { 9839677Slinton *cp++ = w.pbyte[i]; 9849677Slinton } else { 9859677Slinton w.pbyte[i] = *cp++; 9869677Slinton } 9879677Slinton } 9889677Slinton if (op == PWRITE) { 9899677Slinton store(p, seg, newaddr, w.pword); 9909677Slinton } 9919677Slinton } 9929677Slinton } 9939677Slinton 9949677Slinton /* 9959677Slinton * Get a word from a process at the given address. 9969677Slinton * The address is assumed to be on a word boundary. 9979677Slinton * 9989677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 9999677Slinton * to the instruction space since it is assumed to be pure. 10009677Slinton * 10019677Slinton * It is necessary to use a write-through scheme so that 10029677Slinton * breakpoints right next to each other don't interfere. 10039677Slinton */ 10049677Slinton 10059677Slinton private Integer nfetchs, nreads, nwrites; 10069677Slinton 10079677Slinton private Word fetch(p, seg, addr) 10089677Slinton Process p; 10099677Slinton PioSeg seg; 10109677Slinton register int addr; 10119677Slinton { 10129677Slinton register CacheWord *wp; 10139677Slinton register Word w; 10149677Slinton 10159677Slinton switch (seg) { 10169677Slinton case TEXTSEG: 10179677Slinton ++nfetchs; 10189677Slinton wp = &p->word[cachehash(addr)]; 10199677Slinton if (addr == 0 or wp->addr != addr) { 10209677Slinton ++nreads; 10219677Slinton w = ptrace(IREAD, p->pid, addr, 0); 10229677Slinton wp->addr = addr; 10239677Slinton wp->val = w; 10249677Slinton } else { 10259677Slinton w = wp->val; 10269677Slinton } 10279677Slinton break; 10289677Slinton 10299677Slinton case DATASEG: 10309677Slinton w = ptrace(DREAD, p->pid, addr, 0); 10319677Slinton break; 10329677Slinton 10339677Slinton default: 10349677Slinton panic("fetch: bad seg %d", seg); 10359677Slinton /* NOTREACHED */ 10369677Slinton } 10379677Slinton return w; 10389677Slinton } 10399677Slinton 10409677Slinton /* 10419677Slinton * Put a word into the process' address space at the given address. 10429677Slinton * The address is assumed to be on a word boundary. 10439677Slinton */ 10449677Slinton 10459677Slinton private store(p, seg, addr, data) 10469677Slinton Process p; 10479677Slinton PioSeg seg; 10489677Slinton int addr; 10499677Slinton Word data; 10509677Slinton { 10519677Slinton register CacheWord *wp; 10529677Slinton 10539677Slinton switch (seg) { 10549677Slinton case TEXTSEG: 10559677Slinton ++nwrites; 10569677Slinton wp = &p->word[cachehash(addr)]; 10579677Slinton wp->addr = addr; 10589677Slinton wp->val = data; 10599677Slinton ptrace(IWRITE, p->pid, addr, data); 10609677Slinton break; 10619677Slinton 10629677Slinton case DATASEG: 10639677Slinton ptrace(DWRITE, p->pid, addr, data); 10649677Slinton break; 10659677Slinton 10669677Slinton default: 10679677Slinton panic("store: bad seg %d", seg); 10689677Slinton /* NOTREACHED */ 10699677Slinton } 10709677Slinton } 10719677Slinton 10729677Slinton public printptraceinfo() 10739677Slinton { 10749677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 10759677Slinton } 10769677Slinton 10779677Slinton /* 10789677Slinton * Swap file numbers so as to redirect standard input and output. 10799677Slinton */ 10809677Slinton 10819677Slinton private fswap(oldfd, newfd) 10829677Slinton int oldfd; 10839677Slinton int newfd; 10849677Slinton { 10859677Slinton if (oldfd != newfd) { 10869677Slinton close(oldfd); 10879677Slinton dup(newfd); 10889677Slinton close(newfd); 10899677Slinton } 10909677Slinton } 1091