15507Slinton /* Copyright (c) 1982 Regents of the University of California */ 25507Slinton 3*6072Slinton static char sccsid[] = "@(#)ptrace.c 1.3 03/08/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 20*6072Slinton # if (isvaxpx) 21*6072Slinton # include "pxinfo.h" 22*6072Slinton # endif 235507Slinton 245507Slinton /* 255507Slinton * This magic macro enables us to look at the process' registers 265507Slinton * in its user structure. Very gross. 275507Slinton */ 285507Slinton 29*6072Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 305507Slinton 31*6072Slinton #define WMASK (~(sizeof(WORD) - 1)) 32*6072Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 335507Slinton 34*6072Slinton #define FIRSTSIG SIGINT 35*6072Slinton #define LASTSIG SIGQUIT 36*6072Slinton #define ischild(pid) ((pid) == 0) 37*6072Slinton #define traceme() ptrace(0, 0, 0, 0) 38*6072Slinton #define setrep(n) (1 << ((n)-1)) 39*6072Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 405507Slinton 415507Slinton /* 425507Slinton * ptrace options (specified in first argument) 435507Slinton */ 445507Slinton 45*6072Slinton #define UREAD 3 /* read from process's user structure */ 46*6072Slinton #define UWRITE 6 /* write to process's user structure */ 47*6072Slinton #define IREAD 1 /* read from process's instruction space */ 48*6072Slinton #define IWRITE 4 /* write to process's instruction space */ 49*6072Slinton #define DREAD 2 /* read from process's data space */ 50*6072Slinton #define DWRITE 5 /* write to process's data space */ 51*6072Slinton #define CONT 7 /* continue stopped process */ 52*6072Slinton #define SSTEP 9 /* continue for approximately one instruction */ 53*6072Slinton #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 { 73*6072Slinton int status; 74*6072Slinton FILE *in, *out; 755507Slinton 76*6072Slinton if (p->pid != 0) { /* child already running? */ 77*6072Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 78*6072Slinton } 79*6072Slinton psigtrace(p, SIGTRAP, TRUE); 80*6072Slinton if ((p->pid = fork()) == -1) { 81*6072Slinton panic("can't fork"); 82*6072Slinton } 83*6072Slinton if (ischild(p->pid)) { 84*6072Slinton traceme(); 85*6072Slinton if (infile != NIL) { 86*6072Slinton if ((in = fopen(infile, "r")) == NIL) { 87*6072Slinton printf("can't read %s\n", infile); 88*6072Slinton exit(1); 89*6072Slinton } 90*6072Slinton fswap(0, fileno(in)); 915507Slinton } 92*6072Slinton if (outfile != NIL) { 93*6072Slinton if ((out = fopen(outfile, "w")) == NIL) { 94*6072Slinton printf("can't write %s\n", outfile); 95*6072Slinton exit(1); 96*6072Slinton } 97*6072Slinton fswap(1, fileno(out)); 985507Slinton } 99*6072Slinton execvp(cmd, argv); 100*6072Slinton panic("can't exec %s", argv[0]); 101*6072Slinton } 102*6072Slinton pwait(p->pid, &status); 103*6072Slinton 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 { 119*6072Slinton int status; 1205507Slinton 121*6072Slinton if (p->pid == 0) { 122*6072Slinton error("program not active"); 123*6072Slinton } 124*6072Slinton do { 125*6072Slinton setinfo(p); 126*6072Slinton sigs_off(); 127*6072Slinton if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) { 128*6072Slinton panic("can't continue process"); 1295507Slinton } 130*6072Slinton pwait(p->pid, &status); 131*6072Slinton sigs_on(); 132*6072Slinton getinfo(p, status); 133*6072Slinton } 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 { 143*6072Slinton int status; 1445507Slinton 145*6072Slinton setinfo(p); 146*6072Slinton sigs_off(); 147*6072Slinton ptrace(SSTEP, p->pid, p->pc, p->signo); 148*6072Slinton pwait(p->pid, &status); 149*6072Slinton sigs_on(); 150*6072Slinton 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 { 162*6072Slinton if (sw) { 163*6072Slinton p->sigset |= setrep(sig); 164*6072Slinton } else { 165*6072Slinton p->sigset &= ~setrep(sig); 166*6072Slinton } 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 { 177*6072Slinton 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 { 190*6072Slinton register int i; 1915507Slinton 192*6072Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 193*6072Slinton if (i != SIGKILL) { 194*6072Slinton sigfunc[i] = signal(i, SIG_IGN); 1955507Slinton } 196*6072Slinton } 1975507Slinton } 1985507Slinton 1995507Slinton /* 2005507Slinton * turn back on attention to signals 2015507Slinton */ 2025507Slinton 2035507Slinton LOCAL sigs_on() 2045507Slinton { 205*6072Slinton register int i; 2065507Slinton 207*6072Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 208*6072Slinton if (i != SIGKILL) { 209*6072Slinton signal(i, sigfunc[i]); 2105507Slinton } 211*6072Slinton } 2125507Slinton } 2135507Slinton 2145507Slinton /* 2155507Slinton * get PROCESS information from process's user area 2165507Slinton */ 2175507Slinton 2185507Slinton LOCAL int rloc[] ={ 219*6072Slinton 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 { 226*6072Slinton register int i; 2275507Slinton 228*6072Slinton p->signo = (status&0177); 229*6072Slinton p->exitval = ((status >> 8)&0377); 230*6072Slinton if (p->signo == STOPPED) { 231*6072Slinton p->status = p->signo; 232*6072Slinton p->signo = p->exitval; 233*6072Slinton p->exitval = 0; 234*6072Slinton } else { 235*6072Slinton p->status = FINISHED; 236*6072Slinton return; 237*6072Slinton } 238*6072Slinton for (i = 0; i < NREG; i++) { 239*6072Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 240*6072Slinton p->oreg[i] = p->reg[i]; 241*6072Slinton } 242*6072Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0); 243*6072Slinton p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0); 244*6072Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 245*6072Slinton 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 { 255*6072Slinton register int i; 256*6072Slinton register int r; 2575507Slinton 258*6072Slinton if (istraced(p)) { 259*6072Slinton p->signo = 0; 260*6072Slinton } 261*6072Slinton for (i = 0; i < NREG; i++) { 262*6072Slinton if ((r = p->reg[i]) != p->oreg[i]) { 263*6072Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 2645507Slinton } 265*6072Slinton } 266*6072Slinton if ((r = p->fp) != p->ofp) { 267*6072Slinton ptrace(UWRITE, p->pid, regloc(FP), r); 268*6072Slinton } 269*6072Slinton if ((r = p->sp) != p->osp) { 270*6072Slinton ptrace(UWRITE, p->pid, regloc(SP), r); 271*6072Slinton } 272*6072Slinton if ((r = p->ap) != p->oap) { 273*6072Slinton ptrace(UWRITE, p->pid, regloc(AP), r); 274*6072Slinton } 275*6072Slinton if ((r = p->pc) != p->opc) { 276*6072Slinton ptrace(UWRITE, p->pid, regloc(PC), r); 277*6072Slinton } 2785507Slinton } 2795507Slinton 2805507Slinton /* 2815507Slinton * Structure for reading and writing by words, but dealing with bytes. 2825507Slinton */ 2835507Slinton 2845507Slinton typedef union { 285*6072Slinton WORD pword; 286*6072Slinton 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 { 306*6072Slinton register int i; 307*6072Slinton register ADDRESS newaddr; 308*6072Slinton register char *cp; 309*6072Slinton char *bufend; 310*6072Slinton PWORD w; 311*6072Slinton ADDRESS wordaddr; 312*6072Slinton int byteoff; 3135507Slinton 314*6072Slinton if (p->status != STOPPED) { 315*6072Slinton error("program is not active"); 316*6072Slinton } 317*6072Slinton cp = buff; 318*6072Slinton newaddr = addr; 319*6072Slinton wordaddr = (newaddr&WMASK); 320*6072Slinton if (wordaddr != newaddr) { 321*6072Slinton w.pword = fetch(p, seg, wordaddr); 322*6072Slinton for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) { 323*6072Slinton if (op == PREAD) { 324*6072Slinton *cp++ = w.pbyte[i]; 325*6072Slinton } else { 326*6072Slinton w.pbyte[i] = *cp++; 327*6072Slinton } 328*6072Slinton nbytes--; 3295507Slinton } 330*6072Slinton if (op == PWRITE) { 331*6072Slinton store(p, seg, wordaddr, w.pword); 3325507Slinton } 333*6072Slinton newaddr = wordaddr + sizeof(WORD); 334*6072Slinton } 335*6072Slinton byteoff = (nbytes&(~WMASK)); 336*6072Slinton nbytes -= byteoff; 337*6072Slinton bufend = cp + nbytes; 338*6072Slinton while (cp < bufend) { 339*6072Slinton if (op == PREAD) { 340*6072Slinton *((WORD *) cp) = fetch(p, seg, newaddr); 341*6072Slinton } else { 342*6072Slinton store(p, seg, newaddr, *((WORD *) cp)); 3435507Slinton } 344*6072Slinton cp += sizeof(WORD); 345*6072Slinton newaddr += sizeof(WORD); 346*6072Slinton } 347*6072Slinton if (byteoff > 0) { 348*6072Slinton w.pword = fetch(p, seg, newaddr); 349*6072Slinton for (i = 0; i < byteoff; i++) { 350*6072Slinton if (op == PREAD) { 351*6072Slinton *cp++ = w.pbyte[i]; 352*6072Slinton } else { 353*6072Slinton w.pbyte[i] = *cp++; 354*6072Slinton } 3555507Slinton } 356*6072Slinton if (op == PWRITE) { 357*6072Slinton store(p, seg, newaddr, w.pword); 358*6072Slinton } 359*6072Slinton } 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 { 380*6072Slinton register CACHEWORD *wp; 381*6072Slinton register WORD w; 3825507Slinton 383*6072Slinton switch (seg) { 384*6072Slinton case TEXTSEG: 385*6072Slinton # if (isvaxpx) 386*6072Slinton panic("tried to fetch from px i-space"); 387*6072Slinton /* NOTREACHED */ 388*6072Slinton # else 389*6072Slinton wp = &p->word[cachehash(addr)]; 390*6072Slinton if (addr == 0 || wp->addr != addr) { 391*6072Slinton w = ptrace(IREAD, p->pid, addr, 0); 392*6072Slinton wp->addr = addr; 393*6072Slinton wp->val = w; 394*6072Slinton } else { 395*6072Slinton w = wp->val; 396*6072Slinton } 397*6072Slinton break; 398*6072Slinton # endif 3995507Slinton 400*6072Slinton case DATASEG: 401*6072Slinton # if (isvaxpx) 402*6072Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 403*6072Slinton wp = &p->word[cachehash(addr)]; 404*6072Slinton if (addr == 0 || wp->addr != addr) { 405*6072Slinton w = ptrace(DREAD, p->pid, addr, 0); 406*6072Slinton wp->addr = addr; 407*6072Slinton wp->val = w; 408*6072Slinton } else { 409*6072Slinton w = wp->val; 410*6072Slinton } 411*6072Slinton } else { 412*6072Slinton w = ptrace(DREAD, p->pid, addr, 0); 413*6072Slinton } 414*6072Slinton # else 415*6072Slinton w = ptrace(DREAD, p->pid, addr, 0); 416*6072Slinton # endif 417*6072Slinton break; 4185507Slinton 419*6072Slinton default: 420*6072Slinton panic("fetch: bad seg %d", seg); 421*6072Slinton /* NOTREACHED */ 422*6072Slinton } 423*6072Slinton 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 { 437*6072Slinton register CACHEWORD *wp; 4385507Slinton 439*6072Slinton switch (seg) { 440*6072Slinton case TEXTSEG: 441*6072Slinton wp = &p->word[cachehash(addr)]; 442*6072Slinton wp->addr = addr; 443*6072Slinton wp->val = data; 444*6072Slinton ptrace(IWRITE, p->pid, addr, data); 445*6072Slinton break; 4465507Slinton 447*6072Slinton case DATASEG: 448*6072Slinton # if (isvaxpx) 449*6072Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 450*6072Slinton wp = &p->word[cachehash(addr)]; 451*6072Slinton wp->addr = addr; 452*6072Slinton wp->val = data; 453*6072Slinton } 454*6072Slinton # endif 455*6072Slinton ptrace(DWRITE, p->pid, addr, data); 456*6072Slinton break; 4575507Slinton 458*6072Slinton default: 459*6072Slinton panic("store: bad seg %d", seg); 460*6072Slinton /*NOTREACHED*/ 461*6072Slinton } 4625507Slinton } 4635507Slinton 4645507Slinton /* 465*6072Slinton * Initialize the instruction cache for a process. 466*6072Slinton * This is particularly necessary after the program has been remade. 467*6072Slinton */ 468*6072Slinton 469*6072Slinton initcache(process) 470*6072Slinton PROCESS *process; 471*6072Slinton { 472*6072Slinton register int i; 473*6072Slinton 474*6072Slinton for (i = 0; i < CSIZE; i++) { 475*6072Slinton process->word[i].addr = 0; 476*6072Slinton } 477*6072Slinton } 478*6072Slinton 479*6072Slinton /* 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 { 487*6072Slinton if (oldfd != newfd) { 488*6072Slinton close(oldfd); 489*6072Slinton dup(newfd); 490*6072Slinton close(newfd); 491*6072Slinton } 4925507Slinton } 493