# 2.11BSD#431 - /usr/src/ucb/PORT/pascal/pdx/process/ptrace.c

##### Functions

    fetch             X
    fswap             X
    getinfo           X
    initcache         X
    pcont             X
    pio               X
    psigtrace         X
    pstart            X
    pstep             X
    setinfo           X
    sigs_off          X
    sigs_on           X
    store             X
    unsetsigtraces    X

##### Variables

    ar0val            X
    rloc              X

##### Macros

    CONT              X
    DREAD             X
    DWRITE            X
    FIRSTSIG          X
    IREAD             X
    IWRITE            X
    LASTSIG           X
    PKILL             X
    SSTEP             X
    UREAD             X
    UWRITE            X
    U_AR0             X
    U_PAGE            X
    WMASK             X
    cachehash         X
    ischild           X
    istraced          X
    regloc            X
    setrep            X
    traceme           X

       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

- in line 339, 365, 384, 392

fswap defined in line 527; used 2 times

- in line 106, 113

getinfo defined in line 244; used 3 times

- in line 119, 148, 166

initcache defined in line 513; used 1 times

- in /usr/src/ucb/PORT/pascal/pdx/process/runcont.c line 124

pcont defined in line 132; used 5 times

- in /usr/src/ucb/PORT/pascal/pdx/process/resume.c line 46, 164, 177
- in /usr/src/ucb/PORT/pascal/pdx/process/start.c line 55, 68

pio defined in line 342; used 6 times

- in /usr/src/ucb/PORT/pascal/pdx/process/rdwr.c line 50-53(2), 73-76(2), 94, 111

psigtrace defined in line 173; used 6 times

- in line 95
- in /usr/src/ucb/PORT/pascal/pdx/process/start.c line 119-123(5)

pstart defined in line 82; used 1 times

- in /usr/src/ucb/PORT/pascal/pdx/process/start.c line 50

pstep defined in line 156; used 1 times

- in /usr/src/ucb/PORT/pascal/pdx/process/step.c line 98

setinfo defined in line 287; used 2 times

- in line 141, 161

sigs_off defined in line 204; used 2 times

- in line 142, 162

sigs_on defined in line 219; used 2 times

- in line 147, 165

store defined in line 475; used 4 times

- in line 340, 375, 386, 401

unsetsigtraces defined in line 190; used 3 times

- in /usr/src/ucb/PORT/pascal/pdx/process/resume.c line 163, 176
- in /usr/src/ucb/PORT/pascal/pdx/process/start.c line 67

#### Defined variables

ar0val defined in line 33; used 4 times

- in line 44, 261-263(3)

rloc defined in line 239; used 2 times

- in line 267, 298

sccsid defined in line 8; never used

#### Defined macros

CONT defined in line 67; used 1 times

- in line 143

DREAD defined in line 65; used 3 times

- in line 449, 456-459(2)

DWRITE defined in line 66; used 1 times

- in line 499

FIRSTSIG defined in line 50; used 2 times

- in line 208, 223

IREAD defined in line 63; used 1 times

- in line 435

IWRITE defined in line 64; used 1 times

- in line 488

LASTSIG defined in line 51; used 2 times

- in line 208, 223

PKILL defined in line 69; used 1 times

- in line 93

SSTEP defined in line 68; used 1 times

- in line 163

UREAD defined in line 61; used 9 times

- in line 262-279(9)

UWRITE defined in line 62; used 7 times

- in line 298-320(7)

U_AR0 defined in line 32; used 1 times

- in line 262

U_PAGE defined in line 31; used 1 times

- in line 263

WMASK defined in line 47; used 2 times

- in line 363, 379

cachehash defined in line 48; used 4 times

- in line 433, 447, 485, 494

ischild defined in line 52; used 1 times

- in line 99

istraced defined in line 55; used 2 times

- in line 149, 293

regloc defined in line 44; used 15 times

- in line 267-279(8), 298-320(7)

setrep defined in line 54; used 3 times

- in line 55, 179-181(2)

traceme defined in line 53; used 1 times

- in line 100

Last modified: 1985-06-06 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2280 |