Annotation of 43BSDReno/pgrm/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.3 (Berkeley) 5/11/87";
        !             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: #       include "pxinfo.h"
        !            27: 
        !            28: #ifdef mc68000
        !            29: #      define U_PAGE 0x2400
        !            30: #      define U_AR0  (14*sizeof(int))
        !            31:        LOCAL int ar0val = -1;
        !            32: #endif
        !            33: 
        !            34: /*
        !            35:  * This magic macro enables us to look at the process' registers
        !            36:  * in its user structure.  Very gross.
        !            37:  */
        !            38: 
        !            39: #if defined(vax) || defined(tahoe)
        !            40: #      define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
        !            41: #else
        !            42: #      define regloc(reg)     (ar0val + ( sizeof(int) * (reg) ))
        !            43: #endif
        !            44: 
        !            45: #define WMASK           (~(sizeof(WORD) - 1))
        !            46: #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
        !            47: 
        !            48: #define ischild(pid)    ((pid) == 0)
        !            49: #define traceme()       ptrace(0, 0, 0, 0)
        !            50: #define setrep(n)       (1 << ((n)-1))
        !            51: #define istraced(p)     (p->sigset&setrep(p->signo))
        !            52: 
        !            53: /*
        !            54:  * ptrace options (specified in first argument)
        !            55:  */
        !            56: 
        !            57: #define UREAD   3       /* read from process's user structure */
        !            58: #define UWRITE  6       /* write to process's user structure */
        !            59: #define IREAD   1       /* read from process's instruction space */
        !            60: #define IWRITE  4       /* write to process's instruction space */
        !            61: #define DREAD   2       /* read from process's data space */
        !            62: #define DWRITE  5       /* write to process's data space */
        !            63: #define CONT    7       /* continue stopped process */
        !            64: #define SSTEP   9       /* continue for approximately one instruction */
        !            65: #define PKILL   8       /* terminate the process */
        !            66: 
        !            67: /*
        !            68:  * Start up a new process by forking and exec-ing the
        !            69:  * given argument list, returning when the process is loaded
        !            70:  * and ready to execute.  The PROCESS information (pointed to
        !            71:  * by the first argument) is appropriately filled.
        !            72:  *
        !            73:  * If the given PROCESS structure is associated with an already running
        !            74:  * process, we terminate it.
        !            75:  */
        !            76: 
        !            77: /* VARARGS2 */
        !            78: pstart(p, cmd, argv, infile, outfile)
        !            79: PROCESS *p;
        !            80: char *cmd;
        !            81: char **argv;
        !            82: char *infile;
        !            83: char *outfile;
        !            84: {
        !            85:     int status;
        !            86:     FILE *in, *out;
        !            87: 
        !            88:     if (p->pid != 0) {                  /* child already running? */
        !            89:        ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
        !            90:     }
        !            91: #ifdef tahoe
        !            92:     INTFP = (ADDRESS)0;
        !            93: #endif tahoe
        !            94:     psigtrace(p, SIGTRAP, TRUE);
        !            95:     if ((p->pid = fork()) == -1) {
        !            96:        panic("can't fork");
        !            97:     }
        !            98:     if (ischild(p->pid)) {
        !            99:        traceme();
        !           100:        if (infile != NIL) {
        !           101:            if ((in = fopen(infile, "r")) == NIL) {
        !           102:                printf("can't read %s\n", infile);
        !           103:                exit(1);
        !           104:            }
        !           105:            fswap(0, fileno(in));
        !           106:        }
        !           107:        if (outfile != NIL) {
        !           108:            if ((out = fopen(outfile, "w")) == NIL) {
        !           109:                printf("can't write %s\n", outfile);
        !           110:                exit(1);
        !           111:            }
        !           112:            fswap(1, fileno(out));
        !           113:        }
        !           114:        execvp(cmd, argv);
        !           115:        panic("can't exec %s", argv[0]);
        !           116:     }
        !           117:     pwait(p->pid, &status);
        !           118:     getinfo(p, status);
        !           119: }
        !           120: 
        !           121: /*
        !           122:  * Continue a stopped process.  The argument points to a PROCESS structure.
        !           123:  * Before the process is restarted it's user area is modified according to
        !           124:  * the values in the structure.  When this routine finishes,
        !           125:  * the structure has the new values from the process's user area.
        !           126:  *
        !           127:  * Pcont terminates when the process stops with a signal pending that
        !           128:  * is being traced (via psigtrace), or when the process terminates.
        !           129:  */
        !           130: 
        !           131: pcont(p)
        !           132: PROCESS *p;
        !           133: {
        !           134:     int status;
        !           135: 
        !           136:     if (p->pid == 0) {
        !           137:        error("program not active");
        !           138:     }
        !           139:     do {
        !           140:        setinfo(p);
        !           141:        sigs_off();
        !           142:        if (ptrace(CONT, p->pid, p->pc, p->signo) < 0) {
        !           143:            panic("can't continue process");
        !           144:        }
        !           145:        pwait(p->pid, &status);
        !           146:        sigs_on();
        !           147:        getinfo(p, status);
        !           148:     } while (p->status == STOPPED && !istraced(p));
        !           149: }
        !           150: 
        !           151: /*
        !           152:  * single step as best ptrace can
        !           153:  */
        !           154: 
        !           155: pstep(p)
        !           156: PROCESS *p;
        !           157: {
        !           158:     int status;
        !           159: 
        !           160:     setinfo(p);
        !           161:     sigs_off();
        !           162:     ptrace(SSTEP, p->pid, p->pc, p->signo);
        !           163:     pwait(p->pid, &status);
        !           164:     sigs_on();
        !           165:     getinfo(p, status);
        !           166: }
        !           167: 
        !           168: /*
        !           169:  * Return from execution when the given signal is pending.
        !           170:  */
        !           171: 
        !           172: psigtrace(p, sig, sw)
        !           173: PROCESS *p;
        !           174: int sig;
        !           175: int sw;
        !           176: {
        !           177:     if (sw) {
        !           178:        p->sigset |= setrep(sig);
        !           179:     } else {
        !           180:        p->sigset &= ~setrep(sig);
        !           181:     }
        !           182: }
        !           183: 
        !           184: /*
        !           185:  * Don't catch any signals.
        !           186:  * Particularly useful when letting a process finish uninhibited (i.e. px).
        !           187:  */
        !           188: 
        !           189: unsetsigtraces(p)
        !           190: PROCESS *p;
        !           191: {
        !           192:     p->sigset = 0;
        !           193: }
        !           194: 
        !           195: /*
        !           196:  * turn off attention to signals not being caught
        !           197:  */
        !           198: 
        !           199: typedef int INTFUNC();
        !           200: 
        !           201: LOCAL INTFUNC *onintr, *onquit;
        !           202: 
        !           203: LOCAL sigs_off()
        !           204: {
        !           205:     onintr = signal(SIGINT, SIG_IGN);
        !           206:     onquit = signal(SIGQUIT, SIG_IGN);
        !           207: }
        !           208: 
        !           209: /*
        !           210:  * turn back on attention to signals
        !           211:  */
        !           212: 
        !           213: LOCAL sigs_on()
        !           214: {
        !           215:     (void) signal(SIGINT, onintr);
        !           216:     (void) signal(SIGQUIT, onquit);
        !           217: }
        !           218: 
        !           219: /*
        !           220:  * get PROCESS information from process's user area
        !           221:  */
        !           222: 
        !           223: #if vax
        !           224:     LOCAL int rloc[] ={
        !           225:        R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11,
        !           226:     };
        !           227: #endif
        !           228: #if tahoe
        !           229:     LOCAL int rloc[] ={
        !           230:        R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12,
        !           231:     };
        !           232: #endif
        !           233: #if mc68000
        !           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: #if !defined(vax) && !defined(tahoe)
        !           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: #if defined(vax) || defined(tahoe)
        !           266:     p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(FP), 0);
        !           267:     p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
        !           268:     p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
        !           269: #endif
        !           270: #ifdef vax
        !           271:     p->ap = p->oap = ptrace(UREAD, p->pid, regloc(AP), 0);
        !           272: #endif
        !           273: #ifdef mc68000
        !           274:     p->fp = p->ofp = ptrace(UREAD, p->pid, regloc(AR6), 0);
        !           275:     p->ap = p->oap = p->fp;
        !           276:     p->sp = p->osp = ptrace(UREAD, p->pid, regloc(SP), 0);
        !           277:     p->pc = p->opc = ptrace(UREAD, p->pid, regloc(PC), 0);
        !           278: #endif
        !           279: }
        !           280: 
        !           281: /*
        !           282:  * set process's user area information from given PROCESS structure
        !           283:  */
        !           284: 
        !           285: LOCAL setinfo(p)
        !           286: register PROCESS *p;
        !           287: {
        !           288:     register int i;
        !           289:     register int r;
        !           290: 
        !           291:     if (istraced(p)) {
        !           292:        p->signo = 0;
        !           293:     }
        !           294:     for (i = 0; i < NREG; i++) {
        !           295:        if ((r = p->reg[i]) != p->oreg[i]) {
        !           296:            ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
        !           297:        }
        !           298:     }
        !           299: #if vax || tahoe
        !           300:     if ((r = p->fp) != p->ofp) {
        !           301:        ptrace(UWRITE, p->pid, regloc(FP), r);
        !           302:     }
        !           303: #endif
        !           304: #if vax
        !           305:     if ((r = p->ap) != p->oap) {
        !           306:        ptrace(UWRITE, p->pid, regloc(AP), r);
        !           307:     }
        !           308: #endif
        !           309: #if mc68000
        !           310:     if ((r = p->fp) != p->ofp) {
        !           311:        ptrace(UWRITE, p->pid, regloc(AR6), r);
        !           312:     }
        !           313: #endif
        !           314:     if ((r = p->sp) != p->osp) {
        !           315:        ptrace(UWRITE, p->pid, regloc(SP), r);
        !           316:     }
        !           317:     if ((r = p->pc) != p->opc) {
        !           318:        ptrace(UWRITE, p->pid, regloc(PC), r);
        !           319:     }
        !           320: }
        !           321: 
        !           322: /*
        !           323:  * Structure for reading and writing by words, but dealing with bytes.
        !           324:  */
        !           325: 
        !           326: typedef union {
        !           327:     WORD pword;
        !           328:     BYTE pbyte[sizeof(WORD)];
        !           329: } PWORD;
        !           330: 
        !           331: /*
        !           332:  * Read (write) from (to) the process' address space.
        !           333:  * We must deal with ptrace's inability to look anywhere other
        !           334:  * than at a word boundary.
        !           335:  */
        !           336: 
        !           337: LOCAL WORD fetch();
        !           338: LOCAL store();
        !           339: 
        !           340: pio(p, op, seg, buff, addr, nbytes)
        !           341: PROCESS *p;
        !           342: PIO_OP op;
        !           343: PIO_SEG seg;
        !           344: char *buff;
        !           345: ADDRESS addr;
        !           346: int nbytes;
        !           347: {
        !           348:     register int i, k;
        !           349:     register ADDRESS newaddr;
        !           350:     register char *cp;
        !           351:     char *bufend;
        !           352:     PWORD w;
        !           353:     ADDRESS wordaddr;
        !           354:     int byteoff;
        !           355: 
        !           356:     if (p->status != STOPPED) {
        !           357:        error("program is not active");
        !           358:     }
        !           359:     cp = buff;
        !           360:     newaddr = addr;
        !           361:     wordaddr = (newaddr&WMASK);
        !           362:     if (wordaddr != newaddr) {
        !           363:        w.pword = fetch(p, seg, wordaddr);
        !           364:        for (i = newaddr - wordaddr; i<sizeof(WORD) && nbytes>0; i++) {
        !           365:            if (op == PREAD) {
        !           366:                *cp++ = w.pbyte[i];
        !           367:            } else {
        !           368:                w.pbyte[i] = *cp++;
        !           369:            }
        !           370:            nbytes--;
        !           371:        }
        !           372:        if (op == PWRITE) {
        !           373:            store(p, seg, wordaddr, w.pword);
        !           374:        }
        !           375:        newaddr = wordaddr + sizeof(WORD);
        !           376:     }
        !           377:     byteoff = (nbytes&(~WMASK));
        !           378:     nbytes -= byteoff;
        !           379:     bufend = cp + nbytes;
        !           380:     while (cp < bufend) {
        !           381:        if (op == PREAD) {
        !           382:            w.pword = fetch(p, seg, newaddr);
        !           383:            for (k = 0; k < sizeof(WORD); k++) {
        !           384:                *cp++ = w.pbyte[k];
        !           385:            }
        !           386:        } else {
        !           387:            for (k = 0; k < sizeof(WORD); k++) {
        !           388:                w.pbyte[k] = *cp++;
        !           389:            }
        !           390:            store(p, seg, newaddr, w.pword);
        !           391:        }
        !           392:        newaddr += sizeof(WORD);
        !           393:     }
        !           394:     if (byteoff > 0) {
        !           395:        w.pword = fetch(p, seg, newaddr);
        !           396:        for (i = 0; i < byteoff; i++) {
        !           397:            if (op == PREAD) {
        !           398:                *cp++ = w.pbyte[i];
        !           399:            } else {
        !           400:                w.pbyte[i] = *cp++;
        !           401:            }
        !           402:        }
        !           403:        if (op == PWRITE) {
        !           404:            store(p, seg, newaddr, w.pword);
        !           405:        }
        !           406:     }
        !           407: }
        !           408: 
        !           409: /*
        !           410:  * Get a word from a process at the given address.
        !           411:  * The address is assumed to be on a word boundary.
        !           412:  *
        !           413:  * We use a simple cache scheme to avoid redundant references to
        !           414:  * the instruction space (which is assumed to be pure).  In the
        !           415:  * case of px, the "instruction" space lies between ENDOFF and
        !           416:  * ENDOFF + objsize.
        !           417:  *
        !           418:  * It is necessary to use a write-through scheme so that
        !           419:  * breakpoints right next to each other don't interfere.
        !           420:  */
        !           421: 
        !           422: LOCAL WORD fetch(p, seg, addr)
        !           423: PROCESS *p;
        !           424: PIO_SEG seg;
        !           425: register int addr;
        !           426: {
        !           427:     register CACHEWORD *wp;
        !           428:     register WORD w;
        !           429: 
        !           430:     switch (seg) {
        !           431:        case TEXTSEG:
        !           432:            panic("tried to fetch from px i-space");
        !           433:            /* NOTREACHED */
        !           434: 
        !           435:        case DATASEG:
        !           436:            if (addr >= ENDOFF && addr < ENDOFF + objsize) {
        !           437:                wp = &p->word[cachehash(addr)];
        !           438:                if (addr == 0 || wp->addr != addr) {
        !           439:                    w = ptrace(DREAD, p->pid, addr, 0);
        !           440:                    wp->addr = addr;
        !           441:                    wp->val = w;
        !           442:                } else {
        !           443:                    w = wp->val;
        !           444:                }
        !           445:            } else {
        !           446:                w = ptrace(DREAD, p->pid, addr, 0);
        !           447:            }
        !           448:            break;
        !           449: 
        !           450:        default:
        !           451:            panic("fetch: bad seg %d", seg);
        !           452:            /* NOTREACHED */
        !           453:     }
        !           454:     return(w);
        !           455: }
        !           456: 
        !           457: /*
        !           458:  * Put a word into the process' address space at the given address.
        !           459:  * The address is assumed to be on a word boundary.
        !           460:  */
        !           461: 
        !           462: LOCAL store(p, seg, addr, data)
        !           463: PROCESS *p;
        !           464: PIO_SEG seg;
        !           465: int addr;
        !           466: WORD data;
        !           467: {
        !           468:     register CACHEWORD *wp;
        !           469: 
        !           470:     switch (seg) {
        !           471:        case TEXTSEG:
        !           472:            wp = &p->word[cachehash(addr)];
        !           473:            wp->addr = addr;
        !           474:            wp->val = data;
        !           475:            ptrace(IWRITE, p->pid, addr, data);
        !           476:            break;
        !           477: 
        !           478:        case DATASEG:
        !           479:            if (addr >= ENDOFF && addr < ENDOFF + objsize) {
        !           480:                wp = &p->word[cachehash(addr)];
        !           481:                wp->addr = addr;
        !           482:                wp->val = data;
        !           483:            }
        !           484:            ptrace(DWRITE, p->pid, addr, data);
        !           485:            break;
        !           486: 
        !           487:        default:
        !           488:            panic("store: bad seg %d", seg);
        !           489:            /*NOTREACHED*/
        !           490:     }
        !           491: }
        !           492: 
        !           493: /*
        !           494:  * Initialize the instruction cache for a process.
        !           495:  * This is particularly necessary after the program has been remade.
        !           496:  */
        !           497: 
        !           498: initcache(process)
        !           499: PROCESS *process;
        !           500: {
        !           501:     register int i;
        !           502: 
        !           503:     for (i = 0; i < CSIZE; i++) {
        !           504:        process->word[i].addr = 0;
        !           505:     }
        !           506: }
        !           507: 
        !           508: /*
        !           509:  * Swap file numbers so as to redirect standard input and output.
        !           510:  */
        !           511: 
        !           512: LOCAL fswap(oldfd, newfd)
        !           513: int oldfd;
        !           514: int newfd;
        !           515: {
        !           516:     if (oldfd != newfd) {
        !           517:        close(oldfd);
        !           518:        dup(newfd);
        !           519:        close(newfd);
        !           520:     }
        !           521: }
        !           522: 
        !           523: #ifdef tahoe
        !           524: BOOLEAN didret;
        !           525: 
        !           526: void
        !           527: chkret(p, status)
        !           528: PROCESS *p;
        !           529: int status;
        !           530: {
        !           531:        if (((status == (SIGILL << 8) | STOPPED) ||
        !           532:            (status == (SIGTRAP << 8) | STOPPED))) {
        !           533:                didret = FALSE;
        !           534:        } else {
        !           535:                didret = TRUE;
        !           536:        }
        !           537: }
        !           538: 
        !           539: void
        !           540: doret(p)
        !           541: PROCESS *p;
        !           542: {
        !           543:        register count = 0;
        !           544: 
        !           545:        if (!didret) {
        !           546:            do {
        !           547:                if (++count > 5) {
        !           548:                    panic("px would not return to interpreter");
        !           549:                }
        !           550:                p->pc = RETLOC;
        !           551:                pstep(p);
        !           552:            } while(INTFP && p->fp != INTFP);
        !           553:            didret = TRUE;
        !           554:        }
        !           555: }
        !           556: #endif

unix.superglobalmegacorp.com

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