Annotation of 42BSD/ucb/pascal/pdx/process/ptrace.c, revision 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.