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: }

Defined functions

fetch defined in line 419; used 4 times
fswap defined in line 527; used 2 times
getinfo defined in line 244; used 3 times
initcache defined in line 513; used 1 times
pio defined in line 342; used 6 times
psigtrace defined in line 173; used 6 times
pstart defined in line 82; used 1 times
pstep defined in line 156; used 1 times
setinfo defined in line 287; used 2 times
sigs_off defined in line 204; used 2 times
sigs_on defined in line 219; used 2 times
store defined in line 475; used 4 times

Defined variables

ar0val defined in line 33; used 4 times
rloc defined in line 239; used 2 times
sccsid defined in line 8; never used

Defined macros

CONT defined in line 67; used 1 times
DREAD defined in line 65; used 3 times
DWRITE defined in line 66; used 1 times
FIRSTSIG defined in line 50; used 2 times
IREAD defined in line 63; used 1 times
IWRITE defined in line 64; used 1 times
LASTSIG defined in line 51; used 2 times
PKILL defined in line 69; used 1 times
  • in line 93
SSTEP defined in line 68; used 1 times
UREAD defined in line 61; used 9 times
UWRITE defined in line 62; used 7 times
U_AR0 defined in line 32; used 1 times
U_PAGE defined in line 31; used 1 times
WMASK defined in line 47; used 2 times
cachehash defined in line 48; used 4 times
ischild defined in line 52; used 1 times
  • in line 99
istraced defined in line 55; used 2 times
regloc defined in line 44; used 15 times
setrep defined in line 54; used 3 times
traceme defined in line 53; used 1 times
Last modified: 1985-06-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2173
Valid CSS Valid XHTML 1.0 Strict