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