148096Sbostic /*- 2*62144Sbostic * Copyright (c) 1980, 1993 3*62144Sbostic * The Regents of the University of California. All rights reserved. 448096Sbostic * 548096Sbostic * %sccs.include.redist.c% 622510Sdist */ 710768Slinton 822510Sdist #ifndef lint 9*62144Sbostic static char sccsid[] = "@(#)ptrace.c 8.1 (Berkeley) 06/06/93"; 1048096Sbostic #endif /* not lint */ 115507Slinton 125507Slinton /* 135507Slinton * routines for tracing the execution of a process 145507Slinton * 155507Slinton * The system call "ptrace" does all the work, these 165507Slinton * routines just try to interface easily to it. 175507Slinton */ 185507Slinton 195507Slinton #include "defs.h" 205507Slinton #include <signal.h> 215507Slinton #include <sys/param.h> 2210004Ssam #include <machine/reg.h> 235507Slinton #include "process.h" 245507Slinton #include "object.h" 255507Slinton #include "process.rep" 265507Slinton 276072Slinton # include "pxinfo.h" 285507Slinton 2930848Smckusick #ifdef mc68000 3010768Slinton # define U_PAGE 0x2400 3110768Slinton # define U_AR0 (14*sizeof(int)) 3210768Slinton LOCAL int ar0val = -1; 3310768Slinton #endif 3410768Slinton 355507Slinton /* 365507Slinton * This magic macro enables us to look at the process' registers 375507Slinton * in its user structure. Very gross. 385507Slinton */ 395507Slinton 4030848Smckusick #if defined(vax) || defined(tahoe) 4110768Slinton # define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 4210768Slinton #else 4310768Slinton # define regloc(reg) (ar0val + ( sizeof(int) * (reg) )) 4410768Slinton #endif 455507Slinton 466072Slinton #define WMASK (~(sizeof(WORD) - 1)) 476072Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 485507Slinton 496072Slinton #define ischild(pid) ((pid) == 0) 506072Slinton #define traceme() ptrace(0, 0, 0, 0) 516072Slinton #define setrep(n) (1 << ((n)-1)) 526072Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 535507Slinton 545507Slinton /* 555507Slinton * ptrace options (specified in first argument) 565507Slinton */ 575507Slinton 586072Slinton #define UREAD 3 /* read from process's user structure */ 596072Slinton #define UWRITE 6 /* write to process's user structure */ 606072Slinton #define IREAD 1 /* read from process's instruction space */ 616072Slinton #define IWRITE 4 /* write to process's instruction space */ 626072Slinton #define DREAD 2 /* read from process's data space */ 636072Slinton #define DWRITE 5 /* write to process's data space */ 646072Slinton #define CONT 7 /* continue stopped process */ 656072Slinton #define SSTEP 9 /* continue for approximately one instruction */ 666072Slinton #define PKILL 8 /* terminate the process */ 675507Slinton 685507Slinton /* 695507Slinton * Start up a new process by forking and exec-ing the 705507Slinton * given argument list, returning when the process is loaded 715507Slinton * and ready to execute. The PROCESS information (pointed to 725507Slinton * by the first argument) is appropriately filled. 735507Slinton * 745507Slinton * If the given PROCESS structure is associated with an already running 755507Slinton * process, we terminate it. 765507Slinton */ 775507Slinton 785507Slinton /* VARARGS2 */ 795607Slinton pstart(p, cmd, argv, infile, outfile) 805507Slinton PROCESS *p; 815607Slinton char *cmd; 825507Slinton char **argv; 835507Slinton char *infile; 845507Slinton char *outfile; 855507Slinton { 866072Slinton int status; 876072Slinton FILE *in, *out; 885507Slinton 896072Slinton if (p->pid != 0) { /* child already running? */ 906072Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 916072Slinton } 9231082Smckusick #ifdef tahoe 9330848Smckusick INTFP = (ADDRESS)0; 9431082Smckusick #endif tahoe 956072Slinton psigtrace(p, SIGTRAP, TRUE); 966072Slinton if ((p->pid = fork()) == -1) { 976072Slinton panic("can't fork"); 986072Slinton } 996072Slinton if (ischild(p->pid)) { 1006072Slinton traceme(); 1016072Slinton if (infile != NIL) { 1026072Slinton if ((in = fopen(infile, "r")) == NIL) { 1036072Slinton printf("can't read %s\n", infile); 1046072Slinton exit(1); 1056072Slinton } 1066072Slinton fswap(0, fileno(in)); 1075507Slinton } 1086072Slinton if (outfile != NIL) { 1096072Slinton if ((out = fopen(outfile, "w")) == NIL) { 1106072Slinton printf("can't write %s\n", outfile); 1116072Slinton exit(1); 1126072Slinton } 1136072Slinton fswap(1, fileno(out)); 1145507Slinton } 1156072Slinton execvp(cmd, argv); 1166072Slinton panic("can't exec %s", argv[0]); 1176072Slinton } 1186072Slinton pwait(p->pid, &status); 1196072Slinton getinfo(p, status); 1205507Slinton } 1215507Slinton 1225507Slinton /* 1235507Slinton * Continue a stopped process. The argument points to a PROCESS structure. 1245507Slinton * Before the process is restarted it's user area is modified according to 1255507Slinton * the values in the structure. When this routine finishes, 1265507Slinton * the structure has the new values from the process's user area. 1275507Slinton * 1285507Slinton * Pcont terminates when the process stops with a signal pending that 1295507Slinton * is being traced (via psigtrace), or when the process terminates. 1305507Slinton */ 1315507Slinton 1325507Slinton pcont(p) 1335507Slinton PROCESS *p; 1345507Slinton { 1356072Slinton int status; 1365507Slinton 1376072Slinton if (p->pid == 0) { 1386072Slinton error("program not active"); 1396072Slinton } 1406072Slinton do { 1416072Slinton setinfo(p); 1426072Slinton sigs_off(); 1436072Slinton if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) { 1446072Slinton panic("can't continue process"); 1455507Slinton } 1466072Slinton pwait(p->pid, &status); 1476072Slinton sigs_on(); 1486072Slinton getinfo(p, status); 1496072Slinton } while (p->status == STOPPED && !istraced(p)); 1505507Slinton } 1515507Slinton 1525507Slinton /* 1535507Slinton * single step as best ptrace can 1545507Slinton */ 1555507Slinton 1565507Slinton pstep(p) 1575507Slinton PROCESS *p; 1585507Slinton { 1596072Slinton int status; 1605507Slinton 1616072Slinton setinfo(p); 1626072Slinton sigs_off(); 1636072Slinton ptrace(SSTEP, p->pid, p->pc, p->signo); 1646072Slinton pwait(p->pid, &status); 1656072Slinton sigs_on(); 1666072Slinton getinfo(p, status); 1675507Slinton } 1685507Slinton 1695507Slinton /* 1705507Slinton * Return from execution when the given signal is pending. 1715507Slinton */ 1725507Slinton 1735507Slinton psigtrace(p, sig, sw) 1745507Slinton PROCESS *p; 1755507Slinton int sig; 1765507Slinton int sw; 1775507Slinton { 1786072Slinton if (sw) { 1796072Slinton p->sigset |= setrep(sig); 1806072Slinton } else { 1816072Slinton p->sigset &= ~setrep(sig); 1826072Slinton } 1835507Slinton } 1845507Slinton 1855507Slinton /* 1865507Slinton * Don't catch any signals. 1875507Slinton * Particularly useful when letting a process finish uninhibited (i.e. px). 1885507Slinton */ 1895507Slinton 1905507Slinton unsetsigtraces(p) 1915507Slinton PROCESS *p; 1925507Slinton { 1936072Slinton p->sigset = 0; 1945507Slinton } 1955507Slinton 1965507Slinton /* 1975507Slinton * turn off attention to signals not being caught 1985507Slinton */ 1995507Slinton 20045437Sbostic LOCAL void *onintr, *onquit; 2015507Slinton 2025507Slinton LOCAL sigs_off() 2035507Slinton { 20430848Smckusick onintr = signal(SIGINT, SIG_IGN); 20530848Smckusick onquit = signal(SIGQUIT, SIG_IGN); 2065507Slinton } 2075507Slinton 2085507Slinton /* 2095507Slinton * turn back on attention to signals 2105507Slinton */ 2115507Slinton 2125507Slinton LOCAL sigs_on() 2135507Slinton { 21430848Smckusick (void) signal(SIGINT, onintr); 21530848Smckusick (void) signal(SIGQUIT, onquit); 2165507Slinton } 2175507Slinton 2185507Slinton /* 2195507Slinton * get PROCESS information from process's user area 2205507Slinton */ 2215507Slinton 22210768Slinton #if vax 22310768Slinton LOCAL int rloc[] ={ 22410768Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, 22510768Slinton }; 22630848Smckusick #endif 22730848Smckusick #if tahoe 22810768Slinton LOCAL int rloc[] ={ 22930848Smckusick R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, 23030848Smckusick }; 23130848Smckusick #endif 23230848Smckusick #if mc68000 23330848Smckusick LOCAL int rloc[] ={ 23410768Slinton R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, 23510768Slinton }; 23610768Slinton #endif 2375507Slinton 2385507Slinton LOCAL getinfo(p, status) 2395507Slinton register PROCESS *p; 2405507Slinton register int status; 2415507Slinton { 2426072Slinton register int i; 2435507Slinton 2446072Slinton p->signo = (status&0177); 2456072Slinton p->exitval = ((status >> 8)&0377); 2466072Slinton if (p->signo == STOPPED) { 2476072Slinton p->status = p->signo; 2486072Slinton p->signo = p->exitval; 2496072Slinton p->exitval = 0; 2506072Slinton } else { 2516072Slinton p->status = FINISHED; 2526072Slinton return; 2536072Slinton } 25430848Smckusick #if !defined(vax) && !defined(tahoe) 25510768Slinton if (ar0val < 0){ 25610768Slinton ar0val = ptrace(UREAD, p->pid, U_AR0, 0); 25710768Slinton ar0val -= U_PAGE; 25810768Slinton } 25910768Slinton #endif 2606072Slinton for (i = 0; i < NREG; i++) { 2616072Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 2626072Slinton p->oreg[i] = p->reg[i]; 2636072Slinton } 26430848Smckusick #if defined(vax) || defined(tahoe) 2656072Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0); 2666072Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 2676072Slinton p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0); 26830848Smckusick #endif 26930848Smckusick #ifdef vax 27030848Smckusick p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0); 27130848Smckusick #endif 27230848Smckusick #ifdef mc68000 27310768Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(AR6), 0); 27410768Slinton p->ap = p->oap = p->fp; 27510768Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 27610768Slinton p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0); 27710768Slinton #endif 2785507Slinton } 2795507Slinton 2805507Slinton /* 2815507Slinton * set process's user area information from given PROCESS structure 2825507Slinton */ 2835507Slinton 2845507Slinton LOCAL setinfo(p) 2855507Slinton register PROCESS *p; 2865507Slinton { 2876072Slinton register int i; 2886072Slinton register int r; 2895507Slinton 2906072Slinton if (istraced(p)) { 2916072Slinton p->signo = 0; 2926072Slinton } 2936072Slinton for (i = 0; i < NREG; i++) { 2946072Slinton if ((r = p->reg[i]) != p->oreg[i]) { 2956072Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 2965507Slinton } 2976072Slinton } 29830848Smckusick #if vax || tahoe 2996072Slinton if ((r = p->fp) != p->ofp) { 3006072Slinton ptrace(UWRITE, p->pid, regloc(FP), r); 3016072Slinton } 30230848Smckusick #endif 30330848Smckusick #if vax 3046072Slinton if ((r = p->ap) != p->oap) { 3056072Slinton ptrace(UWRITE, p->pid, regloc(AP), r); 3066072Slinton } 30730848Smckusick #endif 30830848Smckusick #if mc68000 30910768Slinton if ((r = p->fp) != p->ofp) { 31010768Slinton ptrace(UWRITE, p->pid, regloc(AR6), r); 31110768Slinton } 31230848Smckusick #endif 31310768Slinton if ((r = p->sp) != p->osp) { 31410768Slinton ptrace(UWRITE, p->pid, regloc(SP), r); 31510768Slinton } 3166072Slinton if ((r = p->pc) != p->opc) { 3176072Slinton ptrace(UWRITE, p->pid, regloc(PC), r); 3186072Slinton } 3195507Slinton } 3205507Slinton 3215507Slinton /* 3225507Slinton * Structure for reading and writing by words, but dealing with bytes. 3235507Slinton */ 3245507Slinton 3255507Slinton typedef union { 3266072Slinton WORD pword; 3276072Slinton BYTE pbyte[sizeof(WORD)]; 3285507Slinton } PWORD; 3295507Slinton 3305507Slinton /* 3315507Slinton * Read (write) from (to) the process' address space. 3325507Slinton * We must deal with ptrace's inability to look anywhere other 3335507Slinton * than at a word boundary. 3345507Slinton */ 3355507Slinton 3365507Slinton LOCAL WORD fetch(); 3375507Slinton LOCAL store(); 3385507Slinton 3395507Slinton pio(p, op, seg, buff, addr, nbytes) 3405507Slinton PROCESS *p; 3415507Slinton PIO_OP op; 3425507Slinton PIO_SEG seg; 3435507Slinton char *buff; 3445507Slinton ADDRESS addr; 3455507Slinton int nbytes; 3465507Slinton { 34730848Smckusick register int i, k; 3486072Slinton register ADDRESS newaddr; 3496072Slinton register char *cp; 3506072Slinton char *bufend; 3516072Slinton PWORD w; 3526072Slinton ADDRESS wordaddr; 3536072Slinton int byteoff; 3545507Slinton 3556072Slinton if (p->status != STOPPED) { 3566072Slinton error("program is not active"); 3576072Slinton } 3586072Slinton cp = buff; 3596072Slinton newaddr = addr; 3606072Slinton wordaddr = (newaddr&WMASK); 3616072Slinton if (wordaddr != newaddr) { 3626072Slinton w.pword = fetch(p, seg, wordaddr); 3636072Slinton for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) { 3646072Slinton if (op == PREAD) { 3656072Slinton *cp++ = w.pbyte[i]; 3666072Slinton } else { 3676072Slinton w.pbyte[i] = *cp++; 3686072Slinton } 3696072Slinton nbytes--; 3705507Slinton } 3716072Slinton if (op == PWRITE) { 3726072Slinton store(p, seg, wordaddr, w.pword); 3735507Slinton } 3746072Slinton newaddr = wordaddr + sizeof(WORD); 3756072Slinton } 3766072Slinton byteoff = (nbytes&(~WMASK)); 3776072Slinton nbytes -= byteoff; 3786072Slinton bufend = cp + nbytes; 3796072Slinton while (cp < bufend) { 3806072Slinton if (op == PREAD) { 38130848Smckusick w.pword = fetch(p, seg, newaddr); 38230848Smckusick for (k = 0; k < sizeof(WORD); k++) { 38330848Smckusick *cp++ = w.pbyte[k]; 38430848Smckusick } 3856072Slinton } else { 38630848Smckusick for (k = 0; k < sizeof(WORD); k++) { 38730848Smckusick w.pbyte[k] = *cp++; 38830848Smckusick } 38930848Smckusick store(p, seg, newaddr, w.pword); 3905507Slinton } 3916072Slinton newaddr += sizeof(WORD); 3926072Slinton } 3936072Slinton if (byteoff > 0) { 3946072Slinton w.pword = fetch(p, seg, newaddr); 3956072Slinton for (i = 0; i < byteoff; i++) { 3966072Slinton if (op == PREAD) { 3976072Slinton *cp++ = w.pbyte[i]; 3986072Slinton } else { 3996072Slinton w.pbyte[i] = *cp++; 4006072Slinton } 4015507Slinton } 4026072Slinton if (op == PWRITE) { 4036072Slinton store(p, seg, newaddr, w.pword); 4046072Slinton } 4056072Slinton } 4065507Slinton } 4075507Slinton 4085507Slinton /* 4095507Slinton * Get a word from a process at the given address. 4105507Slinton * The address is assumed to be on a word boundary. 4115507Slinton * 4125507Slinton * We use a simple cache scheme to avoid redundant references to 4135507Slinton * the instruction space (which is assumed to be pure). In the 4145507Slinton * case of px, the "instruction" space lies between ENDOFF and 4155507Slinton * ENDOFF + objsize. 4165507Slinton * 4175507Slinton * It is necessary to use a write-through scheme so that 4185507Slinton * breakpoints right next to each other don't interfere. 4195507Slinton */ 4205507Slinton 4215507Slinton LOCAL WORD fetch(p, seg, addr) 4225507Slinton PROCESS *p; 4235507Slinton PIO_SEG seg; 4245507Slinton register int addr; 4255507Slinton { 4266072Slinton register CACHEWORD *wp; 4276072Slinton register WORD w; 4285507Slinton 4296072Slinton switch (seg) { 4306072Slinton case TEXTSEG: 43130848Smckusick panic("tried to fetch from px i-space"); 43230848Smckusick /* NOTREACHED */ 43330848Smckusick 43430848Smckusick case DATASEG: 43530848Smckusick if (addr >= ENDOFF && addr < ENDOFF + objsize) { 4366072Slinton wp = &p->word[cachehash(addr)]; 4376072Slinton if (addr == 0 || wp->addr != addr) { 43830848Smckusick w = ptrace(DREAD, p->pid, addr, 0); 4396072Slinton wp->addr = addr; 4406072Slinton wp->val = w; 4416072Slinton } else { 4426072Slinton w = wp->val; 4436072Slinton } 44430848Smckusick } else { 4456072Slinton w = ptrace(DREAD, p->pid, addr, 0); 44630848Smckusick } 4476072Slinton break; 4485507Slinton 4496072Slinton default: 4506072Slinton panic("fetch: bad seg %d", seg); 4516072Slinton /* NOTREACHED */ 4526072Slinton } 4536072Slinton return(w); 4545507Slinton } 4555507Slinton 4565507Slinton /* 4575507Slinton * Put a word into the process' address space at the given address. 4585507Slinton * The address is assumed to be on a word boundary. 4595507Slinton */ 4605507Slinton 4615507Slinton LOCAL store(p, seg, addr, data) 4625507Slinton PROCESS *p; 4635507Slinton PIO_SEG seg; 4645507Slinton int addr; 4655507Slinton WORD data; 4665507Slinton { 4676072Slinton register CACHEWORD *wp; 4685507Slinton 4696072Slinton switch (seg) { 4706072Slinton case TEXTSEG: 4716072Slinton wp = &p->word[cachehash(addr)]; 4726072Slinton wp->addr = addr; 4736072Slinton wp->val = data; 4746072Slinton ptrace(IWRITE, p->pid, addr, data); 4756072Slinton break; 4765507Slinton 4776072Slinton case DATASEG: 47830848Smckusick if (addr >= ENDOFF && addr < ENDOFF + objsize) { 47930848Smckusick wp = &p->word[cachehash(addr)]; 48030848Smckusick wp->addr = addr; 48130848Smckusick wp->val = data; 48230848Smckusick } 4836072Slinton ptrace(DWRITE, p->pid, addr, data); 4846072Slinton break; 4855507Slinton 4866072Slinton default: 4876072Slinton panic("store: bad seg %d", seg); 4886072Slinton /*NOTREACHED*/ 4896072Slinton } 4905507Slinton } 4915507Slinton 4925507Slinton /* 4936072Slinton * Initialize the instruction cache for a process. 4946072Slinton * This is particularly necessary after the program has been remade. 4956072Slinton */ 4966072Slinton 4976072Slinton initcache(process) 4986072Slinton PROCESS *process; 4996072Slinton { 5006072Slinton register int i; 5016072Slinton 5026072Slinton for (i = 0; i < CSIZE; i++) { 5036072Slinton process->word[i].addr = 0; 5046072Slinton } 5056072Slinton } 5066072Slinton 5076072Slinton /* 5085507Slinton * Swap file numbers so as to redirect standard input and output. 5095507Slinton */ 5105507Slinton 5115507Slinton LOCAL fswap(oldfd, newfd) 5125507Slinton int oldfd; 5135507Slinton int newfd; 5145507Slinton { 5156072Slinton if (oldfd != newfd) { 5166072Slinton close(oldfd); 5176072Slinton dup(newfd); 5186072Slinton close(newfd); 5196072Slinton } 5205507Slinton } 52130848Smckusick 52230848Smckusick #ifdef tahoe 52330848Smckusick BOOLEAN didret; 52430848Smckusick 52530848Smckusick void 52630848Smckusick chkret(p, status) 52730848Smckusick PROCESS *p; 52830848Smckusick int status; 52930848Smckusick { 53030848Smckusick if (((status == (SIGILL << 8) | STOPPED) || 53130848Smckusick (status == (SIGTRAP << 8) | STOPPED))) { 53230848Smckusick didret = FALSE; 53330848Smckusick } else { 53430848Smckusick didret = TRUE; 53530848Smckusick } 53630848Smckusick } 53730848Smckusick 53830848Smckusick void 53930848Smckusick doret(p) 54030848Smckusick PROCESS *p; 54130848Smckusick { 54230848Smckusick register count = 0; 54330848Smckusick 54430848Smckusick if (!didret) { 54530848Smckusick do { 54630848Smckusick if (++count > 5) { 54730848Smckusick panic("px would not return to interpreter"); 54830848Smckusick } 54930848Smckusick p->pc = RETLOC; 55030848Smckusick pstep(p); 55130848Smckusick } while(INTFP && p->fp != INTFP); 55230848Smckusick didret = TRUE; 55330848Smckusick } 55430848Smckusick } 55530848Smckusick #endif 556