122510Sdist /* 222510Sdist * Copyright (c) 1980 Regents of the University of California. 322510Sdist * All rights reserved. The Berkeley software License Agreement 422510Sdist * specifies the terms and conditions for redistribution. 522510Sdist */ 610768Slinton 722510Sdist #ifndef lint 8*31082Smckusick static char sccsid[] = "@(#)ptrace.c 5.3 (Berkeley) 05/11/87"; 922510Sdist #endif not lint 105507Slinton 115507Slinton /* 125507Slinton * routines for tracing the execution of a process 135507Slinton * 145507Slinton * The system call "ptrace" does all the work, these 155507Slinton * routines just try to interface easily to it. 165507Slinton */ 175507Slinton 185507Slinton #include "defs.h" 195507Slinton #include <signal.h> 205507Slinton #include <sys/param.h> 2110004Ssam #include <machine/reg.h> 225507Slinton #include "process.h" 235507Slinton #include "object.h" 245507Slinton #include "process.rep" 255507Slinton 266072Slinton # include "pxinfo.h" 275507Slinton 2830848Smckusick #ifdef mc68000 2910768Slinton # define U_PAGE 0x2400 3010768Slinton # define U_AR0 (14*sizeof(int)) 3110768Slinton LOCAL int ar0val = -1; 3210768Slinton #endif 3310768Slinton 345507Slinton /* 355507Slinton * This magic macro enables us to look at the process' registers 365507Slinton * in its user structure. Very gross. 375507Slinton */ 385507Slinton 3930848Smckusick #if defined(vax) || defined(tahoe) 4010768Slinton # define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 4110768Slinton #else 4210768Slinton # define regloc(reg) (ar0val + ( sizeof(int) * (reg) )) 4310768Slinton #endif 445507Slinton 456072Slinton #define WMASK (~(sizeof(WORD) - 1)) 466072Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 475507Slinton 486072Slinton #define ischild(pid) ((pid) == 0) 496072Slinton #define traceme() ptrace(0, 0, 0, 0) 506072Slinton #define setrep(n) (1 << ((n)-1)) 516072Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 525507Slinton 535507Slinton /* 545507Slinton * ptrace options (specified in first argument) 555507Slinton */ 565507Slinton 576072Slinton #define UREAD 3 /* read from process's user structure */ 586072Slinton #define UWRITE 6 /* write to process's user structure */ 596072Slinton #define IREAD 1 /* read from process's instruction space */ 606072Slinton #define IWRITE 4 /* write to process's instruction space */ 616072Slinton #define DREAD 2 /* read from process's data space */ 626072Slinton #define DWRITE 5 /* write to process's data space */ 636072Slinton #define CONT 7 /* continue stopped process */ 646072Slinton #define SSTEP 9 /* continue for approximately one instruction */ 656072Slinton #define PKILL 8 /* terminate the process */ 665507Slinton 675507Slinton /* 685507Slinton * Start up a new process by forking and exec-ing the 695507Slinton * given argument list, returning when the process is loaded 705507Slinton * and ready to execute. The PROCESS information (pointed to 715507Slinton * by the first argument) is appropriately filled. 725507Slinton * 735507Slinton * If the given PROCESS structure is associated with an already running 745507Slinton * process, we terminate it. 755507Slinton */ 765507Slinton 775507Slinton /* VARARGS2 */ 785607Slinton pstart(p, cmd, argv, infile, outfile) 795507Slinton PROCESS *p; 805607Slinton char *cmd; 815507Slinton char **argv; 825507Slinton char *infile; 835507Slinton char *outfile; 845507Slinton { 856072Slinton int status; 866072Slinton FILE *in, *out; 875507Slinton 886072Slinton if (p->pid != 0) { /* child already running? */ 896072Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 906072Slinton } 91*31082Smckusick #ifdef tahoe 9230848Smckusick INTFP = (ADDRESS)0; 93*31082Smckusick #endif tahoe 946072Slinton psigtrace(p, SIGTRAP, TRUE); 956072Slinton if ((p->pid = fork()) == -1) { 966072Slinton panic("can't fork"); 976072Slinton } 986072Slinton if (ischild(p->pid)) { 996072Slinton traceme(); 1006072Slinton if (infile != NIL) { 1016072Slinton if ((in = fopen(infile, "r")) == NIL) { 1026072Slinton printf("can't read %s\n", infile); 1036072Slinton exit(1); 1046072Slinton } 1056072Slinton fswap(0, fileno(in)); 1065507Slinton } 1076072Slinton if (outfile != NIL) { 1086072Slinton if ((out = fopen(outfile, "w")) == NIL) { 1096072Slinton printf("can't write %s\n", outfile); 1106072Slinton exit(1); 1116072Slinton } 1126072Slinton fswap(1, fileno(out)); 1135507Slinton } 1146072Slinton execvp(cmd, argv); 1156072Slinton panic("can't exec %s", argv[0]); 1166072Slinton } 1176072Slinton pwait(p->pid, &status); 1186072Slinton getinfo(p, status); 1195507Slinton } 1205507Slinton 1215507Slinton /* 1225507Slinton * Continue a stopped process. The argument points to a PROCESS structure. 1235507Slinton * Before the process is restarted it's user area is modified according to 1245507Slinton * the values in the structure. When this routine finishes, 1255507Slinton * the structure has the new values from the process's user area. 1265507Slinton * 1275507Slinton * Pcont terminates when the process stops with a signal pending that 1285507Slinton * is being traced (via psigtrace), or when the process terminates. 1295507Slinton */ 1305507Slinton 1315507Slinton pcont(p) 1325507Slinton PROCESS *p; 1335507Slinton { 1346072Slinton int status; 1355507Slinton 1366072Slinton if (p->pid == 0) { 1376072Slinton error("program not active"); 1386072Slinton } 1396072Slinton do { 1406072Slinton setinfo(p); 1416072Slinton sigs_off(); 1426072Slinton if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) { 1436072Slinton panic("can't continue process"); 1445507Slinton } 1456072Slinton pwait(p->pid, &status); 1466072Slinton sigs_on(); 1476072Slinton getinfo(p, status); 1486072Slinton } while (p->status == STOPPED && !istraced(p)); 1495507Slinton } 1505507Slinton 1515507Slinton /* 1525507Slinton * single step as best ptrace can 1535507Slinton */ 1545507Slinton 1555507Slinton pstep(p) 1565507Slinton PROCESS *p; 1575507Slinton { 1586072Slinton int status; 1595507Slinton 1606072Slinton setinfo(p); 1616072Slinton sigs_off(); 1626072Slinton ptrace(SSTEP, p->pid, p->pc, p->signo); 1636072Slinton pwait(p->pid, &status); 1646072Slinton sigs_on(); 1656072Slinton getinfo(p, status); 1665507Slinton } 1675507Slinton 1685507Slinton /* 1695507Slinton * Return from execution when the given signal is pending. 1705507Slinton */ 1715507Slinton 1725507Slinton psigtrace(p, sig, sw) 1735507Slinton PROCESS *p; 1745507Slinton int sig; 1755507Slinton int sw; 1765507Slinton { 1776072Slinton if (sw) { 1786072Slinton p->sigset |= setrep(sig); 1796072Slinton } else { 1806072Slinton p->sigset &= ~setrep(sig); 1816072Slinton } 1825507Slinton } 1835507Slinton 1845507Slinton /* 1855507Slinton * Don't catch any signals. 1865507Slinton * Particularly useful when letting a process finish uninhibited (i.e. px). 1875507Slinton */ 1885507Slinton 1895507Slinton unsetsigtraces(p) 1905507Slinton PROCESS *p; 1915507Slinton { 1926072Slinton p->sigset = 0; 1935507Slinton } 1945507Slinton 1955507Slinton /* 1965507Slinton * turn off attention to signals not being caught 1975507Slinton */ 1985507Slinton 1995507Slinton typedef int INTFUNC(); 2005507Slinton 20130848Smckusick LOCAL INTFUNC *onintr, *onquit; 2025507Slinton 2035507Slinton LOCAL sigs_off() 2045507Slinton { 20530848Smckusick onintr = signal(SIGINT, SIG_IGN); 20630848Smckusick onquit = signal(SIGQUIT, SIG_IGN); 2075507Slinton } 2085507Slinton 2095507Slinton /* 2105507Slinton * turn back on attention to signals 2115507Slinton */ 2125507Slinton 2135507Slinton LOCAL sigs_on() 2145507Slinton { 21530848Smckusick (void) signal(SIGINT, onintr); 21630848Smckusick (void) signal(SIGQUIT, onquit); 2175507Slinton } 2185507Slinton 2195507Slinton /* 2205507Slinton * get PROCESS information from process's user area 2215507Slinton */ 2225507Slinton 22310768Slinton #if vax 22410768Slinton LOCAL int rloc[] ={ 22510768Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, 22610768Slinton }; 22730848Smckusick #endif 22830848Smckusick #if tahoe 22910768Slinton LOCAL int rloc[] ={ 23030848Smckusick R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, 23130848Smckusick }; 23230848Smckusick #endif 23330848Smckusick #if mc68000 23430848Smckusick LOCAL int rloc[] ={ 23510768Slinton R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, 23610768Slinton }; 23710768Slinton #endif 2385507Slinton 2395507Slinton LOCAL getinfo(p, status) 2405507Slinton register PROCESS *p; 2415507Slinton register int status; 2425507Slinton { 2436072Slinton register int i; 2445507Slinton 2456072Slinton p->signo = (status&0177); 2466072Slinton p->exitval = ((status >> 8)&0377); 2476072Slinton if (p->signo == STOPPED) { 2486072Slinton p->status = p->signo; 2496072Slinton p->signo = p->exitval; 2506072Slinton p->exitval = 0; 2516072Slinton } else { 2526072Slinton p->status = FINISHED; 2536072Slinton return; 2546072Slinton } 25530848Smckusick #if !defined(vax) && !defined(tahoe) 25610768Slinton if (ar0val < 0){ 25710768Slinton ar0val = ptrace(UREAD, p->pid, U_AR0, 0); 25810768Slinton ar0val -= U_PAGE; 25910768Slinton } 26010768Slinton #endif 2616072Slinton for (i = 0; i < NREG; i++) { 2626072Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 2636072Slinton p->oreg[i] = p->reg[i]; 2646072Slinton } 26530848Smckusick #if defined(vax) || defined(tahoe) 2666072Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0); 2676072Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 2686072Slinton p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0); 26930848Smckusick #endif 27030848Smckusick #ifdef vax 27130848Smckusick p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0); 27230848Smckusick #endif 27330848Smckusick #ifdef mc68000 27410768Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(AR6), 0); 27510768Slinton p->ap = p->oap = p->fp; 27610768Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 27710768Slinton p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0); 27810768Slinton #endif 2795507Slinton } 2805507Slinton 2815507Slinton /* 2825507Slinton * set process's user area information from given PROCESS structure 2835507Slinton */ 2845507Slinton 2855507Slinton LOCAL setinfo(p) 2865507Slinton register PROCESS *p; 2875507Slinton { 2886072Slinton register int i; 2896072Slinton register int r; 2905507Slinton 2916072Slinton if (istraced(p)) { 2926072Slinton p->signo = 0; 2936072Slinton } 2946072Slinton for (i = 0; i < NREG; i++) { 2956072Slinton if ((r = p->reg[i]) != p->oreg[i]) { 2966072Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 2975507Slinton } 2986072Slinton } 29930848Smckusick #if vax || tahoe 3006072Slinton if ((r = p->fp) != p->ofp) { 3016072Slinton ptrace(UWRITE, p->pid, regloc(FP), r); 3026072Slinton } 30330848Smckusick #endif 30430848Smckusick #if vax 3056072Slinton if ((r = p->ap) != p->oap) { 3066072Slinton ptrace(UWRITE, p->pid, regloc(AP), r); 3076072Slinton } 30830848Smckusick #endif 30930848Smckusick #if mc68000 31010768Slinton if ((r = p->fp) != p->ofp) { 31110768Slinton ptrace(UWRITE, p->pid, regloc(AR6), r); 31210768Slinton } 31330848Smckusick #endif 31410768Slinton if ((r = p->sp) != p->osp) { 31510768Slinton ptrace(UWRITE, p->pid, regloc(SP), r); 31610768Slinton } 3176072Slinton if ((r = p->pc) != p->opc) { 3186072Slinton ptrace(UWRITE, p->pid, regloc(PC), r); 3196072Slinton } 3205507Slinton } 3215507Slinton 3225507Slinton /* 3235507Slinton * Structure for reading and writing by words, but dealing with bytes. 3245507Slinton */ 3255507Slinton 3265507Slinton typedef union { 3276072Slinton WORD pword; 3286072Slinton BYTE pbyte[sizeof(WORD)]; 3295507Slinton } PWORD; 3305507Slinton 3315507Slinton /* 3325507Slinton * Read (write) from (to) the process' address space. 3335507Slinton * We must deal with ptrace's inability to look anywhere other 3345507Slinton * than at a word boundary. 3355507Slinton */ 3365507Slinton 3375507Slinton LOCAL WORD fetch(); 3385507Slinton LOCAL store(); 3395507Slinton 3405507Slinton pio(p, op, seg, buff, addr, nbytes) 3415507Slinton PROCESS *p; 3425507Slinton PIO_OP op; 3435507Slinton PIO_SEG seg; 3445507Slinton char *buff; 3455507Slinton ADDRESS addr; 3465507Slinton int nbytes; 3475507Slinton { 34830848Smckusick register int i, k; 3496072Slinton register ADDRESS newaddr; 3506072Slinton register char *cp; 3516072Slinton char *bufend; 3526072Slinton PWORD w; 3536072Slinton ADDRESS wordaddr; 3546072Slinton int byteoff; 3555507Slinton 3566072Slinton if (p->status != STOPPED) { 3576072Slinton error("program is not active"); 3586072Slinton } 3596072Slinton cp = buff; 3606072Slinton newaddr = addr; 3616072Slinton wordaddr = (newaddr&WMASK); 3626072Slinton if (wordaddr != newaddr) { 3636072Slinton w.pword = fetch(p, seg, wordaddr); 3646072Slinton for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) { 3656072Slinton if (op == PREAD) { 3666072Slinton *cp++ = w.pbyte[i]; 3676072Slinton } else { 3686072Slinton w.pbyte[i] = *cp++; 3696072Slinton } 3706072Slinton nbytes--; 3715507Slinton } 3726072Slinton if (op == PWRITE) { 3736072Slinton store(p, seg, wordaddr, w.pword); 3745507Slinton } 3756072Slinton newaddr = wordaddr + sizeof(WORD); 3766072Slinton } 3776072Slinton byteoff = (nbytes&(~WMASK)); 3786072Slinton nbytes -= byteoff; 3796072Slinton bufend = cp + nbytes; 3806072Slinton while (cp < bufend) { 3816072Slinton if (op == PREAD) { 38230848Smckusick w.pword = fetch(p, seg, newaddr); 38330848Smckusick for (k = 0; k < sizeof(WORD); k++) { 38430848Smckusick *cp++ = w.pbyte[k]; 38530848Smckusick } 3866072Slinton } else { 38730848Smckusick for (k = 0; k < sizeof(WORD); k++) { 38830848Smckusick w.pbyte[k] = *cp++; 38930848Smckusick } 39030848Smckusick store(p, seg, newaddr, w.pword); 3915507Slinton } 3926072Slinton newaddr += sizeof(WORD); 3936072Slinton } 3946072Slinton if (byteoff > 0) { 3956072Slinton w.pword = fetch(p, seg, newaddr); 3966072Slinton for (i = 0; i < byteoff; i++) { 3976072Slinton if (op == PREAD) { 3986072Slinton *cp++ = w.pbyte[i]; 3996072Slinton } else { 4006072Slinton w.pbyte[i] = *cp++; 4016072Slinton } 4025507Slinton } 4036072Slinton if (op == PWRITE) { 4046072Slinton store(p, seg, newaddr, w.pword); 4056072Slinton } 4066072Slinton } 4075507Slinton } 4085507Slinton 4095507Slinton /* 4105507Slinton * Get a word from a process at the given address. 4115507Slinton * The address is assumed to be on a word boundary. 4125507Slinton * 4135507Slinton * We use a simple cache scheme to avoid redundant references to 4145507Slinton * the instruction space (which is assumed to be pure). In the 4155507Slinton * case of px, the "instruction" space lies between ENDOFF and 4165507Slinton * ENDOFF + objsize. 4175507Slinton * 4185507Slinton * It is necessary to use a write-through scheme so that 4195507Slinton * breakpoints right next to each other don't interfere. 4205507Slinton */ 4215507Slinton 4225507Slinton LOCAL WORD fetch(p, seg, addr) 4235507Slinton PROCESS *p; 4245507Slinton PIO_SEG seg; 4255507Slinton register int addr; 4265507Slinton { 4276072Slinton register CACHEWORD *wp; 4286072Slinton register WORD w; 4295507Slinton 4306072Slinton switch (seg) { 4316072Slinton case TEXTSEG: 43230848Smckusick panic("tried to fetch from px i-space"); 43330848Smckusick /* NOTREACHED */ 43430848Smckusick 43530848Smckusick case DATASEG: 43630848Smckusick if (addr >= ENDOFF && addr < ENDOFF + objsize) { 4376072Slinton wp = &p->word[cachehash(addr)]; 4386072Slinton if (addr == 0 || wp->addr != addr) { 43930848Smckusick w = ptrace(DREAD, p->pid, addr, 0); 4406072Slinton wp->addr = addr; 4416072Slinton wp->val = w; 4426072Slinton } else { 4436072Slinton w = wp->val; 4446072Slinton } 44530848Smckusick } else { 4466072Slinton w = ptrace(DREAD, p->pid, addr, 0); 44730848Smckusick } 4486072Slinton break; 4495507Slinton 4506072Slinton default: 4516072Slinton panic("fetch: bad seg %d", seg); 4526072Slinton /* NOTREACHED */ 4536072Slinton } 4546072Slinton return(w); 4555507Slinton } 4565507Slinton 4575507Slinton /* 4585507Slinton * Put a word into the process' address space at the given address. 4595507Slinton * The address is assumed to be on a word boundary. 4605507Slinton */ 4615507Slinton 4625507Slinton LOCAL store(p, seg, addr, data) 4635507Slinton PROCESS *p; 4645507Slinton PIO_SEG seg; 4655507Slinton int addr; 4665507Slinton WORD data; 4675507Slinton { 4686072Slinton register CACHEWORD *wp; 4695507Slinton 4706072Slinton switch (seg) { 4716072Slinton case TEXTSEG: 4726072Slinton wp = &p->word[cachehash(addr)]; 4736072Slinton wp->addr = addr; 4746072Slinton wp->val = data; 4756072Slinton ptrace(IWRITE, p->pid, addr, data); 4766072Slinton break; 4775507Slinton 4786072Slinton case DATASEG: 47930848Smckusick if (addr >= ENDOFF && addr < ENDOFF + objsize) { 48030848Smckusick wp = &p->word[cachehash(addr)]; 48130848Smckusick wp->addr = addr; 48230848Smckusick wp->val = data; 48330848Smckusick } 4846072Slinton ptrace(DWRITE, p->pid, addr, data); 4856072Slinton break; 4865507Slinton 4876072Slinton default: 4886072Slinton panic("store: bad seg %d", seg); 4896072Slinton /*NOTREACHED*/ 4906072Slinton } 4915507Slinton } 4925507Slinton 4935507Slinton /* 4946072Slinton * Initialize the instruction cache for a process. 4956072Slinton * This is particularly necessary after the program has been remade. 4966072Slinton */ 4976072Slinton 4986072Slinton initcache(process) 4996072Slinton PROCESS *process; 5006072Slinton { 5016072Slinton register int i; 5026072Slinton 5036072Slinton for (i = 0; i < CSIZE; i++) { 5046072Slinton process->word[i].addr = 0; 5056072Slinton } 5066072Slinton } 5076072Slinton 5086072Slinton /* 5095507Slinton * Swap file numbers so as to redirect standard input and output. 5105507Slinton */ 5115507Slinton 5125507Slinton LOCAL fswap(oldfd, newfd) 5135507Slinton int oldfd; 5145507Slinton int newfd; 5155507Slinton { 5166072Slinton if (oldfd != newfd) { 5176072Slinton close(oldfd); 5186072Slinton dup(newfd); 5196072Slinton close(newfd); 5206072Slinton } 5215507Slinton } 52230848Smckusick 52330848Smckusick #ifdef tahoe 52430848Smckusick BOOLEAN didret; 52530848Smckusick 52630848Smckusick void 52730848Smckusick chkret(p, status) 52830848Smckusick PROCESS *p; 52930848Smckusick int status; 53030848Smckusick { 53130848Smckusick if (((status == (SIGILL << 8) | STOPPED) || 53230848Smckusick (status == (SIGTRAP << 8) | STOPPED))) { 53330848Smckusick didret = FALSE; 53430848Smckusick } else { 53530848Smckusick didret = TRUE; 53630848Smckusick } 53730848Smckusick } 53830848Smckusick 53930848Smckusick void 54030848Smckusick doret(p) 54130848Smckusick PROCESS *p; 54230848Smckusick { 54330848Smckusick register count = 0; 54430848Smckusick 54530848Smckusick if (!didret) { 54630848Smckusick do { 54730848Smckusick if (++count > 5) { 54830848Smckusick panic("px would not return to interpreter"); 54930848Smckusick } 55030848Smckusick p->pc = RETLOC; 55130848Smckusick pstep(p); 55230848Smckusick } while(INTFP && p->fp != INTFP); 55330848Smckusick didret = TRUE; 55430848Smckusick } 55530848Smckusick } 55630848Smckusick #endif 557