Annotation of 43BSDTahoe/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.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.