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