Annotation of 42BSD/ucb/pascal/pdx/process/ptrace.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.