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