15507Slinton /* Copyright (c) 1982 Regents of the University of California */ 25507Slinton 3*10004Ssam static char sccsid[] = "@(#)ptrace.c 1.4 12/29/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> 15*10004Ssam #include <machine/reg.h> 165507Slinton #include "process.h" 175507Slinton #include "object.h" 185507Slinton #include "process.rep" 195507Slinton 206072Slinton # if (isvaxpx) 216072Slinton # include "pxinfo.h" 226072Slinton # endif 235507Slinton 245507Slinton /* 255507Slinton * This magic macro enables us to look at the process' registers 265507Slinton * in its user structure. Very gross. 275507Slinton */ 285507Slinton 296072Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 305507Slinton 316072Slinton #define WMASK (~(sizeof(WORD) - 1)) 326072Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 335507Slinton 346072Slinton #define FIRSTSIG SIGINT 356072Slinton #define LASTSIG SIGQUIT 366072Slinton #define ischild(pid) ((pid) == 0) 376072Slinton #define traceme() ptrace(0, 0, 0, 0) 386072Slinton #define setrep(n) (1 << ((n)-1)) 396072Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 405507Slinton 415507Slinton /* 425507Slinton * ptrace options (specified in first argument) 435507Slinton */ 445507Slinton 456072Slinton #define UREAD 3 /* read from process's user structure */ 466072Slinton #define UWRITE 6 /* write to process's user structure */ 476072Slinton #define IREAD 1 /* read from process's instruction space */ 486072Slinton #define IWRITE 4 /* write to process's instruction space */ 496072Slinton #define DREAD 2 /* read from process's data space */ 506072Slinton #define DWRITE 5 /* write to process's data space */ 516072Slinton #define CONT 7 /* continue stopped process */ 526072Slinton #define SSTEP 9 /* continue for approximately one instruction */ 536072Slinton #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 */ 665607Slinton pstart(p, cmd, argv, infile, outfile) 675507Slinton PROCESS *p; 685607Slinton char *cmd; 695507Slinton char **argv; 705507Slinton char *infile; 715507Slinton char *outfile; 725507Slinton { 736072Slinton int status; 746072Slinton FILE *in, *out; 755507Slinton 766072Slinton if (p->pid != 0) { /* child already running? */ 776072Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 786072Slinton } 796072Slinton psigtrace(p, SIGTRAP, TRUE); 806072Slinton if ((p->pid = fork()) == -1) { 816072Slinton panic("can't fork"); 826072Slinton } 836072Slinton if (ischild(p->pid)) { 846072Slinton traceme(); 856072Slinton if (infile != NIL) { 866072Slinton if ((in = fopen(infile, "r")) == NIL) { 876072Slinton printf("can't read %s\n", infile); 886072Slinton exit(1); 896072Slinton } 906072Slinton fswap(0, fileno(in)); 915507Slinton } 926072Slinton if (outfile != NIL) { 936072Slinton if ((out = fopen(outfile, "w")) == NIL) { 946072Slinton printf("can't write %s\n", outfile); 956072Slinton exit(1); 966072Slinton } 976072Slinton fswap(1, fileno(out)); 985507Slinton } 996072Slinton execvp(cmd, argv); 1006072Slinton panic("can't exec %s", argv[0]); 1016072Slinton } 1026072Slinton pwait(p->pid, &status); 1036072Slinton 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 { 1196072Slinton int status; 1205507Slinton 1216072Slinton if (p->pid == 0) { 1226072Slinton error("program not active"); 1236072Slinton } 1246072Slinton do { 1256072Slinton setinfo(p); 1266072Slinton sigs_off(); 1276072Slinton if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) { 1286072Slinton panic("can't continue process"); 1295507Slinton } 1306072Slinton pwait(p->pid, &status); 1316072Slinton sigs_on(); 1326072Slinton getinfo(p, status); 1336072Slinton } 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 { 1436072Slinton int status; 1445507Slinton 1456072Slinton setinfo(p); 1466072Slinton sigs_off(); 1476072Slinton ptrace(SSTEP, p->pid, p->pc, p->signo); 1486072Slinton pwait(p->pid, &status); 1496072Slinton sigs_on(); 1506072Slinton 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 { 1626072Slinton if (sw) { 1636072Slinton p->sigset |= setrep(sig); 1646072Slinton } else { 1656072Slinton p->sigset &= ~setrep(sig); 1666072Slinton } 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 { 1776072Slinton 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 { 1906072Slinton register int i; 1915507Slinton 1926072Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 1936072Slinton if (i != SIGKILL) { 1946072Slinton sigfunc[i] = signal(i, SIG_IGN); 1955507Slinton } 1966072Slinton } 1975507Slinton } 1985507Slinton 1995507Slinton /* 2005507Slinton * turn back on attention to signals 2015507Slinton */ 2025507Slinton 2035507Slinton LOCAL sigs_on() 2045507Slinton { 2056072Slinton register int i; 2065507Slinton 2076072Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 2086072Slinton if (i != SIGKILL) { 2096072Slinton signal(i, sigfunc[i]); 2105507Slinton } 2116072Slinton } 2125507Slinton } 2135507Slinton 2145507Slinton /* 2155507Slinton * get PROCESS information from process's user area 2165507Slinton */ 2175507Slinton 2185507Slinton LOCAL int rloc[] ={ 2196072Slinton 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 { 2266072Slinton register int i; 2275507Slinton 2286072Slinton p->signo = (status&0177); 2296072Slinton p->exitval = ((status >> 8)&0377); 2306072Slinton if (p->signo == STOPPED) { 2316072Slinton p->status = p->signo; 2326072Slinton p->signo = p->exitval; 2336072Slinton p->exitval = 0; 2346072Slinton } else { 2356072Slinton p->status = FINISHED; 2366072Slinton return; 2376072Slinton } 2386072Slinton for (i = 0; i < NREG; i++) { 2396072Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 2406072Slinton p->oreg[i] = p->reg[i]; 2416072Slinton } 2426072Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0); 2436072Slinton p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0); 2446072Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 2456072Slinton 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 { 2556072Slinton register int i; 2566072Slinton register int r; 2575507Slinton 2586072Slinton if (istraced(p)) { 2596072Slinton p->signo = 0; 2606072Slinton } 2616072Slinton for (i = 0; i < NREG; i++) { 2626072Slinton if ((r = p->reg[i]) != p->oreg[i]) { 2636072Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 2645507Slinton } 2656072Slinton } 2666072Slinton if ((r = p->fp) != p->ofp) { 2676072Slinton ptrace(UWRITE, p->pid, regloc(FP), r); 2686072Slinton } 2696072Slinton if ((r = p->sp) != p->osp) { 2706072Slinton ptrace(UWRITE, p->pid, regloc(SP), r); 2716072Slinton } 2726072Slinton if ((r = p->ap) != p->oap) { 2736072Slinton ptrace(UWRITE, p->pid, regloc(AP), r); 2746072Slinton } 2756072Slinton if ((r = p->pc) != p->opc) { 2766072Slinton ptrace(UWRITE, p->pid, regloc(PC), r); 2776072Slinton } 2785507Slinton } 2795507Slinton 2805507Slinton /* 2815507Slinton * Structure for reading and writing by words, but dealing with bytes. 2825507Slinton */ 2835507Slinton 2845507Slinton typedef union { 2856072Slinton WORD pword; 2866072Slinton 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 { 3066072Slinton register int i; 3076072Slinton register ADDRESS newaddr; 3086072Slinton register char *cp; 3096072Slinton char *bufend; 3106072Slinton PWORD w; 3116072Slinton ADDRESS wordaddr; 3126072Slinton int byteoff; 3135507Slinton 3146072Slinton if (p->status != STOPPED) { 3156072Slinton error("program is not active"); 3166072Slinton } 3176072Slinton cp = buff; 3186072Slinton newaddr = addr; 3196072Slinton wordaddr = (newaddr&WMASK); 3206072Slinton if (wordaddr != newaddr) { 3216072Slinton w.pword = fetch(p, seg, wordaddr); 3226072Slinton for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) { 3236072Slinton if (op == PREAD) { 3246072Slinton *cp++ = w.pbyte[i]; 3256072Slinton } else { 3266072Slinton w.pbyte[i] = *cp++; 3276072Slinton } 3286072Slinton nbytes--; 3295507Slinton } 3306072Slinton if (op == PWRITE) { 3316072Slinton store(p, seg, wordaddr, w.pword); 3325507Slinton } 3336072Slinton newaddr = wordaddr + sizeof(WORD); 3346072Slinton } 3356072Slinton byteoff = (nbytes&(~WMASK)); 3366072Slinton nbytes -= byteoff; 3376072Slinton bufend = cp + nbytes; 3386072Slinton while (cp < bufend) { 3396072Slinton if (op == PREAD) { 3406072Slinton *((WORD *) cp) = fetch(p, seg, newaddr); 3416072Slinton } else { 3426072Slinton store(p, seg, newaddr, *((WORD *) cp)); 3435507Slinton } 3446072Slinton cp += sizeof(WORD); 3456072Slinton newaddr += sizeof(WORD); 3466072Slinton } 3476072Slinton if (byteoff > 0) { 3486072Slinton w.pword = fetch(p, seg, newaddr); 3496072Slinton for (i = 0; i < byteoff; i++) { 3506072Slinton if (op == PREAD) { 3516072Slinton *cp++ = w.pbyte[i]; 3526072Slinton } else { 3536072Slinton w.pbyte[i] = *cp++; 3546072Slinton } 3555507Slinton } 3566072Slinton if (op == PWRITE) { 3576072Slinton store(p, seg, newaddr, w.pword); 3586072Slinton } 3596072Slinton } 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 { 3806072Slinton register CACHEWORD *wp; 3816072Slinton register WORD w; 3825507Slinton 3836072Slinton switch (seg) { 3846072Slinton case TEXTSEG: 3856072Slinton # if (isvaxpx) 3866072Slinton panic("tried to fetch from px i-space"); 3876072Slinton /* NOTREACHED */ 3886072Slinton # else 3896072Slinton wp = &p->word[cachehash(addr)]; 3906072Slinton if (addr == 0 || wp->addr != addr) { 3916072Slinton w = ptrace(IREAD, p->pid, addr, 0); 3926072Slinton wp->addr = addr; 3936072Slinton wp->val = w; 3946072Slinton } else { 3956072Slinton w = wp->val; 3966072Slinton } 3976072Slinton break; 3986072Slinton # endif 3995507Slinton 4006072Slinton case DATASEG: 4016072Slinton # if (isvaxpx) 4026072Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 4036072Slinton wp = &p->word[cachehash(addr)]; 4046072Slinton if (addr == 0 || wp->addr != addr) { 4056072Slinton w = ptrace(DREAD, p->pid, addr, 0); 4066072Slinton wp->addr = addr; 4076072Slinton wp->val = w; 4086072Slinton } else { 4096072Slinton w = wp->val; 4106072Slinton } 4116072Slinton } else { 4126072Slinton w = ptrace(DREAD, p->pid, addr, 0); 4136072Slinton } 4146072Slinton # else 4156072Slinton w = ptrace(DREAD, p->pid, addr, 0); 4166072Slinton # endif 4176072Slinton break; 4185507Slinton 4196072Slinton default: 4206072Slinton panic("fetch: bad seg %d", seg); 4216072Slinton /* NOTREACHED */ 4226072Slinton } 4236072Slinton 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 { 4376072Slinton register CACHEWORD *wp; 4385507Slinton 4396072Slinton switch (seg) { 4406072Slinton case TEXTSEG: 4416072Slinton wp = &p->word[cachehash(addr)]; 4426072Slinton wp->addr = addr; 4436072Slinton wp->val = data; 4446072Slinton ptrace(IWRITE, p->pid, addr, data); 4456072Slinton break; 4465507Slinton 4476072Slinton case DATASEG: 4486072Slinton # if (isvaxpx) 4496072Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 4506072Slinton wp = &p->word[cachehash(addr)]; 4516072Slinton wp->addr = addr; 4526072Slinton wp->val = data; 4536072Slinton } 4546072Slinton # endif 4556072Slinton ptrace(DWRITE, p->pid, addr, data); 4566072Slinton break; 4575507Slinton 4586072Slinton default: 4596072Slinton panic("store: bad seg %d", seg); 4606072Slinton /*NOTREACHED*/ 4616072Slinton } 4625507Slinton } 4635507Slinton 4645507Slinton /* 4656072Slinton * Initialize the instruction cache for a process. 4666072Slinton * This is particularly necessary after the program has been remade. 4676072Slinton */ 4686072Slinton 4696072Slinton initcache(process) 4706072Slinton PROCESS *process; 4716072Slinton { 4726072Slinton register int i; 4736072Slinton 4746072Slinton for (i = 0; i < CSIZE; i++) { 4756072Slinton process->word[i].addr = 0; 4766072Slinton } 4776072Slinton } 4786072Slinton 4796072Slinton /* 4805507Slinton * Swap file numbers so as to redirect standard input and output. 4815507Slinton */ 4825507Slinton 4835507Slinton LOCAL fswap(oldfd, newfd) 4845507Slinton int oldfd; 4855507Slinton int newfd; 4865507Slinton { 4876072Slinton if (oldfd != newfd) { 4886072Slinton close(oldfd); 4896072Slinton dup(newfd); 4906072Slinton close(newfd); 4916072Slinton } 4925507Slinton } 493