19677Slinton /* Copyright (c) 1982 Regents of the University of California */ 29677Slinton 3*11867Slinton static char sccsid[] = "@(#)process.c 1.8 04/08/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 301*11867Slinton public cont(signo) 302*11867Slinton int signo; 3039677Slinton { 3049677Slinton dbintr = signal(SIGINT, intr); 3059677Slinton if (just_started) { 3069677Slinton just_started = false; 3079677Slinton } else { 3089677Slinton if (not isstopped) { 3099677Slinton error("can't continue execution"); 3109677Slinton } 3119677Slinton isstopped = false; 312*11867Slinton stepover(); 3139677Slinton } 3149677Slinton for (;;) { 3159677Slinton if (single_stepping) { 3169677Slinton printnews(); 3179677Slinton } else { 3189677Slinton setallbps(); 319*11867Slinton resume(signo); 3209677Slinton unsetallbps(); 3219677Slinton if (bpact() fails) { 3229677Slinton printstatus(); 3239677Slinton } 3249677Slinton } 325*11867Slinton stepover(); 3269677Slinton } 3279677Slinton /* NOTREACHED */ 3289677Slinton } 3299677Slinton 3309677Slinton /* 3319677Slinton * This routine is called if we get an interrupt while "running" px 3329677Slinton * but actually in the debugger. Could happen, for example, while 3339677Slinton * processing breakpoints. 3349677Slinton * 3359677Slinton * We basically just want to keep going; the assumption is 3369677Slinton * that when the process resumes it will get the interrupt 3379677Slinton * which will then be handled. 3389677Slinton */ 3399677Slinton 3409677Slinton private intr() 3419677Slinton { 3429677Slinton signal(SIGINT, intr); 3439677Slinton } 3449677Slinton 3459677Slinton public fixintr() 3469677Slinton { 3479677Slinton signal(SIGINT, dbintr); 3489677Slinton } 3499677Slinton 3509677Slinton /* 3519677Slinton * Resume execution. 3529677Slinton */ 3539677Slinton 354*11867Slinton public resume(signo) 355*11867Slinton int signo; 3569677Slinton { 3579677Slinton register Process p; 3589677Slinton 3599677Slinton p = process; 3609677Slinton if (traceexec) { 3619677Slinton printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]); 3629677Slinton fflush(stdout); 3639677Slinton } 364*11867Slinton pcont(p, signo); 3659677Slinton pc = process->reg[PROGCTR]; 3669677Slinton if (traceexec) { 3679677Slinton printf("execution stops at pc 0x%x on sig %d\n", 3689677Slinton process->reg[PROGCTR], p->signo); 3699677Slinton fflush(stdout); 3709677Slinton } 37111832Slinton if (p->status != STOPPED) { 372*11867Slinton if (p->signo != 0) { 373*11867Slinton error("program terminated by signal %d", p->signo); 374*11867Slinton } else { 375*11867Slinton error("program unexpectedly exited with %d", p->exitval); 376*11867Slinton } 37711832Slinton } 3789677Slinton } 3799677Slinton 3809677Slinton /* 3819677Slinton * Continue execution up to the next source line. 3829677Slinton * 3839677Slinton * There are two ways to define the next source line depending on what 3849677Slinton * is desired when a procedure or function call is encountered. Step 3859677Slinton * stops at the beginning of the procedure or call; next skips over it. 3869677Slinton */ 3879677Slinton 3889677Slinton /* 3899677Slinton * Stepc is what is called when the step command is given. 3909677Slinton * It has to play with the "isstopped" information. 3919677Slinton */ 3929677Slinton 3939677Slinton public stepc() 3949677Slinton { 3959677Slinton if (not isstopped) { 3969677Slinton error("can't continue execution"); 3979677Slinton } 3989677Slinton isstopped = false; 3999677Slinton dostep(false); 4009677Slinton isstopped = true; 4019677Slinton } 4029677Slinton 4039677Slinton public next() 4049677Slinton { 4059677Slinton if (not isstopped) { 4069677Slinton error("can't continue execution"); 4079677Slinton } 4089677Slinton isstopped = false; 4099677Slinton dostep(true); 4109677Slinton isstopped = true; 4119677Slinton } 4129677Slinton 413*11867Slinton /* 414*11867Slinton * Single-step over the current machine instruction. 415*11867Slinton * 416*11867Slinton * If we're single-stepping by source line we want to step to the 417*11867Slinton * next source line. Otherwise we're going to continue so there's 418*11867Slinton * no reason to do all the work necessary to single-step to the next 419*11867Slinton * source line. 420*11867Slinton */ 421*11867Slinton 422*11867Slinton private stepover() 4239677Slinton { 424*11867Slinton Boolean b; 425*11867Slinton 426*11867Slinton if (single_stepping) { 427*11867Slinton dostep(false); 428*11867Slinton } else { 429*11867Slinton b = inst_tracing; 430*11867Slinton inst_tracing = true; 431*11867Slinton dostep(false); 432*11867Slinton inst_tracing = b; 433*11867Slinton } 4349677Slinton } 4359677Slinton 4369677Slinton /* 4379677Slinton * Resume execution up to the given address. It is assumed that 4389677Slinton * no breakpoints exist between the current address and the one 4399677Slinton * we're stepping to. This saves us from setting all the breakpoints. 4409677Slinton */ 4419677Slinton 4429677Slinton public stepto(addr) 4439677Slinton Address addr; 4449677Slinton { 4459677Slinton setbp(addr); 446*11867Slinton resume(0); 4479677Slinton unsetbp(addr); 4489677Slinton if (not isbperr()) { 4499677Slinton printstatus(); 4509677Slinton } 4519677Slinton } 4529677Slinton 4539677Slinton /* 4549677Slinton * Print the status of the process. 4559677Slinton * This routine does not return. 4569677Slinton */ 4579677Slinton 4589677Slinton public printstatus() 4599677Slinton { 4609843Slinton if (process->status == FINISHED) { 4619843Slinton exit(0); 4629843Slinton } else { 4639843Slinton curfunc = whatblock(pc); 4649677Slinton getsrcpos(); 4659843Slinton if (process->signo == SIGINT) { 4669843Slinton isstopped = true; 4679843Slinton printerror(); 4689843Slinton } else if (isbperr() and isstopped) { 4699843Slinton printf("stopped "); 47011172Slinton printloc(); 47111172Slinton putchar('\n'); 4729843Slinton if (curline > 0) { 4739843Slinton printlines(curline, curline); 4749843Slinton } else { 4759843Slinton printinst(pc, pc); 4769843Slinton } 4779843Slinton erecover(); 4789677Slinton } else { 4799843Slinton fixbps(); 4809843Slinton fixintr(); 4819677Slinton isstopped = true; 4829677Slinton printerror(); 4839677Slinton } 4849677Slinton } 4859677Slinton } 4869677Slinton 4879677Slinton /* 48811172Slinton * Print out the current location in the debuggee. 48911172Slinton */ 49011172Slinton 49111172Slinton public printloc() 49211172Slinton { 49311172Slinton printf("in "); 49411172Slinton printname(stdout, curfunc); 49511172Slinton putchar(' '); 49611172Slinton if (curline > 0) { 49711172Slinton printsrcpos(); 49811172Slinton } else { 49911172Slinton printf("at 0x%x", pc); 50011172Slinton } 50111172Slinton } 50211172Slinton 50311172Slinton /* 5049677Slinton * Some functions for testing the state of the process. 5059677Slinton */ 5069677Slinton 5079677Slinton public Boolean notstarted(p) 5089677Slinton Process p; 5099677Slinton { 5109677Slinton return (Boolean) (p->status == NOTSTARTED); 5119677Slinton } 5129677Slinton 5139677Slinton public Boolean isfinished(p) 5149677Slinton Process p; 5159677Slinton { 5169677Slinton return (Boolean) (p->status == FINISHED); 5179677Slinton } 5189677Slinton 5199677Slinton /* 5209677Slinton * Return the signal number which stopped the process. 5219677Slinton */ 5229677Slinton 5239677Slinton public Integer errnum(p) 5249677Slinton Process p; 5259677Slinton { 5269677Slinton return p->signo; 5279677Slinton } 5289677Slinton 5299677Slinton /* 5309677Slinton * Return the termination code of the process. 5319677Slinton */ 5329677Slinton 5339677Slinton public Integer exitcode(p) 5349677Slinton Process p; 5359677Slinton { 5369677Slinton return p->exitval; 5379677Slinton } 5389677Slinton 5399677Slinton /* 5409677Slinton * These routines are used to access the debuggee process from 5419677Slinton * outside this module. 5429677Slinton * 5439677Slinton * They invoke "pio" which eventually leads to a call to "ptrace". 54411560Slinton * The system generates an I/O error when a ptrace fails, we assume 54511560Slinton * during a read/write to the process that such an error is due to 54611560Slinton * a misguided address and ignore it. 5479677Slinton */ 5489677Slinton 5499677Slinton extern Intfunc *onsyserr(); 5509677Slinton 5519677Slinton private badaddr; 5529677Slinton private rwerr(); 5539677Slinton 5549677Slinton /* 5559677Slinton * Read from the process' instruction area. 5569677Slinton */ 5579677Slinton 5589677Slinton public iread(buff, addr, nbytes) 5599677Slinton char *buff; 5609677Slinton Address addr; 5619677Slinton int nbytes; 5629677Slinton { 5639677Slinton Intfunc *f; 5649677Slinton 5659677Slinton f = onsyserr(EIO, rwerr); 5669677Slinton badaddr = addr; 5679677Slinton if (coredump) { 5689677Slinton coredump_readtext(buff, addr, nbytes); 5699677Slinton } else { 5709677Slinton pio(process, PREAD, TEXTSEG, buff, addr, nbytes); 5719677Slinton } 5729677Slinton onsyserr(EIO, f); 5739677Slinton } 5749677Slinton 5759677Slinton /* 5769677Slinton * Write to the process' instruction area, usually in order to set 5779677Slinton * or unset a breakpoint. 5789677Slinton */ 5799677Slinton 5809677Slinton public iwrite(buff, addr, nbytes) 5819677Slinton char *buff; 5829677Slinton Address addr; 5839677Slinton int nbytes; 5849677Slinton { 5859677Slinton Intfunc *f; 5869677Slinton 5879677Slinton if (coredump) { 5889677Slinton error("no process to write to"); 5899677Slinton } 5909677Slinton f = onsyserr(EIO, rwerr); 5919677Slinton badaddr = addr; 5929677Slinton pio(process, PWRITE, TEXTSEG, buff, addr, nbytes); 5939677Slinton onsyserr(EIO, f); 5949677Slinton } 5959677Slinton 5969677Slinton /* 5979677Slinton * Read for the process' data area. 5989677Slinton */ 5999677Slinton 6009677Slinton public dread(buff, addr, nbytes) 6019677Slinton char *buff; 6029677Slinton Address addr; 6039677Slinton int nbytes; 6049677Slinton { 6059677Slinton Intfunc *f; 6069677Slinton 6079677Slinton f = onsyserr(EIO, rwerr); 6089677Slinton badaddr = addr; 6099677Slinton if (coredump) { 6109677Slinton coredump_readdata(buff, addr, nbytes); 6119677Slinton } else { 6129677Slinton pio(process, PREAD, DATASEG, buff, addr, nbytes); 6139677Slinton } 6149677Slinton onsyserr(EIO, f); 6159677Slinton } 6169677Slinton 6179677Slinton /* 6189677Slinton * Write to the process' data area. 6199677Slinton */ 6209677Slinton 6219677Slinton public dwrite(buff, addr, nbytes) 6229677Slinton char *buff; 6239677Slinton Address addr; 6249677Slinton int nbytes; 6259677Slinton { 6269677Slinton Intfunc *f; 6279677Slinton 6289677Slinton if (coredump) { 6299677Slinton error("no process to write to"); 6309677Slinton } 6319677Slinton f = onsyserr(EIO, rwerr); 6329677Slinton badaddr = addr; 6339677Slinton pio(process, PWRITE, DATASEG, buff, addr, nbytes); 6349677Slinton onsyserr(EIO, f); 6359677Slinton } 6369677Slinton 6379677Slinton /* 6389677Slinton * Error handler. 6399677Slinton */ 6409677Slinton 6419677Slinton private rwerr() 6429677Slinton { 64311560Slinton /* 64411560Slinton * Current response is to ignore the error and let the result 64511560Slinton * (-1) ripple back up to the process. 64611560Slinton * 6479677Slinton error("bad read/write process address 0x%x", badaddr); 64811560Slinton */ 6499677Slinton } 6509677Slinton 6519677Slinton /* 6529677Slinton * Ptrace interface. 6539677Slinton */ 6549677Slinton 6559677Slinton /* 6569677Slinton * This magic macro enables us to look at the process' registers 6579677Slinton * in its user structure. Very gross. 6589677Slinton */ 6599677Slinton 6609677Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 6619677Slinton 6629677Slinton #define WMASK (~(sizeof(Word) - 1)) 6639677Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 6649677Slinton 6659677Slinton #define FIRSTSIG SIGINT 6669677Slinton #define LASTSIG SIGQUIT 6679677Slinton #define ischild(pid) ((pid) == 0) 6689677Slinton #define traceme() ptrace(0, 0, 0, 0) 6699677Slinton #define setrep(n) (1 << ((n)-1)) 6709677Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 6719677Slinton 6729677Slinton /* 6739677Slinton * Ptrace options (specified in first argument). 6749677Slinton */ 6759677Slinton 6769677Slinton #define UREAD 3 /* read from process's user structure */ 6779677Slinton #define UWRITE 6 /* write to process's user structure */ 6789677Slinton #define IREAD 1 /* read from process's instruction space */ 6799677Slinton #define IWRITE 4 /* write to process's instruction space */ 6809677Slinton #define DREAD 2 /* read from process's data space */ 6819677Slinton #define DWRITE 5 /* write to process's data space */ 6829677Slinton #define CONT 7 /* continue stopped process */ 6839677Slinton #define SSTEP 9 /* continue for approximately one instruction */ 6849677Slinton #define PKILL 8 /* terminate the process */ 6859677Slinton 6869677Slinton /* 6879677Slinton * Start up a new process by forking and exec-ing the 6889677Slinton * given argument list, returning when the process is loaded 6899677Slinton * and ready to execute. The PROCESS information (pointed to 6909677Slinton * by the first argument) is appropriately filled. 6919677Slinton * 6929677Slinton * If the given PROCESS structure is associated with an already running 6939677Slinton * process, we terminate it. 6949677Slinton */ 6959677Slinton 6969677Slinton /* VARARGS2 */ 6979677Slinton private pstart(p, argv, infile, outfile) 6989677Slinton Process p; 6999677Slinton String argv[]; 7009677Slinton String infile; 7019677Slinton String outfile; 7029677Slinton { 7039677Slinton int status; 7049677Slinton 7059677Slinton if (p->pid != 0) { /* child already running? */ 7069677Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 7079677Slinton } 7089677Slinton psigtrace(p, SIGTRAP, true); 70911172Slinton if ((p->pid = vfork()) == -1) { 7109677Slinton panic("can't fork"); 7119677Slinton } 7129677Slinton if (ischild(p->pid)) { 71311172Slinton Fileid in, out; 71411172Slinton 7159677Slinton traceme(); 7169677Slinton if (infile != nil) { 71711172Slinton in = open(infile, 0); 71811172Slinton if (in == -1) { 71911172Slinton write(2, "can't read ", 11); 72011172Slinton write(2, infile, strlen(infile)); 72111172Slinton write(2, "\n", 1); 72211172Slinton _exit(1); 7239677Slinton } 72411172Slinton fswap(0, in); 7259677Slinton } 7269677Slinton if (outfile != nil) { 72711172Slinton out = creat(outfile, 0666); 72811172Slinton if (out == -1) { 72911172Slinton write(2, "can't write ", 12); 73011172Slinton write(2, outfile, strlen(outfile)); 73111172Slinton write(2, "\n", 1); 73211172Slinton _exit(1); 7339677Slinton } 73411172Slinton fswap(1, out); 7359677Slinton } 73611832Slinton execv(argv[0], argv); 73711172Slinton write(2, "can't exec ", 11); 73811172Slinton write(2, argv[0], strlen(argv[0])); 73911172Slinton write(2, "\n", 1); 74011172Slinton _exit(1); 7419677Slinton } 7429677Slinton pwait(p->pid, &status); 7439677Slinton getinfo(p, status); 7449677Slinton if (p->status != STOPPED) { 7459677Slinton error("program could not begin execution"); 7469677Slinton } 7479677Slinton } 7489677Slinton 7499677Slinton /* 750*11867Slinton * Continue a stopped process. The first argument points to a Process 751*11867Slinton * structure. Before the process is restarted it's user area is modified 752*11867Slinton * according to the values in the structure. When this routine finishes, 7539677Slinton * the structure has the new values from the process's user area. 7549677Slinton * 7559677Slinton * Pcont terminates when the process stops with a signal pending that 7569677Slinton * is being traced (via psigtrace), or when the process terminates. 7579677Slinton */ 7589677Slinton 759*11867Slinton private pcont(p, signo) 7609677Slinton Process p; 761*11867Slinton int signo; 7629677Slinton { 7639677Slinton int status; 7649677Slinton 7659677Slinton if (p->pid == 0) { 7669677Slinton error("program not active"); 7679677Slinton } 7689677Slinton do { 769*11867Slinton setinfo(p, signo); 7709677Slinton sigs_off(); 7719677Slinton if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) { 7729677Slinton panic("can't continue process"); 7739677Slinton } 7749677Slinton pwait(p->pid, &status); 7759677Slinton sigs_on(); 7769677Slinton getinfo(p, status); 7779677Slinton } while (p->status == STOPPED and not istraced(p)); 7789677Slinton } 7799677Slinton 7809677Slinton /* 7819677Slinton * Single step as best ptrace can. 7829677Slinton */ 7839677Slinton 7849677Slinton public pstep(p) 7859677Slinton Process p; 7869677Slinton { 7879677Slinton int status; 7889677Slinton 789*11867Slinton setinfo(p, 0); 7909677Slinton sigs_off(); 7919677Slinton ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo); 7929677Slinton pwait(p->pid, &status); 7939677Slinton sigs_on(); 7949677Slinton getinfo(p, status); 7959677Slinton } 7969677Slinton 7979677Slinton /* 7989677Slinton * Return from execution when the given signal is pending. 7999677Slinton */ 8009677Slinton 8019677Slinton public psigtrace(p, sig, sw) 8029677Slinton Process p; 8039677Slinton int sig; 8049677Slinton Boolean sw; 8059677Slinton { 8069677Slinton if (sw) { 8079677Slinton p->sigset |= setrep(sig); 8089677Slinton } else { 8099677Slinton p->sigset &= ~setrep(sig); 8109677Slinton } 8119677Slinton } 8129677Slinton 8139677Slinton /* 8149677Slinton * Don't catch any signals. 8159677Slinton * Particularly useful when letting a process finish uninhibited. 8169677Slinton */ 8179677Slinton 8189677Slinton public unsetsigtraces(p) 8199677Slinton Process p; 8209677Slinton { 8219677Slinton p->sigset = 0; 8229677Slinton } 8239677Slinton 8249677Slinton /* 8259677Slinton * Turn off attention to signals not being caught. 8269677Slinton */ 8279677Slinton 8289677Slinton private Intfunc *sigfunc[NSIG]; 8299677Slinton 8309677Slinton private sigs_off() 8319677Slinton { 8329677Slinton register int i; 8339677Slinton 8349677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8359677Slinton if (i != SIGKILL) { 8369677Slinton sigfunc[i] = signal(i, SIG_IGN); 8379677Slinton } 8389677Slinton } 8399677Slinton } 8409677Slinton 8419677Slinton /* 8429677Slinton * Turn back on attention to signals. 8439677Slinton */ 8449677Slinton 8459677Slinton private sigs_on() 8469677Slinton { 8479677Slinton register int i; 8489677Slinton 8499677Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 8509677Slinton if (i != SIGKILL) { 8519677Slinton signal(i, sigfunc[i]); 8529677Slinton } 8539677Slinton } 8549677Slinton } 8559677Slinton 8569677Slinton /* 8579677Slinton * Get process information from user area. 8589677Slinton */ 8599677Slinton 8609677Slinton private int rloc[] ={ 8619677Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC 8629677Slinton }; 8639677Slinton 8649677Slinton private getinfo(p, status) 8659677Slinton register Process p; 8669677Slinton register int status; 8679677Slinton { 8689677Slinton register int i; 8699677Slinton 8709677Slinton p->signo = (status&0177); 8719677Slinton p->exitval = ((status >> 8)&0377); 8729677Slinton if (p->signo != STOPPED) { 8739677Slinton p->status = FINISHED; 8749677Slinton } else { 8759677Slinton p->status = p->signo; 8769677Slinton p->signo = p->exitval; 8779677Slinton p->exitval = 0; 8789677Slinton p->mask = ptrace(UREAD, p->pid, regloc(PS), 0); 8799677Slinton for (i = 0; i < NREG; i++) { 8809677Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 8819677Slinton p->oreg[i] = p->reg[i]; 8829677Slinton } 88311768Slinton savetty(stdout, &(p->ttyinfo)); 8849677Slinton } 8859677Slinton } 8869677Slinton 8879677Slinton /* 8889677Slinton * Set process's user area information from given process structure. 8899677Slinton */ 8909677Slinton 891*11867Slinton private setinfo(p, signo) 8929677Slinton register Process p; 893*11867Slinton int signo; 8949677Slinton { 8959677Slinton register int i; 8969677Slinton register int r; 8979677Slinton 8989677Slinton if (istraced(p)) { 899*11867Slinton p->signo = signo; 9009677Slinton } 9019677Slinton for (i = 0; i < NREG; i++) { 9029677Slinton if ((r = p->reg[i]) != p->oreg[i]) { 9039677Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 9049677Slinton } 9059677Slinton } 90611768Slinton restoretty(stdout, &(p->ttyinfo)); 9079677Slinton } 9089677Slinton 9099677Slinton /* 9109677Slinton * Structure for reading and writing by words, but dealing with bytes. 9119677Slinton */ 9129677Slinton 9139677Slinton typedef union { 9149677Slinton Word pword; 9159677Slinton Byte pbyte[sizeof(Word)]; 9169677Slinton } Pword; 9179677Slinton 9189677Slinton /* 9199677Slinton * Read (write) from (to) the process' address space. 9209677Slinton * We must deal with ptrace's inability to look anywhere other 9219677Slinton * than at a word boundary. 9229677Slinton */ 9239677Slinton 9249677Slinton private Word fetch(); 9259677Slinton private store(); 9269677Slinton 9279677Slinton private pio(p, op, seg, buff, addr, nbytes) 9289677Slinton Process p; 9299677Slinton PioOp op; 9309677Slinton PioSeg seg; 9319677Slinton char *buff; 9329677Slinton Address addr; 9339677Slinton int nbytes; 9349677Slinton { 9359677Slinton register int i; 9369677Slinton register Address newaddr; 9379677Slinton register char *cp; 9389677Slinton char *bufend; 9399677Slinton Pword w; 9409677Slinton Address wordaddr; 9419677Slinton int byteoff; 9429677Slinton 9439677Slinton if (p->status != STOPPED) { 9449677Slinton error("program is not active"); 9459677Slinton } 9469677Slinton cp = buff; 9479677Slinton newaddr = addr; 9489677Slinton wordaddr = (newaddr&WMASK); 9499677Slinton if (wordaddr != newaddr) { 9509677Slinton w.pword = fetch(p, seg, wordaddr); 9519677Slinton for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) { 9529677Slinton if (op == PREAD) { 9539677Slinton *cp++ = w.pbyte[i]; 9549677Slinton } else { 9559677Slinton w.pbyte[i] = *cp++; 9569677Slinton } 9579677Slinton nbytes--; 9589677Slinton } 9599677Slinton if (op == PWRITE) { 9609677Slinton store(p, seg, wordaddr, w.pword); 9619677Slinton } 9629677Slinton newaddr = wordaddr + sizeof(Word); 9639677Slinton } 9649677Slinton byteoff = (nbytes&(~WMASK)); 9659677Slinton nbytes -= byteoff; 9669677Slinton bufend = cp + nbytes; 9679677Slinton while (cp < bufend) { 9689677Slinton if (op == PREAD) { 9699677Slinton *((Word *) cp) = fetch(p, seg, newaddr); 9709677Slinton } else { 9719677Slinton store(p, seg, newaddr, *((Word *) cp)); 9729677Slinton } 9739677Slinton cp += sizeof(Word); 9749677Slinton newaddr += sizeof(Word); 9759677Slinton } 9769677Slinton if (byteoff > 0) { 9779677Slinton w.pword = fetch(p, seg, newaddr); 9789677Slinton for (i = 0; i < byteoff; i++) { 9799677Slinton if (op == PREAD) { 9809677Slinton *cp++ = w.pbyte[i]; 9819677Slinton } else { 9829677Slinton w.pbyte[i] = *cp++; 9839677Slinton } 9849677Slinton } 9859677Slinton if (op == PWRITE) { 9869677Slinton store(p, seg, newaddr, w.pword); 9879677Slinton } 9889677Slinton } 9899677Slinton } 9909677Slinton 9919677Slinton /* 9929677Slinton * Get a word from a process at the given address. 9939677Slinton * The address is assumed to be on a word boundary. 9949677Slinton * 9959677Slinton * A simple cache scheme is used to avoid redundant ptrace calls 9969677Slinton * to the instruction space since it is assumed to be pure. 9979677Slinton * 9989677Slinton * It is necessary to use a write-through scheme so that 9999677Slinton * breakpoints right next to each other don't interfere. 10009677Slinton */ 10019677Slinton 10029677Slinton private Integer nfetchs, nreads, nwrites; 10039677Slinton 10049677Slinton private Word fetch(p, seg, addr) 10059677Slinton Process p; 10069677Slinton PioSeg seg; 10079677Slinton register int addr; 10089677Slinton { 10099677Slinton register CacheWord *wp; 10109677Slinton register Word w; 10119677Slinton 10129677Slinton switch (seg) { 10139677Slinton case TEXTSEG: 10149677Slinton ++nfetchs; 10159677Slinton wp = &p->word[cachehash(addr)]; 10169677Slinton if (addr == 0 or wp->addr != addr) { 10179677Slinton ++nreads; 10189677Slinton w = ptrace(IREAD, p->pid, addr, 0); 10199677Slinton wp->addr = addr; 10209677Slinton wp->val = w; 10219677Slinton } else { 10229677Slinton w = wp->val; 10239677Slinton } 10249677Slinton break; 10259677Slinton 10269677Slinton case DATASEG: 10279677Slinton w = ptrace(DREAD, p->pid, addr, 0); 10289677Slinton break; 10299677Slinton 10309677Slinton default: 10319677Slinton panic("fetch: bad seg %d", seg); 10329677Slinton /* NOTREACHED */ 10339677Slinton } 10349677Slinton return w; 10359677Slinton } 10369677Slinton 10379677Slinton /* 10389677Slinton * Put a word into the process' address space at the given address. 10399677Slinton * The address is assumed to be on a word boundary. 10409677Slinton */ 10419677Slinton 10429677Slinton private store(p, seg, addr, data) 10439677Slinton Process p; 10449677Slinton PioSeg seg; 10459677Slinton int addr; 10469677Slinton Word data; 10479677Slinton { 10489677Slinton register CacheWord *wp; 10499677Slinton 10509677Slinton switch (seg) { 10519677Slinton case TEXTSEG: 10529677Slinton ++nwrites; 10539677Slinton wp = &p->word[cachehash(addr)]; 10549677Slinton wp->addr = addr; 10559677Slinton wp->val = data; 10569677Slinton ptrace(IWRITE, p->pid, addr, data); 10579677Slinton break; 10589677Slinton 10599677Slinton case DATASEG: 10609677Slinton ptrace(DWRITE, p->pid, addr, data); 10619677Slinton break; 10629677Slinton 10639677Slinton default: 10649677Slinton panic("store: bad seg %d", seg); 10659677Slinton /* NOTREACHED */ 10669677Slinton } 10679677Slinton } 10689677Slinton 10699677Slinton public printptraceinfo() 10709677Slinton { 10719677Slinton printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites); 10729677Slinton } 10739677Slinton 10749677Slinton /* 10759677Slinton * Swap file numbers so as to redirect standard input and output. 10769677Slinton */ 10779677Slinton 10789677Slinton private fswap(oldfd, newfd) 10799677Slinton int oldfd; 10809677Slinton int newfd; 10819677Slinton { 10829677Slinton if (oldfd != newfd) { 10839677Slinton close(oldfd); 10849677Slinton dup(newfd); 10859677Slinton close(newfd); 10869677Slinton } 10879677Slinton } 1088