19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*14757Slinton static char sccsid[] = "@(#)process.c 1.12 08/19/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" 17*14757Slinton #include "eval.h" 189677Slinton #include "operators.h" 199677Slinton #include "source.h" 209677Slinton #include "object.h" 219677Slinton #include "mappings.h" 229677Slinton #include "main.h" 239677Slinton #include "coredump.h" 249677Slinton #include <signal.h> 259677Slinton #include <errno.h> 269677Slinton #include <sys/param.h> 279843Slinton #include <machine/reg.h> 289677Slinton #include <sys/stat.h> 299677Slinton 309677Slinton #ifndef public 319677Slinton 329677Slinton typedef struct Process *Process; 339677Slinton 349677Slinton Process process; 359677Slinton 36*14757Slinton #define DEFSIG -1 37*14757Slinton 389677Slinton #include "machine.h" 399677Slinton 409677Slinton #endif 419677Slinton 429677Slinton #define NOTSTARTED 1 439677Slinton #define STOPPED 0177 449677Slinton #define FINISHED 0 459677Slinton 469677Slinton /* 479677Slinton * Cache-ing of instruction segment is done to reduce the number 489677Slinton * of system calls. 499677Slinton */ 509677Slinton 519677Slinton #define CSIZE 1003 /* size of instruction cache */ 529677Slinton 539677Slinton typedef struct { 549677Slinton Word addr; 559677Slinton Word val; 569677Slinton } CacheWord; 579677Slinton 589677Slinton /* 599677Slinton * This structure holds the information we need from the user structure. 609677Slinton */ 619677Slinton 629677Slinton struct Process { 639677Slinton int pid; /* process being traced */ 6411768Slinton int mask; /* process status word */ 6511768Slinton Word reg[NREG]; /* process' registers */ 669677Slinton Word oreg[NREG]; /* registers when process last stopped */ 679677Slinton short status; /* either STOPPED or FINISHED */ 689677Slinton short signo; /* signal that stopped process */ 699677Slinton int exitval; /* return value from exit() */ 709677Slinton long sigset; /* bit array of traced signals */ 719677Slinton CacheWord word[CSIZE]; /* text segment cache */ 7211768Slinton Ttyinfo ttyinfo; /* process' terminal characteristics */ 739677Slinton }; 749677Slinton 759677Slinton /* 769677Slinton * These definitions are for the arguments to "pio". 779677Slinton */ 789677Slinton 799677Slinton typedef enum { PREAD, PWRITE } PioOp; 809677Slinton typedef enum { TEXTSEG, DATASEG } PioSeg; 819677Slinton 829677Slinton private struct Process pbuf; 839677Slinton 8413841Slinton #define MAXNCMDARGS 100 /* maximum number of arguments to RUN */ 859677Slinton 8614395Slinton extern int errno; 8714395Slinton 889677Slinton private Boolean just_started; 899677Slinton private int argc; 909677Slinton private String argv[MAXNCMDARGS]; 919677Slinton private String infile, outfile; 929677Slinton 939677Slinton /* 949677Slinton * Initialize process information. 959677Slinton */ 969677Slinton 979677Slinton public process_init() 989677Slinton { 999677Slinton register Integer i; 1009677Slinton Char buf[10]; 1019677Slinton 1029677Slinton process = &pbuf; 1039677Slinton process->status = (coredump) ? STOPPED : NOTSTARTED; 1049677Slinton setsigtrace(); 1059677Slinton for (i = 0; i < NREG; i++) { 1069677Slinton sprintf(buf, "$r%d", i); 1079677Slinton defregname(identname(buf, false), i); 1089677Slinton } 1099677Slinton defregname(identname("$ap", true), ARGP); 1109677Slinton defregname(identname("$fp", true), FRP); 1119677Slinton defregname(identname("$sp", true), STKP); 1129677Slinton defregname(identname("$pc", true), PROGCTR); 1139677Slinton if (coredump) { 1149677Slinton coredump_readin(process->mask, process->reg, process->signo); 11512484Slinton pc = process->reg[PROGCTR]; 11612484Slinton getsrcpos(); 1179677Slinton } 11812484Slinton arginit(); 1199677Slinton } 1209677Slinton 1219677Slinton /* 1229677Slinton * Routines to get at process information from outside this module. 1239677Slinton */ 1249677Slinton 1259677Slinton public Word reg(n) 1269677Slinton Integer n; 1279677Slinton { 1289677Slinton register Word w; 1299677Slinton 1309677Slinton if (n == NREG) { 1319677Slinton w = process->mask; 1329677Slinton } else { 1339677Slinton w = process->reg[n]; 1349677Slinton } 1359677Slinton return w; 1369677Slinton } 1379677Slinton 1389677Slinton public setreg(n, w) 1399677Slinton Integer n; 1409677Slinton Word w; 1419677Slinton { 1429677Slinton process->reg[n] = w; 1439677Slinton } 1449677Slinton 1459677Slinton /* 1469677Slinton * Begin execution. 1479677Slinton * 1489677Slinton * We set a breakpoint at the end of the code so that the 1499677Slinton * process data doesn't disappear after the program terminates. 1509677Slinton */ 1519677Slinton 1529677Slinton private Boolean remade(); 1539677Slinton 1549677Slinton public start(argv, infile, outfile) 1559677Slinton String argv[]; 1569677Slinton String infile, outfile; 1579677Slinton { 1589677Slinton String pargv[4]; 1599677Slinton Node cond; 1609677Slinton 1619677Slinton if (coredump) { 1629677Slinton coredump = false; 1639677Slinton fclose(corefile); 1649677Slinton coredump_close(); 1659677Slinton } 1669677Slinton if (argv == nil) { 1679677Slinton argv = pargv; 1689677Slinton pargv[0] = objname; 1699677Slinton pargv[1] = nil; 1709677Slinton } else { 1719677Slinton argv[argc] = nil; 1729677Slinton } 1739677Slinton if (remade(objname)) { 1749677Slinton reinit(argv, infile, outfile); 1759677Slinton } 1769677Slinton pstart(process, argv, infile, outfile); 1779677Slinton if (process->status == STOPPED) { 1789677Slinton pc = 0; 1799677Slinton curfunc = program; 1809677Slinton if (objsize != 0) { 1819677Slinton cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr())); 1829677Slinton event_once(cond, buildcmdlist(build(O_ENDX))); 1839677Slinton } 1849677Slinton } 1859677Slinton } 1869677Slinton 1879677Slinton /* 1889677Slinton * Check to see if the object file has changed since the symbolic 1899677Slinton * information last was read. 1909677Slinton */ 1919677Slinton 1929677Slinton private time_t modtime; 1939677Slinton 1949677Slinton private Boolean remade(filename) 1959677Slinton String filename; 1969677Slinton { 1979677Slinton struct stat s; 1989677Slinton Boolean b; 1999677Slinton 2009677Slinton stat(filename, &s); 2019677Slinton b = (Boolean) (modtime != 0 and modtime < s.st_mtime); 2029677Slinton modtime = s.st_mtime; 2039677Slinton return b; 2049677Slinton } 2059677Slinton 2069677Slinton /* 2079677Slinton * Set up what signals we want to trace. 2089677Slinton */ 2099677Slinton 2109677Slinton private setsigtrace() 2119677Slinton { 2129677Slinton register Integer i; 2139677Slinton register Process p; 2149677Slinton 2159677Slinton p = process; 2169677Slinton for (i = 1; i <= NSIG; i++) { 2179677Slinton psigtrace(p, i, true); 2189677Slinton } 2199677Slinton psigtrace(p, SIGHUP, false); 2209677Slinton psigtrace(p, SIGKILL, false); 2219677Slinton psigtrace(p, SIGALRM, false); 2229677Slinton psigtrace(p, SIGTSTP, false); 2239677Slinton psigtrace(p, SIGCONT, false); 2249677Slinton psigtrace(p, SIGCHLD, false); 2259677Slinton } 2269677Slinton 2279677Slinton /* 2289677Slinton * Initialize the argument list. 2299677Slinton */ 2309677Slinton 2319677Slinton public arginit() 2329677Slinton { 2339677Slinton infile = nil; 2349677Slinton outfile = nil; 2359677Slinton argv[0] = objname; 2369677Slinton argc = 1; 2379677Slinton } 2389677Slinton 2399677Slinton /* 2409677Slinton * Add an argument to the list for the debuggee. 2419677Slinton */ 2429677Slinton 2439677Slinton public newarg(arg) 2449677Slinton String arg; 2459677Slinton { 2469677Slinton if (argc >= MAXNCMDARGS) { 2479677Slinton error("too many arguments"); 2489677Slinton } 2499677Slinton argv[argc++] = arg; 2509677Slinton } 2519677Slinton 2529677Slinton /* 2539677Slinton * Set the standard input for the debuggee. 2549677Slinton */ 2559677Slinton 2569677Slinton public inarg(filename) 2579677Slinton String filename; 2589677Slinton { 2599677Slinton if (infile != nil) { 2609677Slinton error("multiple input redirects"); 2619677Slinton } 2629677Slinton infile = filename; 2639677Slinton } 2649677Slinton 2659677Slinton /* 2669677Slinton * Set the standard output for the debuggee. 2679677Slinton * Probably should check to avoid overwriting an existing file. 2689677Slinton */ 2699677Slinton 2709677Slinton public outarg(filename) 2719677Slinton String filename; 2729677Slinton { 2739677Slinton if (outfile != nil) { 2749677Slinton error("multiple output redirect"); 2759677Slinton } 2769677Slinton outfile = filename; 2779677Slinton } 2789677Slinton 2799677Slinton /* 2809677Slinton * Start debuggee executing. 2819677Slinton */ 2829677Slinton 2839677Slinton public run() 2849677Slinton { 2859677Slinton process->status = STOPPED; 2869677Slinton fixbps(); 2879677Slinton curline = 0; 2889677Slinton start(argv, infile, outfile); 2899677Slinton just_started = true; 2909677Slinton isstopped = false; 291*14757Slinton cont(0); 2929677Slinton } 2939677Slinton 2949677Slinton /* 2959677Slinton * Continue execution wherever we left off. 2969677Slinton * 2979677Slinton * Note that this routine never returns. Eventually bpact() will fail 2989677Slinton * and we'll call printstatus or step will call it. 2999677Slinton */ 3009677Slinton 3019677Slinton typedef int Intfunc(); 3029677Slinton 3039677Slinton private Intfunc *dbintr; 3049677Slinton private intr(); 3059677Slinton 3069677Slinton #define succeeds == true 3079677Slinton #define fails == false 3089677Slinton 30911867Slinton public cont(signo) 31011867Slinton int signo; 3119677Slinton { 3129677Slinton dbintr = signal(SIGINT, intr); 3139677Slinton if (just_started) { 3149677Slinton just_started = false; 3159677Slinton } else { 3169677Slinton if (not isstopped) { 3179677Slinton error("can't continue execution"); 3189677Slinton } 3199677Slinton isstopped = false; 32011867Slinton stepover(); 3219677Slinton } 3229677Slinton for (;;) { 3239677Slinton if (single_stepping) { 3249677Slinton printnews(); 3259677Slinton } else { 3269677Slinton setallbps(); 32711867Slinton resume(signo); 3289677Slinton unsetallbps(); 3299677Slinton if (bpact() fails) { 3309677Slinton printstatus(); 3319677Slinton } 3329677Slinton } 33311867Slinton stepover(); 3349677Slinton } 3359677Slinton /* NOTREACHED */ 3369677Slinton } 3379677Slinton 3389677Slinton /* 3399677Slinton * This routine is called if we get an interrupt while "running" px 3409677Slinton * but actually in the debugger. Could happen, for example, while 3419677Slinton * processing breakpoints. 3429677Slinton * 3439677Slinton * We basically just want to keep going; the assumption is 3449677Slinton * that when the process resumes it will get the interrupt 3459677Slinton * which will then be handled. 3469677Slinton */ 3479677Slinton 3489677Slinton private intr() 3499677Slinton { 3509677Slinton signal(SIGINT, intr); 3519677Slinton } 3529677Slinton 3539677Slinton public fixintr() 3549677Slinton { 3559677Slinton signal(SIGINT, dbintr); 3569677Slinton } 3579677Slinton 3589677Slinton /* 3599677Slinton * Resume execution. 3609677Slinton */ 3619677Slinton 36211867Slinton public resume(signo) 36311867Slinton int signo; 3649677Slinton { 3659677Slinton register Process p; 3669677Slinton 3679677Slinton p = process; 3689677Slinton if (traceexec) { 3699677Slinton printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]); 3709677Slinton fflush(stdout); 3719677Slinton } 37211867Slinton pcont(p, signo); 3739677Slinton pc = process->reg[PROGCTR]; 3749677Slinton if (traceexec) { 3759677Slinton printf("execution stops at pc 0x%x on sig %d\n", 3769677Slinton process->reg[PROGCTR], p->signo); 3779677Slinton fflush(stdout); 3789677Slinton } 37911832Slinton if (p->status != STOPPED) { 38011867Slinton if (p->signo != 0) { 38111867Slinton error("program terminated by signal %d", p->signo); 382*14757Slinton } else if (not runfirst) { 38311867Slinton error("program unexpectedly exited with %d", p->exitval); 38411867Slinton } 38511832Slinton } 3869677Slinton } 3879677Slinton 3889677Slinton /* 3899677Slinton * Continue execution up to the next source line. 3909677Slinton * 3919677Slinton * There are two ways to define the next source line depending on what 3929677Slinton * is desired when a procedure or function call is encountered. Step 3939677Slinton * stops at the beginning of the procedure or call; next skips over it. 3949677Slinton */ 3959677Slinton 3969677Slinton /* 3979677Slinton * Stepc is what is called when the step command is given. 3989677Slinton * It has to play with the "isstopped" information. 3999677Slinton */ 4009677Slinton 4019677Slinton public stepc() 4029677Slinton { 4039677Slinton if (not isstopped) { 4049677Slinton error("can't continue execution"); 4059677Slinton } 4069677Slinton isstopped = false; 4079677Slinton dostep(false); 4089677Slinton isstopped = true; 4099677Slinton } 4109677Slinton 4119677Slinton public next() 4129677Slinton { 4139677Slinton if (not isstopped) { 4149677Slinton error("can't continue execution"); 4159677Slinton } 4169677Slinton isstopped = false; 4179677Slinton dostep(true); 4189677Slinton isstopped = true; 4199677Slinton } 4209677Slinton 42111867Slinton /* 42211867Slinton * Single-step over the current machine instruction. 42311867Slinton * 42411867Slinton * If we're single-stepping by source line we want to step to the 42511867Slinton * next source line. Otherwise we're going to continue so there's 42611867Slinton * no reason to do all the work necessary to single-step to the next 42711867Slinton * source line. 42811867Slinton */ 42911867Slinton 43011867Slinton private stepover() 4319677Slinton { 43211867Slinton Boolean b; 43311867Slinton 43411867Slinton if (single_stepping) { 43511867Slinton dostep(false); 43611867Slinton } else { 43711867Slinton b = inst_tracing; 43811867Slinton inst_tracing = true; 43911867Slinton dostep(false); 44011867Slinton inst_tracing = b; 44111867Slinton } 4429677Slinton } 4439677Slinton 4449677Slinton /* 4459677Slinton * Resume execution up to the given address. It is assumed that 4469677Slinton * no breakpoints exist between the current address and the one 4479677Slinton * we're stepping to. This saves us from setting all the breakpoints. 4489677Slinton */ 4499677Slinton 4509677Slinton public stepto(addr) 4519677Slinton Address addr; 4529677Slinton { 4539677Slinton setbp(addr); 454*14757Slinton resume(DEFSIG); 4559677Slinton unsetbp(addr); 4569677Slinton if (not isbperr()) { 4579677Slinton printstatus(); 4589677Slinton } 4599677Slinton } 4609677Slinton 4619677Slinton /* 4629677Slinton * Print the status of the process. 4639677Slinton * This routine does not return. 4649677Slinton */ 4659677Slinton 4669677Slinton public printstatus() 4679677Slinton { 46814395Slinton int status; 46914395Slinton 4709843Slinton if (process->status == FINISHED) { 4719843Slinton exit(0); 4729843Slinton } else { 4739843Slinton curfunc = whatblock(pc); 4749677Slinton getsrcpos(); 4759843Slinton if (process->signo == SIGINT) { 4769843Slinton isstopped = true; 4779843Slinton printerror(); 4789843Slinton } else if (isbperr() and isstopped) { 4799843Slinton printf("stopped "); 48011172Slinton printloc(); 48111172Slinton putchar('\n'); 4829843Slinton if (curline > 0) { 4839843Slinton printlines(curline, curline); 4849843Slinton } else { 4859843Slinton printinst(pc, pc); 4869843Slinton } 4879843Slinton erecover(); 4889677Slinton } else { 4899843Slinton fixbps(); 4909843Slinton fixintr(); 4919677Slinton isstopped = true; 4929677Slinton printerror(); 4939677Slinton } 4949677Slinton } 4959677Slinton } 4969677Slinton 4979677Slinton /* 49811172Slinton * Print out the current location in the debuggee. 49911172Slinton */ 50011172Slinton 50111172Slinton public printloc() 50211172Slinton { 50311172Slinton printf("in "); 50411172Slinton printname(stdout, curfunc); 50511172Slinton putchar(' '); 506*14757Slinton if (curline > 0 and not useInstLoc) { 50711172Slinton printsrcpos(); 50811172Slinton } else { 509*14757Slinton useInstLoc = false; 510*14757Slinton curline = 0; 51111172Slinton printf("at 0x%x", pc); 51211172Slinton } 51311172Slinton } 51411172Slinton 51511172Slinton /* 5169677Slinton * Some functions for testing the state of the process. 5179677Slinton */ 5189677Slinton 5199677Slinton public Boolean notstarted(p) 5209677Slinton Process p; 5219677Slinton { 5229677Slinton return (Boolean) (p->status == NOTSTARTED); 5239677Slinton } 5249677Slinton 5259677Slinton public Boolean isfinished(p) 5269677Slinton Process p; 5279677Slinton { 5289677Slinton return (Boolean) (p->status == FINISHED); 5299677Slinton } 5309677Slinton 5319677Slinton /* 5329677Slinton * Return the signal number which stopped the process. 5339677Slinton */ 5349677Slinton 5359677Slinton public Integer errnum(p) 5369677Slinton Process p; 5379677Slinton { 5389677Slinton return p->signo; 5399677Slinton } 5409677Slinton 5419677Slinton /* 5429677Slinton * Return the termination code of the process. 5439677Slinton */ 5449677Slinton 5459677Slinton public Integer exitcode(p) 5469677Slinton Process p; 5479677Slinton { 5489677Slinton return p->exitval; 5499677Slinton } 5509677Slinton 5519677Slinton /* 5529677Slinton * These routines are used to access the debuggee process from 5539677Slinton * outside this module. 5549677Slinton * 5559677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 556*14757Slinton * The system generates an I/O error when a ptrace fails. During reads 557*14757Slinton * these are ignored, during writes they are reported as an error, and 558*14757Slinton * for anything else they cause a fatal error. 5599677Slinton */ 5609677Slinton 5619677Slinton extern Intfunc *onsyserr(); 5629677Slinton 5639677Slinton private badaddr; 564*14757Slinton private read_err(), write_err(); 5659677Slinton 5669677Slinton /* 5679677Slinton * Read from the process' instruction area. 5689677Slinton */ 5699677Slinton 5709677Slinton public iread(buff, addr, nbytes) 5719677Slinton char *buff; 5729677Slinton Address addr; 5739677Slinton int nbytes; 5749677Slinton { 5759677Slinton Intfunc *f; 5769677Slinton 577*14757Slinton f = onsyserr(EIO, read_err); 5789677Slinton badaddr = addr; 5799677Slinton if (coredump) { 5809677Slinton coredump_readtext(buff, addr, nbytes); 5819677Slinton } else { 5829677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 5839677Slinton } 5849677Slinton onsyserr(EIO, f); 5859677Slinton } 5869677Slinton 5879677Slinton /* 5889677Slinton * Write to the process' instruction area, usually in order to set 5899677Slinton * or unset a breakpoint. 5909677Slinton */ 5919677Slinton 5929677Slinton public iwrite(buff, addr, nbytes) 5939677Slinton char *buff; 5949677Slinton Address addr; 5959677Slinton int nbytes; 5969677Slinton { 5979677Slinton Intfunc *f; 5989677Slinton 5999677Slinton if (coredump) { 6009677Slinton error("no process to write to"); 6019677Slinton } 602*14757Slinton f = onsyserr(EIO, write_err); 6039677Slinton badaddr = addr; 6049677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 6059677Slinton onsyserr(EIO, f); 6069677Slinton } 6079677Slinton 6089677Slinton /* 6099677Slinton * Read for the process' data area. 6109677Slinton */ 6119677Slinton 6129677Slinton public dread(buff, addr, nbytes) 6139677Slinton char *buff; 6149677Slinton Address addr; 6159677Slinton int nbytes; 6169677Slinton { 6179677Slinton Intfunc *f; 6189677Slinton 619*14757Slinton f = onsyserr(EIO, read_err); 6209677Slinton badaddr = addr; 6219677Slinton if (coredump) { 6229677Slinton coredump_readdata(buff, addr, nbytes); 6239677Slinton } else { 6249677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 6259677Slinton } 6269677Slinton onsyserr(EIO, f); 6279677Slinton } 6289677Slinton 6299677Slinton /* 6309677Slinton * Write to the process' data area. 6319677Slinton */ 6329677Slinton 6339677Slinton public dwrite(buff, addr, nbytes) 6349677Slinton char *buff; 6359677Slinton Address addr; 6369677Slinton int nbytes; 6379677Slinton { 6389677Slinton Intfunc *f; 6399677Slinton 6409677Slinton if (coredump) { 6419677Slinton error("no process to write to"); 6429677Slinton } 643*14757Slinton f = onsyserr(EIO, write_err); 6449677Slinton badaddr = addr; 6459677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 6469677Slinton onsyserr(EIO, f); 6479677Slinton } 6489677Slinton 6499677Slinton /* 650*14757Slinton * Trap for errors in reading or writing to a process. 651*14757Slinton * The current approach is to "ignore" read errors and complain 652*14757Slinton * bitterly about write errors. 6539677Slinton */ 6549677Slinton 655*14757Slinton private read_err() 6569677Slinton { 65711560Slinton /* 658*14757Slinton * Ignore. 65911560Slinton */ 6609677Slinton } 6619677Slinton 662*14757Slinton private write_err() 663*14757Slinton { 664*14757Slinton error("can't write to process (address 0x%x)", badaddr); 665*14757Slinton } 666*14757Slinton 6679677Slinton /* 6689677Slinton * Ptrace interface. 6699677Slinton */ 6709677Slinton 6719677Slinton /* 6729677Slinton * This magic macro enables us to look at the process' registers 673*14757Slinton * in its user structure. 6749677Slinton */ 6759677Slinton 6769677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 6779677Slinton 6789677Slinton #define WMASK (~(sizeof(Word) - 1)) 6799677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 6809677Slinton 6819677Slinton #define FIRSTSIG SIGINT 6829677Slinton #define LASTSIG SIGQUIT 6839677Slinton #define ischild(pid) ((pid) == 0) 6849677Slinton #define traceme() ptrace(0, 0, 0, 0) 6859677Slinton #define setrep(n) (1 << ((n)-1)) 6869677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 6879677Slinton 6889677Slinton /* 6899677Slinton * Ptrace options (specified in first argument). 6909677Slinton */ 6919677Slinton 6929677Slinton #define UREAD 3 /* read from process's user structure */ 6939677Slinton #define UWRITE 6 /* write to process's user structure */ 6949677Slinton #define IREAD 1 /* read from process's instruction space */ 6959677Slinton #define IWRITE 4 /* write to process's instruction space */ 6969677Slinton #define DREAD 2 /* read from process's data space */ 6979677Slinton #define DWRITE 5 /* write to process's data space */ 6989677Slinton #define CONT 7 /* continue stopped process */ 6999677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 7009677Slinton #define PKILL 8 /* terminate the process */ 7019677Slinton 7029677Slinton /* 7039677Slinton * Start up a new process by forking and exec-ing the 7049677Slinton * given argument list, returning when the process is loaded 7059677Slinton * and ready to execute. The PROCESS information (pointed to 7069677Slinton * by the first argument) is appropriately filled. 7079677Slinton * 7089677Slinton * If the given PROCESS structure is associated with an already running 7099677Slinton * process, we terminate it. 7109677Slinton */ 7119677Slinton 7129677Slinton /* VARARGS2 */ 7139677Slinton private pstart(p, argv, infile, outfile) 7149677Slinton Process p; 7159677Slinton String argv[]; 7169677Slinton String infile; 7179677Slinton String outfile; 7189677Slinton { 7199677Slinton int status; 72014395Slinton Fileid in, out; 7219677Slinton 722*14757Slinton if (p->pid != 0) { /* child already running? */ 723*14757Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 72414395Slinton pwait(p->pid, &status); /* wait for it to exit */ 72514395Slinton unptraced(p->pid); 7269677Slinton } 7279677Slinton psigtrace(p, SIGTRAP, true); 72814395Slinton p->pid = vfork(); 72914395Slinton if (p->pid == -1) { 7309677Slinton panic("can't fork"); 7319677Slinton } 7329677Slinton if (ischild(p->pid)) { 7339677Slinton traceme(); 7349677Slinton if (infile != nil) { 73511172Slinton in = open(infile, 0); 73611172Slinton if (in == -1) { 73711172Slinton write(2, "can't read ", 11); 73811172Slinton write(2, infile, strlen(infile)); 73911172Slinton write(2, "\n", 1); 74011172Slinton _exit(1); 7419677Slinton } 74211172Slinton fswap(0, in); 7439677Slinton } 7449677Slinton if (outfile != nil) { 74511172Slinton out = creat(outfile, 0666); 74611172Slinton if (out == -1) { 74711172Slinton write(2, "can't write ", 12); 74811172Slinton write(2, outfile, strlen(outfile)); 74911172Slinton write(2, "\n", 1); 75011172Slinton _exit(1); 7519677Slinton } 75211172Slinton fswap(1, out); 7539677Slinton } 75411832Slinton execv(argv[0], argv); 75511172Slinton write(2, "can't exec ", 11); 75611172Slinton write(2, argv[0], strlen(argv[0])); 75711172Slinton write(2, "\n", 1); 75811172Slinton _exit(1); 7599677Slinton } 7609677Slinton pwait(p->pid, &status); 7619677Slinton getinfo(p, status); 7629677Slinton if (p->status != STOPPED) { 7639677Slinton error("program could not begin execution"); 7649677Slinton } 76514395Slinton ptraced(p->pid); 7669677Slinton } 7679677Slinton 7689677Slinton /* 76911867Slinton * Continue a stopped process. The first argument points to a Process 77011867Slinton * structure. Before the process is restarted it's user area is modified 77111867Slinton * according to the values in the structure. When this routine finishes, 7729677Slinton * the structure has the new values from the process's user area. 7739677Slinton * 7749677Slinton * Pcont terminates when the process stops with a signal pending that 7759677Slinton * is being traced (via psigtrace), or when the process terminates. 7769677Slinton */ 7779677Slinton 77811867Slinton private pcont(p, signo) 7799677Slinton Process p; 78011867Slinton int signo; 7819677Slinton { 7829677Slinton int status; 7839677Slinton 7849677Slinton if (p->pid == 0) { 7859677Slinton error("program not active"); 7869677Slinton } 7879677Slinton do { 78811867Slinton setinfo(p, signo); 7899677Slinton sigs_off(); 7909677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 79114395Slinton panic("error %d trying to continue process", errno); 7929677Slinton } 7939677Slinton pwait(p->pid, &status); 7949677Slinton sigs_on(); 7959677Slinton getinfo(p, status); 7969677Slinton } while (p->status == STOPPED and not istraced(p)); 7979677Slinton } 7989677Slinton 7999677Slinton /* 8009677Slinton * Single step as best ptrace can. 8019677Slinton */ 8029677Slinton 8039677Slinton public pstep(p) 8049677Slinton Process p; 8059677Slinton { 8069677Slinton int status; 8079677Slinton 808*14757Slinton setinfo(p, DEFSIG); 8099677Slinton sigs_off(); 8109677Slinton ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 8119677Slinton pwait(p->pid, &status); 8129677Slinton sigs_on(); 8139677Slinton getinfo(p, status); 8149677Slinton } 8159677Slinton 8169677Slinton /* 8179677Slinton * Return from execution when the given signal is pending. 8189677Slinton */ 8199677Slinton 8209677Slinton public psigtrace(p, sig, sw) 8219677Slinton Process p; 8229677Slinton int sig; 8239677Slinton Boolean sw; 8249677Slinton { 8259677Slinton if (sw) { 8269677Slinton p->sigset |= setrep(sig); 8279677Slinton } else { 8289677Slinton p->sigset &= ~setrep(sig); 8299677Slinton } 8309677Slinton } 8319677Slinton 8329677Slinton /* 8339677Slinton * Don't catch any signals. 8349677Slinton * Particularly useful when letting a process finish uninhibited. 8359677Slinton */ 8369677Slinton 8379677Slinton public unsetsigtraces(p) 8389677Slinton Process p; 8399677Slinton { 8409677Slinton p->sigset = 0; 8419677Slinton } 8429677Slinton 8439677Slinton /* 8449677Slinton * Turn off attention to signals not being caught. 8459677Slinton */ 8469677Slinton 8479677Slinton private Intfunc *sigfunc[NSIG]; 8489677Slinton 8499677Slinton private sigs_off() 8509677Slinton { 8519677Slinton register int i; 8529677Slinton 8539677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8549677Slinton if (i != SIGKILL) { 8559677Slinton sigfunc[i] = signal(i, SIG_IGN); 8569677Slinton } 8579677Slinton } 8589677Slinton } 8599677Slinton 8609677Slinton /* 8619677Slinton * Turn back on attention to signals. 8629677Slinton */ 8639677Slinton 8649677Slinton private sigs_on() 8659677Slinton { 8669677Slinton register int i; 8679677Slinton 8689677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8699677Slinton if (i != SIGKILL) { 8709677Slinton signal(i, sigfunc[i]); 8719677Slinton } 8729677Slinton } 8739677Slinton } 8749677Slinton 8759677Slinton /* 8769677Slinton * Get process information from user area. 8779677Slinton */ 8789677Slinton 8799677Slinton private int rloc[] ={ 8809677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 8819677Slinton }; 8829677Slinton 8839677Slinton private getinfo(p, status) 8849677Slinton register Process p; 8859677Slinton register int status; 8869677Slinton { 8879677Slinton register int i; 8889677Slinton 8899677Slinton p->signo = (status&0177); 8909677Slinton p->exitval = ((status >> 8)&0377); 8919677Slinton if (p->signo != STOPPED) { 8929677Slinton p->status = FINISHED; 893*14757Slinton p->pid = 0; 8949677Slinton } else { 8959677Slinton p->status = p->signo; 8969677Slinton p->signo = p->exitval; 8979677Slinton p->exitval = 0; 8989677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 8999677Slinton for (i = 0; i < NREG; i++) { 9009677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 9019677Slinton p->oreg[i] = p->reg[i]; 9029677Slinton } 90311768Slinton savetty(stdout, &(p->ttyinfo)); 9049677Slinton } 9059677Slinton } 9069677Slinton 9079677Slinton /* 9089677Slinton * Set process's user area information from given process structure. 9099677Slinton */ 9109677Slinton 91111867Slinton private setinfo(p, signo) 9129677Slinton register Process p; 91311867Slinton int signo; 9149677Slinton { 9159677Slinton register int i; 9169677Slinton register int r; 9179677Slinton 918*14757Slinton if (signo == DEFSIG) { 919*14757Slinton if (istraced(p)) { 920*14757Slinton p->signo = 0; 921*14757Slinton } 922*14757Slinton } else { 92311867Slinton p->signo = signo; 9249677Slinton } 9259677Slinton for (i = 0; i < NREG; i++) { 9269677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 9279677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 9289677Slinton } 9299677Slinton } 93011768Slinton restoretty(stdout, &(p->ttyinfo)); 9319677Slinton } 9329677Slinton 9339677Slinton /* 9349677Slinton * Structure for reading and writing by words, but dealing with bytes. 9359677Slinton */ 9369677Slinton 9379677Slinton typedef union { 9389677Slinton Word pword; 9399677Slinton Byte pbyte[sizeof(Word)]; 9409677Slinton } Pword; 9419677Slinton 9429677Slinton /* 9439677Slinton * Read (write) from (to) the process' address space. 9449677Slinton * We must deal with ptrace's inability to look anywhere other 9459677Slinton * than at a word boundary. 9469677Slinton */ 9479677Slinton 9489677Slinton private Word fetch(); 9499677Slinton private store(); 9509677Slinton 9519677Slinton private pio(p, op, seg, buff, addr, nbytes) 9529677Slinton Process p; 9539677Slinton PioOp op; 9549677Slinton PioSeg seg; 9559677Slinton char *buff; 9569677Slinton Address addr; 9579677Slinton int nbytes; 9589677Slinton { 9599677Slinton register int i; 9609677Slinton register Address newaddr; 9619677Slinton register char *cp; 9629677Slinton char *bufend; 9639677Slinton Pword w; 9649677Slinton Address wordaddr; 9659677Slinton int byteoff; 9669677Slinton 9679677Slinton if (p->status != STOPPED) { 9689677Slinton error("program is not active"); 9699677Slinton } 9709677Slinton cp = buff; 9719677Slinton newaddr = addr; 9729677Slinton wordaddr = (newaddr&WMASK); 9739677Slinton if (wordaddr != newaddr) { 9749677Slinton w.pword = fetch(p, seg, wordaddr); 9759677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 9769677Slinton if (op == PREAD) { 9779677Slinton *cp++ = w.pbyte[i]; 9789677Slinton } else { 9799677Slinton w.pbyte[i] = *cp++; 9809677Slinton } 9819677Slinton nbytes--; 9829677Slinton } 9839677Slinton if (op == PWRITE) { 9849677Slinton store(p, seg, wordaddr, w.pword); 9859677Slinton } 9869677Slinton newaddr = wordaddr + sizeof(Word); 9879677Slinton } 9889677Slinton byteoff = (nbytes&(~WMASK)); 9899677Slinton nbytes -= byteoff; 9909677Slinton bufend = cp + nbytes; 9919677Slinton while (cp < bufend) { 9929677Slinton if (op == PREAD) { 9939677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 9949677Slinton } else { 9959677Slinton store(p, seg, newaddr, *((Word *) cp)); 9969677Slinton } 9979677Slinton cp += sizeof(Word); 9989677Slinton newaddr += sizeof(Word); 9999677Slinton } 10009677Slinton if (byteoff > 0) { 10019677Slinton w.pword = fetch(p, seg, newaddr); 10029677Slinton for (i = 0; i < byteoff; i++) { 10039677Slinton if (op == PREAD) { 10049677Slinton *cp++ = w.pbyte[i]; 10059677Slinton } else { 10069677Slinton w.pbyte[i] = *cp++; 10079677Slinton } 10089677Slinton } 10099677Slinton if (op == PWRITE) { 10109677Slinton store(p, seg, newaddr, w.pword); 10119677Slinton } 10129677Slinton } 10139677Slinton } 10149677Slinton 10159677Slinton /* 10169677Slinton * Get a word from a process at the given address. 10179677Slinton * The address is assumed to be on a word boundary. 10189677Slinton * 10199677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 10209677Slinton * to the instruction space since it is assumed to be pure. 10219677Slinton * 10229677Slinton * It is necessary to use a write-through scheme so that 10239677Slinton * breakpoints right next to each other don't interfere. 10249677Slinton */ 10259677Slinton 10269677Slinton private Integer nfetchs, nreads, nwrites; 10279677Slinton 10289677Slinton private Word fetch(p, seg, addr) 10299677Slinton Process p; 10309677Slinton PioSeg seg; 10319677Slinton register int addr; 10329677Slinton { 10339677Slinton register CacheWord *wp; 10349677Slinton register Word w; 10359677Slinton 10369677Slinton switch (seg) { 10379677Slinton case TEXTSEG: 10389677Slinton ++nfetchs; 10399677Slinton wp = &p->word[cachehash(addr)]; 10409677Slinton if (addr == 0 or wp->addr != addr) { 10419677Slinton ++nreads; 10429677Slinton w = ptrace(IREAD, p->pid, addr, 0); 10439677Slinton wp->addr = addr; 10449677Slinton wp->val = w; 10459677Slinton } else { 10469677Slinton w = wp->val; 10479677Slinton } 10489677Slinton break; 10499677Slinton 10509677Slinton case DATASEG: 10519677Slinton w = ptrace(DREAD, p->pid, addr, 0); 10529677Slinton break; 10539677Slinton 10549677Slinton default: 10559677Slinton panic("fetch: bad seg %d", seg); 10569677Slinton /* NOTREACHED */ 10579677Slinton } 10589677Slinton return w; 10599677Slinton } 10609677Slinton 10619677Slinton /* 10629677Slinton * Put a word into the process' address space at the given address. 10639677Slinton * The address is assumed to be on a word boundary. 10649677Slinton */ 10659677Slinton 10669677Slinton private store(p, seg, addr, data) 10679677Slinton Process p; 10689677Slinton PioSeg seg; 10699677Slinton int addr; 10709677Slinton Word data; 10719677Slinton { 10729677Slinton register CacheWord *wp; 10739677Slinton 10749677Slinton switch (seg) { 10759677Slinton case TEXTSEG: 10769677Slinton ++nwrites; 10779677Slinton wp = &p->word[cachehash(addr)]; 10789677Slinton wp->addr = addr; 10799677Slinton wp->val = data; 10809677Slinton ptrace(IWRITE, p->pid, addr, data); 10819677Slinton break; 10829677Slinton 10839677Slinton case DATASEG: 10849677Slinton ptrace(DWRITE, p->pid, addr, data); 10859677Slinton break; 10869677Slinton 10879677Slinton default: 10889677Slinton panic("store: bad seg %d", seg); 10899677Slinton /* NOTREACHED */ 10909677Slinton } 10919677Slinton } 10929677Slinton 10939677Slinton public printptraceinfo() 10949677Slinton { 10959677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 10969677Slinton } 10979677Slinton 10989677Slinton /* 10999677Slinton * Swap file numbers so as to redirect standard input and output. 11009677Slinton */ 11019677Slinton 11029677Slinton private fswap(oldfd, newfd) 11039677Slinton int oldfd; 11049677Slinton int newfd; 11059677Slinton { 11069677Slinton if (oldfd != newfd) { 11079677Slinton close(oldfd); 11089677Slinton dup(newfd); 11099677Slinton close(newfd); 11109677Slinton } 11119677Slinton } 1112