1*5507Slinton /* Copyright (c) 1982 Regents of the University of California */ 2*5507Slinton 3*5507Slinton static char sccsid[] = "@(#)ptrace.c 1.1 01/18/82"; 4*5507Slinton 5*5507Slinton /* 6*5507Slinton * routines for tracing the execution of a process 7*5507Slinton * 8*5507Slinton * The system call "ptrace" does all the work, these 9*5507Slinton * routines just try to interface easily to it. 10*5507Slinton */ 11*5507Slinton 12*5507Slinton #include "defs.h" 13*5507Slinton #include <signal.h> 14*5507Slinton #include <sys/param.h> 15*5507Slinton #include <sys/reg.h> 16*5507Slinton #include "process.h" 17*5507Slinton #include "object.h" 18*5507Slinton #include "process.rep" 19*5507Slinton 20*5507Slinton # if (isvaxpx) 21*5507Slinton # include "pxinfo.h" 22*5507Slinton # endif 23*5507Slinton 24*5507Slinton /* 25*5507Slinton * This magic macro enables us to look at the process' registers 26*5507Slinton * in its user structure. Very gross. 27*5507Slinton */ 28*5507Slinton 29*5507Slinton #define regloc(reg) (ctob(UPAGES) + ( sizeof(int) * (reg) )) 30*5507Slinton 31*5507Slinton #define WMASK (~(sizeof(WORD) - 1)) 32*5507Slinton #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE)) 33*5507Slinton 34*5507Slinton #define FIRSTSIG SIGINT 35*5507Slinton #define LASTSIG SIGQUIT 36*5507Slinton #define ischild(pid) ((pid) == 0) 37*5507Slinton #define traceme() ptrace(0, 0, 0, 0) 38*5507Slinton #define setrep(n) (1 << ((n)-1)) 39*5507Slinton #define istraced(p) (p->sigset&setrep(p->signo)) 40*5507Slinton 41*5507Slinton /* 42*5507Slinton * ptrace options (specified in first argument) 43*5507Slinton */ 44*5507Slinton 45*5507Slinton #define UREAD 3 /* read from process's user structure */ 46*5507Slinton #define UWRITE 6 /* write to process's user structure */ 47*5507Slinton #define IREAD 1 /* read from process's instruction space */ 48*5507Slinton #define IWRITE 4 /* write to process's instruction space */ 49*5507Slinton #define DREAD 2 /* read from process's data space */ 50*5507Slinton #define DWRITE 5 /* write to process's data space */ 51*5507Slinton #define CONT 7 /* continue stopped process */ 52*5507Slinton #define SSTEP 9 /* continue for approximately one instruction */ 53*5507Slinton #define PKILL 8 /* terminate the process */ 54*5507Slinton 55*5507Slinton /* 56*5507Slinton * Start up a new process by forking and exec-ing the 57*5507Slinton * given argument list, returning when the process is loaded 58*5507Slinton * and ready to execute. The PROCESS information (pointed to 59*5507Slinton * by the first argument) is appropriately filled. 60*5507Slinton * 61*5507Slinton * If the given PROCESS structure is associated with an already running 62*5507Slinton * process, we terminate it. 63*5507Slinton */ 64*5507Slinton 65*5507Slinton /* VARARGS2 */ 66*5507Slinton pstart(p, argv, infile, outfile) 67*5507Slinton PROCESS *p; 68*5507Slinton char **argv; 69*5507Slinton char *infile; 70*5507Slinton char *outfile; 71*5507Slinton { 72*5507Slinton int status; 73*5507Slinton FILE *in, *out; 74*5507Slinton 75*5507Slinton if (p->pid != 0) { /* child already running? */ 76*5507Slinton ptrace(PKILL, p->pid, 0, 0); /* ... kill it! */ 77*5507Slinton } 78*5507Slinton psigtrace(p, SIGTRAP, TRUE); 79*5507Slinton if ((p->pid = fork()) == -1) { 80*5507Slinton panic("can't fork"); 81*5507Slinton } 82*5507Slinton if (ischild(p->pid)) { 83*5507Slinton traceme(); 84*5507Slinton if (infile != NIL) { 85*5507Slinton if ((in = fopen(infile, "r")) == NIL) { 86*5507Slinton printf("can't read %s\n", infile); 87*5507Slinton exit(1); 88*5507Slinton } 89*5507Slinton fswap(0, fileno(in)); 90*5507Slinton } 91*5507Slinton if (outfile != NIL) { 92*5507Slinton if ((out = fopen(outfile, "w")) == NIL) { 93*5507Slinton printf("can't write %s\n", outfile); 94*5507Slinton exit(1); 95*5507Slinton } 96*5507Slinton fswap(1, fileno(out)); 97*5507Slinton } 98*5507Slinton execvp(argv[0], argv); 99*5507Slinton panic("can't exec %s", argv[0]); 100*5507Slinton } 101*5507Slinton pwait(p->pid, &status); 102*5507Slinton getinfo(p, status); 103*5507Slinton if (p->status != STOPPED) { 104*5507Slinton error("program could not begin execution"); 105*5507Slinton } 106*5507Slinton } 107*5507Slinton 108*5507Slinton /* 109*5507Slinton * Continue a stopped process. The argument points to a PROCESS structure. 110*5507Slinton * Before the process is restarted it's user area is modified according to 111*5507Slinton * the values in the structure. When this routine finishes, 112*5507Slinton * the structure has the new values from the process's user area. 113*5507Slinton * 114*5507Slinton * Pcont terminates when the process stops with a signal pending that 115*5507Slinton * is being traced (via psigtrace), or when the process terminates. 116*5507Slinton */ 117*5507Slinton 118*5507Slinton pcont(p) 119*5507Slinton PROCESS *p; 120*5507Slinton { 121*5507Slinton int status; 122*5507Slinton 123*5507Slinton if (p->pid == 0) { 124*5507Slinton error("program not active"); 125*5507Slinton } 126*5507Slinton do { 127*5507Slinton setinfo(p); 128*5507Slinton sigs_off(); 129*5507Slinton if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) { 130*5507Slinton panic("can't continue process"); 131*5507Slinton } 132*5507Slinton pwait(p->pid, &status); 133*5507Slinton sigs_on(); 134*5507Slinton getinfo(p, status); 135*5507Slinton } while (p->status == STOPPED && !istraced(p)); 136*5507Slinton } 137*5507Slinton 138*5507Slinton /* 139*5507Slinton * single step as best ptrace can 140*5507Slinton */ 141*5507Slinton 142*5507Slinton pstep(p) 143*5507Slinton PROCESS *p; 144*5507Slinton { 145*5507Slinton int status; 146*5507Slinton 147*5507Slinton setinfo(p); 148*5507Slinton sigs_off(); 149*5507Slinton ptrace(SSTEP, p->pid, p->pc, p->signo); 150*5507Slinton pwait(p->pid, &status); 151*5507Slinton sigs_on(); 152*5507Slinton getinfo(p, status); 153*5507Slinton } 154*5507Slinton 155*5507Slinton /* 156*5507Slinton * Return from execution when the given signal is pending. 157*5507Slinton */ 158*5507Slinton 159*5507Slinton psigtrace(p, sig, sw) 160*5507Slinton PROCESS *p; 161*5507Slinton int sig; 162*5507Slinton int sw; 163*5507Slinton { 164*5507Slinton if (sw) { 165*5507Slinton p->sigset |= setrep(sig); 166*5507Slinton } else { 167*5507Slinton p->sigset &= ~setrep(sig); 168*5507Slinton } 169*5507Slinton } 170*5507Slinton 171*5507Slinton /* 172*5507Slinton * Don't catch any signals. 173*5507Slinton * Particularly useful when letting a process finish uninhibited (i.e. px). 174*5507Slinton */ 175*5507Slinton 176*5507Slinton unsetsigtraces(p) 177*5507Slinton PROCESS *p; 178*5507Slinton { 179*5507Slinton p->sigset = 0; 180*5507Slinton } 181*5507Slinton 182*5507Slinton /* 183*5507Slinton * turn off attention to signals not being caught 184*5507Slinton */ 185*5507Slinton 186*5507Slinton typedef int INTFUNC(); 187*5507Slinton 188*5507Slinton LOCAL INTFUNC *sigfunc[NSIG]; 189*5507Slinton 190*5507Slinton LOCAL sigs_off() 191*5507Slinton { 192*5507Slinton register int i; 193*5507Slinton 194*5507Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 195*5507Slinton if (i != SIGKILL) { 196*5507Slinton sigfunc[i] = signal(i, SIG_IGN); 197*5507Slinton } 198*5507Slinton } 199*5507Slinton } 200*5507Slinton 201*5507Slinton /* 202*5507Slinton * turn back on attention to signals 203*5507Slinton */ 204*5507Slinton 205*5507Slinton LOCAL sigs_on() 206*5507Slinton { 207*5507Slinton register int i; 208*5507Slinton 209*5507Slinton for (i = FIRSTSIG; i < LASTSIG; i++) { 210*5507Slinton if (i != SIGKILL) { 211*5507Slinton signal(i, sigfunc[i]); 212*5507Slinton } 213*5507Slinton } 214*5507Slinton } 215*5507Slinton 216*5507Slinton /* 217*5507Slinton * get PROCESS information from process's user area 218*5507Slinton */ 219*5507Slinton 220*5507Slinton LOCAL int rloc[] ={ 221*5507Slinton R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, 222*5507Slinton }; 223*5507Slinton 224*5507Slinton LOCAL getinfo(p, status) 225*5507Slinton register PROCESS *p; 226*5507Slinton register int status; 227*5507Slinton { 228*5507Slinton register int i; 229*5507Slinton 230*5507Slinton p->signo = (status&0177); 231*5507Slinton p->exitval = ((status >> 8)&0377); 232*5507Slinton if (p->signo == STOPPED) { 233*5507Slinton p->status = p->signo; 234*5507Slinton p->signo = p->exitval; 235*5507Slinton p->exitval = 0; 236*5507Slinton } else { 237*5507Slinton p->status = FINISHED; 238*5507Slinton return; 239*5507Slinton } 240*5507Slinton for (i = 0; i < NREG; i++) { 241*5507Slinton p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0); 242*5507Slinton p->oreg[i] = p->reg[i]; 243*5507Slinton } 244*5507Slinton p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0); 245*5507Slinton p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0); 246*5507Slinton p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0); 247*5507Slinton p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0); 248*5507Slinton } 249*5507Slinton 250*5507Slinton /* 251*5507Slinton * set process's user area information from given PROCESS structure 252*5507Slinton */ 253*5507Slinton 254*5507Slinton LOCAL setinfo(p) 255*5507Slinton register PROCESS *p; 256*5507Slinton { 257*5507Slinton register int i; 258*5507Slinton register int r; 259*5507Slinton 260*5507Slinton if (istraced(p)) { 261*5507Slinton p->signo = 0; 262*5507Slinton } 263*5507Slinton for (i = 0; i < NREG; i++) { 264*5507Slinton if ((r = p->reg[i]) != p->oreg[i]) { 265*5507Slinton ptrace(UWRITE, p->pid, regloc(rloc[i]), r); 266*5507Slinton } 267*5507Slinton } 268*5507Slinton if ((r = p->fp) != p->ofp) { 269*5507Slinton ptrace(UWRITE, p->pid, regloc(FP), r); 270*5507Slinton } 271*5507Slinton if ((r = p->sp) != p->osp) { 272*5507Slinton ptrace(UWRITE, p->pid, regloc(SP), r); 273*5507Slinton } 274*5507Slinton if ((r = p->ap) != p->oap) { 275*5507Slinton ptrace(UWRITE, p->pid, regloc(AP), r); 276*5507Slinton } 277*5507Slinton if ((r = p->pc) != p->opc) { 278*5507Slinton ptrace(UWRITE, p->pid, regloc(PC), r); 279*5507Slinton } 280*5507Slinton } 281*5507Slinton 282*5507Slinton /* 283*5507Slinton * Structure for reading and writing by words, but dealing with bytes. 284*5507Slinton */ 285*5507Slinton 286*5507Slinton typedef union { 287*5507Slinton WORD pword; 288*5507Slinton BYTE pbyte[sizeof(WORD)]; 289*5507Slinton } PWORD; 290*5507Slinton 291*5507Slinton /* 292*5507Slinton * Read (write) from (to) the process' address space. 293*5507Slinton * We must deal with ptrace's inability to look anywhere other 294*5507Slinton * than at a word boundary. 295*5507Slinton */ 296*5507Slinton 297*5507Slinton LOCAL WORD fetch(); 298*5507Slinton LOCAL store(); 299*5507Slinton 300*5507Slinton pio(p, op, seg, buff, addr, nbytes) 301*5507Slinton PROCESS *p; 302*5507Slinton PIO_OP op; 303*5507Slinton PIO_SEG seg; 304*5507Slinton char *buff; 305*5507Slinton ADDRESS addr; 306*5507Slinton int nbytes; 307*5507Slinton { 308*5507Slinton register int i; 309*5507Slinton register ADDRESS newaddr; 310*5507Slinton register char *cp; 311*5507Slinton char *bufend; 312*5507Slinton PWORD w; 313*5507Slinton ADDRESS wordaddr; 314*5507Slinton int byteoff; 315*5507Slinton 316*5507Slinton if (p->status != STOPPED) { 317*5507Slinton error("program is not active"); 318*5507Slinton } 319*5507Slinton cp = buff; 320*5507Slinton newaddr = addr; 321*5507Slinton wordaddr = (newaddr&WMASK); 322*5507Slinton if (wordaddr != newaddr) { 323*5507Slinton w.pword = fetch(p, seg, wordaddr); 324*5507Slinton for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) { 325*5507Slinton if (op == PREAD) { 326*5507Slinton *cp++ = w.pbyte[i]; 327*5507Slinton } else { 328*5507Slinton w.pbyte[i] = *cp++; 329*5507Slinton } 330*5507Slinton nbytes--; 331*5507Slinton } 332*5507Slinton if (op == PWRITE) { 333*5507Slinton store(p, seg, wordaddr, w.pword); 334*5507Slinton } 335*5507Slinton newaddr = wordaddr + sizeof(WORD); 336*5507Slinton } 337*5507Slinton byteoff = (nbytes&(~WMASK)); 338*5507Slinton nbytes -= byteoff; 339*5507Slinton bufend = cp + nbytes; 340*5507Slinton while (cp < bufend) { 341*5507Slinton if (op == PREAD) { 342*5507Slinton *((WORD *) cp) = fetch(p, seg, newaddr); 343*5507Slinton } else { 344*5507Slinton store(p, seg, newaddr, *((WORD *) cp)); 345*5507Slinton } 346*5507Slinton cp += sizeof(WORD); 347*5507Slinton newaddr += sizeof(WORD); 348*5507Slinton } 349*5507Slinton if (byteoff > 0) { 350*5507Slinton w.pword = fetch(p, seg, newaddr); 351*5507Slinton for (i = 0; i < byteoff; i++) { 352*5507Slinton if (op == PREAD) { 353*5507Slinton *cp++ = w.pbyte[i]; 354*5507Slinton } else { 355*5507Slinton w.pbyte[i] = *cp++; 356*5507Slinton } 357*5507Slinton } 358*5507Slinton if (op == PWRITE) { 359*5507Slinton store(p, seg, newaddr, w.pword); 360*5507Slinton } 361*5507Slinton } 362*5507Slinton } 363*5507Slinton 364*5507Slinton /* 365*5507Slinton * Get a word from a process at the given address. 366*5507Slinton * The address is assumed to be on a word boundary. 367*5507Slinton * 368*5507Slinton * We use a simple cache scheme to avoid redundant references to 369*5507Slinton * the instruction space (which is assumed to be pure). In the 370*5507Slinton * case of px, the "instruction" space lies between ENDOFF and 371*5507Slinton * ENDOFF + objsize. 372*5507Slinton * 373*5507Slinton * It is necessary to use a write-through scheme so that 374*5507Slinton * breakpoints right next to each other don't interfere. 375*5507Slinton */ 376*5507Slinton 377*5507Slinton LOCAL WORD fetch(p, seg, addr) 378*5507Slinton PROCESS *p; 379*5507Slinton PIO_SEG seg; 380*5507Slinton register int addr; 381*5507Slinton { 382*5507Slinton register CACHEWORD *wp; 383*5507Slinton register WORD w; 384*5507Slinton 385*5507Slinton switch (seg) { 386*5507Slinton case TEXTSEG: 387*5507Slinton # if (isvaxpx) 388*5507Slinton panic("tried to fetch from px i-space"); 389*5507Slinton /* NOTREACHED */ 390*5507Slinton # else 391*5507Slinton wp = &p->word[cachehash(addr)]; 392*5507Slinton if (addr == 0 || wp->addr != addr) { 393*5507Slinton w = ptrace(IREAD, p->pid, addr, 0); 394*5507Slinton wp->addr = addr; 395*5507Slinton wp->val = w; 396*5507Slinton } else { 397*5507Slinton w = wp->val; 398*5507Slinton } 399*5507Slinton break; 400*5507Slinton # endif 401*5507Slinton 402*5507Slinton case DATASEG: 403*5507Slinton # if (isvaxpx) 404*5507Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 405*5507Slinton wp = &p->word[cachehash(addr)]; 406*5507Slinton if (addr == 0 || wp->addr != addr) { 407*5507Slinton w = ptrace(DREAD, p->pid, addr, 0); 408*5507Slinton wp->addr = addr; 409*5507Slinton wp->val = w; 410*5507Slinton } else { 411*5507Slinton w = wp->val; 412*5507Slinton } 413*5507Slinton } else { 414*5507Slinton w = ptrace(DREAD, p->pid, addr, 0); 415*5507Slinton } 416*5507Slinton # else 417*5507Slinton w = ptrace(DREAD, p->pid, addr, 0); 418*5507Slinton # endif 419*5507Slinton break; 420*5507Slinton 421*5507Slinton default: 422*5507Slinton panic("fetch: bad seg %d", seg); 423*5507Slinton /* NOTREACHED */ 424*5507Slinton } 425*5507Slinton return(w); 426*5507Slinton } 427*5507Slinton 428*5507Slinton /* 429*5507Slinton * Put a word into the process' address space at the given address. 430*5507Slinton * The address is assumed to be on a word boundary. 431*5507Slinton */ 432*5507Slinton 433*5507Slinton LOCAL store(p, seg, addr, data) 434*5507Slinton PROCESS *p; 435*5507Slinton PIO_SEG seg; 436*5507Slinton int addr; 437*5507Slinton WORD data; 438*5507Slinton { 439*5507Slinton register CACHEWORD *wp; 440*5507Slinton 441*5507Slinton switch (seg) { 442*5507Slinton case TEXTSEG: 443*5507Slinton wp = &p->word[cachehash(addr)]; 444*5507Slinton wp->addr = addr; 445*5507Slinton wp->val = data; 446*5507Slinton ptrace(IWRITE, p->pid, addr, data); 447*5507Slinton break; 448*5507Slinton 449*5507Slinton case DATASEG: 450*5507Slinton # if (isvaxpx) 451*5507Slinton if (addr >= ENDOFF && addr < ENDOFF + objsize) { 452*5507Slinton wp = &p->word[cachehash(addr)]; 453*5507Slinton wp->addr = addr; 454*5507Slinton wp->val = data; 455*5507Slinton } 456*5507Slinton # endif 457*5507Slinton ptrace(DWRITE, p->pid, addr, data); 458*5507Slinton break; 459*5507Slinton 460*5507Slinton default: 461*5507Slinton panic("store: bad seg %d", seg); 462*5507Slinton /*NOTREACHED*/ 463*5507Slinton } 464*5507Slinton } 465*5507Slinton 466*5507Slinton /* 467*5507Slinton * Swap file numbers so as to redirect standard input and output. 468*5507Slinton */ 469*5507Slinton 470*5507Slinton LOCAL fswap(oldfd, newfd) 471*5507Slinton int oldfd; 472*5507Slinton int newfd; 473*5507Slinton { 474*5507Slinton if (oldfd != newfd) { 475*5507Slinton close(oldfd); 476*5507Slinton dup(newfd); 477*5507Slinton close(newfd); 478*5507Slinton } 479*5507Slinton } 480