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