15507Slinton /* Copyright (c) 1982 Regents of the University of California */ 25507Slinton 3*5607Slinton static char sccsid[] = "@(#)ptrace.c 1.2 01/23/82"; 45507Slinton 55507Slinton /* 65507Slinton * routines for tracing the execution of a process 75507Slinton * 85507Slinton * The system call "ptrace" does all the work, these 95507Slinton * routines just try to interface easily to it. 105507Slinton */ 115507Slinton 125507Slinton #include "defs.h" 135507Slinton #include <signal.h> 145507Slinton #include <sys/param.h> 155507Slinton #include <sys/reg.h> 165507Slinton #include "process.h" 175507Slinton #include "object.h" 185507Slinton #include "process.rep" 195507Slinton 205507Slinton # if (isvaxpx) 215507Slinton # include "pxinfo.h" 225507Slinton # endif 235507Slinton 245507Slinton /* 255507Slinton * This magic macro enables us to look at the process' registers 265507Slinton * in its user structure. Very gross. 275507Slinton */ 285507Slinton 295507Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 305507Slinton 315507Slinton #define WMASK (~(sizeof(WORD) - 1)) 325507Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 335507Slinton 345507Slinton #define FIRSTSIG SIGINT 355507Slinton #define LASTSIG SIGQUIT 365507Slinton #define ischild(pid) ((pid) == 0) 375507Slinton #define traceme() ptrace(0, 0, 0, 0) 385507Slinton #define setrep(n) (1 << ((n)-1)) 395507Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 405507Slinton 415507Slinton /* 425507Slinton * ptrace options (specified in first argument) 435507Slinton */ 445507Slinton 455507Slinton #define UREAD 3 /* read from process's user structure */ 465507Slinton #define UWRITE 6 /* write to process's user structure */ 475507Slinton #define IREAD 1 /* read from process's instruction space */ 485507Slinton #define IWRITE 4 /* write to process's instruction space */ 495507Slinton #define DREAD 2 /* read from process's data space */ 505507Slinton #define DWRITE 5 /* write to process's data space */ 515507Slinton #define CONT 7 /* continue stopped process */ 525507Slinton #define SSTEP 9 /* continue for approximately one instruction */ 535507Slinton #define PKILL 8 /* terminate the process */ 545507Slinton 555507Slinton /* 565507Slinton * Start up a new process by forking and exec-ing the 575507Slinton * given argument list, returning when the process is loaded 585507Slinton * and ready to execute. The PROCESS information (pointed to 595507Slinton * by the first argument) is appropriately filled. 605507Slinton * 615507Slinton * If the given PROCESS structure is associated with an already running 625507Slinton * process, we terminate it. 635507Slinton */ 645507Slinton 655507Slinton /* VARARGS2 */ 66*5607Slinton pstart(p, cmd, argv, infile, outfile) 675507Slinton PROCESS *p; 68*5607Slinton char *cmd; 695507Slinton char **argv; 705507Slinton char *infile; 715507Slinton char *outfile; 725507Slinton { 735507Slinton int status; 745507Slinton FILE *in, *out; 755507Slinton 765507Slinton if (p->pid != 0) { /* child already running? */ 775507Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 785507Slinton } 795507Slinton psigtrace(p, SIGTRAP, TRUE); 805507Slinton if ((p->pid = fork()) == -1) { 815507Slinton panic("can't fork"); 825507Slinton } 835507Slinton if (ischild(p->pid)) { 845507Slinton traceme(); 855507Slinton if (infile != NIL) { 865507Slinton if ((in = fopen(infile, "r")) == NIL) { 875507Slinton printf("can't read %s\n", infile); 885507Slinton exit(1); 895507Slinton } 905507Slinton fswap(0, fileno(in)); 915507Slinton } 925507Slinton if (outfile != NIL) { 935507Slinton if ((out = fopen(outfile, "w")) == NIL) { 945507Slinton printf("can't write %s\n", outfile); 955507Slinton exit(1); 965507Slinton } 975507Slinton fswap(1, fileno(out)); 985507Slinton } 99*5607Slinton execvp(cmd, argv); 1005507Slinton panic("can't exec %s", argv[0]); 1015507Slinton } 1025507Slinton pwait(p->pid, &status); 1035507Slinton getinfo(p, status); 1045507Slinton } 1055507Slinton 1065507Slinton /* 1075507Slinton * Continue a stopped process. The argument points to a PROCESS structure. 1085507Slinton * Before the process is restarted it's user area is modified according to 1095507Slinton * the values in the structure. When this routine finishes, 1105507Slinton * the structure has the new values from the process's user area. 1115507Slinton * 1125507Slinton * Pcont terminates when the process stops with a signal pending that 1135507Slinton * is being traced (via psigtrace), or when the process terminates. 1145507Slinton */ 1155507Slinton 1165507Slinton pcont(p) 1175507Slinton PROCESS *p; 1185507Slinton { 1195507Slinton int status; 1205507Slinton 1215507Slinton if (p->pid == 0) { 1225507Slinton error("program not active"); 1235507Slinton } 1245507Slinton do { 1255507Slinton setinfo(p); 1265507Slinton sigs_off(); 1275507Slinton if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) { 1285507Slinton panic("can't continue process"); 1295507Slinton } 1305507Slinton pwait(p->pid, &status); 1315507Slinton sigs_on(); 1325507Slinton getinfo(p, status); 1335507Slinton } while (p->status == STOPPED && !istraced(p)); 1345507Slinton } 1355507Slinton 1365507Slinton /* 1375507Slinton * single step as best ptrace can 1385507Slinton */ 1395507Slinton 1405507Slinton pstep(p) 1415507Slinton PROCESS *p; 1425507Slinton { 1435507Slinton int status; 1445507Slinton 1455507Slinton setinfo(p); 1465507Slinton sigs_off(); 1475507Slinton ptrace(SSTEP, p->pid, p->pc, p->signo); 1485507Slinton pwait(p->pid, &status); 1495507Slinton sigs_on(); 1505507Slinton getinfo(p, status); 1515507Slinton } 1525507Slinton 1535507Slinton /* 1545507Slinton * Return from execution when the given signal is pending. 1555507Slinton */ 1565507Slinton 1575507Slinton psigtrace(p, sig, sw) 1585507Slinton PROCESS *p; 1595507Slinton int sig; 1605507Slinton int sw; 1615507Slinton { 1625507Slinton if (sw) { 1635507Slinton p->sigset |= setrep(sig); 1645507Slinton } else { 1655507Slinton p->sigset &= ~setrep(sig); 1665507Slinton } 1675507Slinton } 1685507Slinton 1695507Slinton /* 1705507Slinton * Don't catch any signals. 1715507Slinton * Particularly useful when letting a process finish uninhibited (i.e. px). 1725507Slinton */ 1735507Slinton 1745507Slinton unsetsigtraces(p) 1755507Slinton PROCESS *p; 1765507Slinton { 1775507Slinton p->sigset = 0; 1785507Slinton } 1795507Slinton 1805507Slinton /* 1815507Slinton * turn off attention to signals not being caught 1825507Slinton */ 1835507Slinton 1845507Slinton typedef int INTFUNC(); 1855507Slinton 1865507Slinton LOCAL INTFUNC *sigfunc[NSIG]; 1875507Slinton 1885507Slinton LOCAL sigs_off() 1895507Slinton { 1905507Slinton register int i; 1915507Slinton 1925507Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 1935507Slinton if (i != SIGKILL) { 1945507Slinton sigfunc[i] = signal(i, SIG_IGN); 1955507Slinton } 1965507Slinton } 1975507Slinton } 1985507Slinton 1995507Slinton /* 2005507Slinton * turn back on attention to signals 2015507Slinton */ 2025507Slinton 2035507Slinton LOCAL sigs_on() 2045507Slinton { 2055507Slinton register int i; 2065507Slinton 2075507Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 2085507Slinton if (i != SIGKILL) { 2095507Slinton signal(i, sigfunc[i]); 2105507Slinton } 2115507Slinton } 2125507Slinton } 2135507Slinton 2145507Slinton /* 2155507Slinton * get PROCESS information from process's user area 2165507Slinton */ 2175507Slinton 2185507Slinton LOCAL int rloc[] ={ 2195507Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, 2205507Slinton }; 2215507Slinton 2225507Slinton LOCAL getinfo(p, status) 2235507Slinton register PROCESS *p; 2245507Slinton register int status; 2255507Slinton { 2265507Slinton register int i; 2275507Slinton 2285507Slinton p->signo = (status&0177); 2295507Slinton p->exitval = ((status >> 8)&0377); 2305507Slinton if (p->signo == STOPPED) { 2315507Slinton p->status = p->signo; 2325507Slinton p->signo = p->exitval; 2335507Slinton p->exitval = 0; 2345507Slinton } else { 2355507Slinton p->status = FINISHED; 2365507Slinton return; 2375507Slinton } 2385507Slinton for (i = 0; i < NREG; i++) { 2395507Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 2405507Slinton p->oreg[i] = p->reg[i]; 2415507Slinton } 2425507Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0); 2435507Slinton p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0); 2445507Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 2455507Slinton p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0); 2465507Slinton } 2475507Slinton 2485507Slinton /* 2495507Slinton * set process's user area information from given PROCESS structure 2505507Slinton */ 2515507Slinton 2525507Slinton LOCAL setinfo(p) 2535507Slinton register PROCESS *p; 2545507Slinton { 2555507Slinton register int i; 2565507Slinton register int r; 2575507Slinton 2585507Slinton if (istraced(p)) { 2595507Slinton p->signo = 0; 2605507Slinton } 2615507Slinton for (i = 0; i < NREG; i++) { 2625507Slinton if ((r = p->reg[i]) != p->oreg[i]) { 2635507Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 2645507Slinton } 2655507Slinton } 2665507Slinton if ((r = p->fp) != p->ofp) { 2675507Slinton ptrace(UWRITE, p->pid, regloc(FP), r); 2685507Slinton } 2695507Slinton if ((r = p->sp) != p->osp) { 2705507Slinton ptrace(UWRITE, p->pid, regloc(SP), r); 2715507Slinton } 2725507Slinton if ((r = p->ap) != p->oap) { 2735507Slinton ptrace(UWRITE, p->pid, regloc(AP), r); 2745507Slinton } 2755507Slinton if ((r = p->pc) != p->opc) { 2765507Slinton ptrace(UWRITE, p->pid, regloc(PC), r); 2775507Slinton } 2785507Slinton } 2795507Slinton 2805507Slinton /* 2815507Slinton * Structure for reading and writing by words, but dealing with bytes. 2825507Slinton */ 2835507Slinton 2845507Slinton typedef union { 2855507Slinton WORD pword; 2865507Slinton BYTE pbyte[sizeof(WORD)]; 2875507Slinton } PWORD; 2885507Slinton 2895507Slinton /* 2905507Slinton * Read (write) from (to) the process' address space. 2915507Slinton * We must deal with ptrace's inability to look anywhere other 2925507Slinton * than at a word boundary. 2935507Slinton */ 2945507Slinton 2955507Slinton LOCAL WORD fetch(); 2965507Slinton LOCAL store(); 2975507Slinton 2985507Slinton pio(p, op, seg, buff, addr, nbytes) 2995507Slinton PROCESS *p; 3005507Slinton PIO_OP op; 3015507Slinton PIO_SEG seg; 3025507Slinton char *buff; 3035507Slinton ADDRESS addr; 3045507Slinton int nbytes; 3055507Slinton { 3065507Slinton register int i; 3075507Slinton register ADDRESS newaddr; 3085507Slinton register char *cp; 3095507Slinton char *bufend; 3105507Slinton PWORD w; 3115507Slinton ADDRESS wordaddr; 3125507Slinton int byteoff; 3135507Slinton 3145507Slinton if (p->status != STOPPED) { 3155507Slinton error("program is not active"); 3165507Slinton } 3175507Slinton cp = buff; 3185507Slinton newaddr = addr; 3195507Slinton wordaddr = (newaddr&WMASK); 3205507Slinton if (wordaddr != newaddr) { 3215507Slinton w.pword = fetch(p, seg, wordaddr); 3225507Slinton for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) { 3235507Slinton if (op == PREAD) { 3245507Slinton *cp++ = w.pbyte[i]; 3255507Slinton } else { 3265507Slinton w.pbyte[i] = *cp++; 3275507Slinton } 3285507Slinton nbytes--; 3295507Slinton } 3305507Slinton if (op == PWRITE) { 3315507Slinton store(p, seg, wordaddr, w.pword); 3325507Slinton } 3335507Slinton newaddr = wordaddr + sizeof(WORD); 3345507Slinton } 3355507Slinton byteoff = (nbytes&(~WMASK)); 3365507Slinton nbytes -= byteoff; 3375507Slinton bufend = cp + nbytes; 3385507Slinton while (cp < bufend) { 3395507Slinton if (op == PREAD) { 3405507Slinton *((WORD *) cp) = fetch(p, seg, newaddr); 3415507Slinton } else { 3425507Slinton store(p, seg, newaddr, *((WORD *) cp)); 3435507Slinton } 3445507Slinton cp += sizeof(WORD); 3455507Slinton newaddr += sizeof(WORD); 3465507Slinton } 3475507Slinton if (byteoff > 0) { 3485507Slinton w.pword = fetch(p, seg, newaddr); 3495507Slinton for (i = 0; i < byteoff; i++) { 3505507Slinton if (op == PREAD) { 3515507Slinton *cp++ = w.pbyte[i]; 3525507Slinton } else { 3535507Slinton w.pbyte[i] = *cp++; 3545507Slinton } 3555507Slinton } 3565507Slinton if (op == PWRITE) { 3575507Slinton store(p, seg, newaddr, w.pword); 3585507Slinton } 3595507Slinton } 3605507Slinton } 3615507Slinton 3625507Slinton /* 3635507Slinton * Get a word from a process at the given address. 3645507Slinton * The address is assumed to be on a word boundary. 3655507Slinton * 3665507Slinton * We use a simple cache scheme to avoid redundant references to 3675507Slinton * the instruction space (which is assumed to be pure). In the 3685507Slinton * case of px, the "instruction" space lies between ENDOFF and 3695507Slinton * ENDOFF + objsize. 3705507Slinton * 3715507Slinton * It is necessary to use a write-through scheme so that 3725507Slinton * breakpoints right next to each other don't interfere. 3735507Slinton */ 3745507Slinton 3755507Slinton LOCAL WORD fetch(p, seg, addr) 3765507Slinton PROCESS *p; 3775507Slinton PIO_SEG seg; 3785507Slinton register int addr; 3795507Slinton { 3805507Slinton register CACHEWORD *wp; 3815507Slinton register WORD w; 3825507Slinton 3835507Slinton switch (seg) { 3845507Slinton case TEXTSEG: 3855507Slinton # if (isvaxpx) 3865507Slinton panic("tried to fetch from px i-space"); 3875507Slinton /* NOTREACHED */ 3885507Slinton # else 3895507Slinton wp = &p->word[cachehash(addr)]; 3905507Slinton if (addr == 0 || wp->addr != addr) { 3915507Slinton w = ptrace(IREAD, p->pid, addr, 0); 3925507Slinton wp->addr = addr; 3935507Slinton wp->val = w; 3945507Slinton } else { 3955507Slinton w = wp->val; 3965507Slinton } 3975507Slinton break; 3985507Slinton # endif 3995507Slinton 4005507Slinton case DATASEG: 4015507Slinton # if (isvaxpx) 4025507Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 4035507Slinton wp = &p->word[cachehash(addr)]; 4045507Slinton if (addr == 0 || wp->addr != addr) { 4055507Slinton w = ptrace(DREAD, p->pid, addr, 0); 4065507Slinton wp->addr = addr; 4075507Slinton wp->val = w; 4085507Slinton } else { 4095507Slinton w = wp->val; 4105507Slinton } 4115507Slinton } else { 4125507Slinton w = ptrace(DREAD, p->pid, addr, 0); 4135507Slinton } 4145507Slinton # else 4155507Slinton w = ptrace(DREAD, p->pid, addr, 0); 4165507Slinton # endif 4175507Slinton break; 4185507Slinton 4195507Slinton default: 4205507Slinton panic("fetch: bad seg %d", seg); 4215507Slinton /* NOTREACHED */ 4225507Slinton } 4235507Slinton return(w); 4245507Slinton } 4255507Slinton 4265507Slinton /* 4275507Slinton * Put a word into the process' address space at the given address. 4285507Slinton * The address is assumed to be on a word boundary. 4295507Slinton */ 4305507Slinton 4315507Slinton LOCAL store(p, seg, addr, data) 4325507Slinton PROCESS *p; 4335507Slinton PIO_SEG seg; 4345507Slinton int addr; 4355507Slinton WORD data; 4365507Slinton { 4375507Slinton register CACHEWORD *wp; 4385507Slinton 4395507Slinton switch (seg) { 4405507Slinton case TEXTSEG: 4415507Slinton wp = &p->word[cachehash(addr)]; 4425507Slinton wp->addr = addr; 4435507Slinton wp->val = data; 4445507Slinton ptrace(IWRITE, p->pid, addr, data); 4455507Slinton break; 4465507Slinton 4475507Slinton case DATASEG: 4485507Slinton # if (isvaxpx) 4495507Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 4505507Slinton wp = &p->word[cachehash(addr)]; 4515507Slinton wp->addr = addr; 4525507Slinton wp->val = data; 4535507Slinton } 4545507Slinton # endif 4555507Slinton ptrace(DWRITE, p->pid, addr, data); 4565507Slinton break; 4575507Slinton 4585507Slinton default: 4595507Slinton panic("store: bad seg %d", seg); 4605507Slinton /*NOTREACHED*/ 4615507Slinton } 4625507Slinton } 4635507Slinton 4645507Slinton /* 4655507Slinton * Swap file numbers so as to redirect standard input and output. 4665507Slinton */ 4675507Slinton 4685507Slinton LOCAL fswap(oldfd, newfd) 4695507Slinton int oldfd; 4705507Slinton int newfd; 4715507Slinton { 4725507Slinton if (oldfd != newfd) { 4735507Slinton close(oldfd); 4745507Slinton dup(newfd); 4755507Slinton close(newfd); 4765507Slinton } 4775507Slinton } 478