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

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

unix.superglobalmegacorp.com

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