Annotation of 43BSD/ucb/dbx/process.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1983 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[] = "@(#)process.c  5.1 (Berkeley) 5/31/85";
                      9: #endif not lint
                     10: 
                     11: static char rcsid[] = "$Header: process.c,v 1.5 84/12/26 10:41:37 linton Exp $";
                     12: 
                     13: /*
                     14:  * Process management.
                     15:  *
                     16:  * This module contains the routines to manage the execution and
                     17:  * tracing of the debuggee process.
                     18:  */
                     19: 
                     20: #include "defs.h"
                     21: #include "process.h"
                     22: #include "machine.h"
                     23: #include "events.h"
                     24: #include "tree.h"
                     25: #include "eval.h"
                     26: #include "operators.h"
                     27: #include "source.h"
                     28: #include "object.h"
                     29: #include "mappings.h"
                     30: #include "main.h"
                     31: #include "coredump.h"
                     32: #include <signal.h>
                     33: #include <errno.h>
                     34: #include <sys/param.h>
                     35: #include <sys/dir.h>
                     36: #include <sys/user.h>
                     37: #include <machine/reg.h>
                     38: #include <sys/stat.h>
                     39: 
                     40: #ifndef public
                     41: 
                     42: typedef struct Process *Process;
                     43: 
                     44: Process process;
                     45: 
                     46: #define DEFSIG -1
                     47: 
                     48: #include "machine.h"
                     49: 
                     50: #endif
                     51: 
                     52: #define NOTSTARTED 1
                     53: #define STOPPED 0177
                     54: #define FINISHED 0
                     55: 
                     56: /*
                     57:  * A cache of the instruction segment is kept to reduce the number
                     58:  * of system calls.  Might be better just to read the entire
                     59:  * code space into memory.
                     60:  */
                     61: 
                     62: #define CSIZE 1003       /* size of instruction cache */
                     63: 
                     64: typedef struct {
                     65:     Word addr;
                     66:     Word val;
                     67: } CacheWord;
                     68: 
                     69: /*
                     70:  * This structure holds the information we need from the user structure.
                     71:  */
                     72: 
                     73: struct Process {
                     74:     int pid;                   /* process being traced */
                     75:     int mask;                  /* process status word */
                     76:     Word reg[NREG];            /* process' registers */
                     77:     Word oreg[NREG];           /* registers when process last stopped */
                     78:     short status;              /* either STOPPED or FINISHED */
                     79:     short signo;               /* signal that stopped process */
                     80:     short sigcode;             /* extra signal information */
                     81:     int exitval;               /* return value from exit() */
                     82:     long sigset;               /* bit array of traced signals */
                     83:     CacheWord word[CSIZE];     /* text segment cache */
                     84:     Ttyinfo ttyinfo;           /* process' terminal characteristics */
                     85:     Address sigstatus;         /* process' handler for current signal */
                     86: };
                     87: 
                     88: /*
                     89:  * These definitions are for the arguments to "pio".
                     90:  */
                     91: 
                     92: typedef enum { PREAD, PWRITE } PioOp;
                     93: typedef enum { TEXTSEG, DATASEG } PioSeg;
                     94: 
                     95: private struct Process pbuf;
                     96: 
                     97: #define MAXNCMDARGS 1000         /* maximum number of arguments to RUN */
                     98: 
                     99: extern int errno;
                    100: 
                    101: private Boolean just_started;
                    102: private int argc;
                    103: private String argv[MAXNCMDARGS];
                    104: private String infile, outfile;
                    105: 
                    106: /*
                    107:  * Initialize process information.
                    108:  */
                    109: 
                    110: public process_init()
                    111: {
                    112:     register Integer i;
                    113:     Char buf[10];
                    114: 
                    115:     process = &pbuf;
                    116:     process->status = (coredump) ? STOPPED : NOTSTARTED;
                    117:     setsigtrace();
                    118:     for (i = 0; i < NREG; i++) {
                    119:        sprintf(buf, "$r%d", i);
                    120:        defregname(identname(buf, false), i);
                    121:     }
                    122:     defregname(identname("$ap", true), ARGP);
                    123:     defregname(identname("$fp", true), FRP);
                    124:     defregname(identname("$sp", true), STKP);
                    125:     defregname(identname("$pc", true), PROGCTR);
                    126:     if (coredump) {
                    127:        coredump_readin(process->mask, process->reg, process->signo);
                    128:        pc = process->reg[PROGCTR];
                    129:        getsrcpos();
                    130:     }
                    131:     arginit();
                    132: }
                    133: 
                    134: /*
                    135:  * Routines to get at process information from outside this module.
                    136:  */
                    137: 
                    138: public Word reg(n)
                    139: Integer n;
                    140: {
                    141:     register Word w;
                    142: 
                    143:     if (n == NREG) {
                    144:        w = process->mask;
                    145:     } else {
                    146:        w = process->reg[n];
                    147:     }
                    148:     return w;
                    149: }
                    150: 
                    151: public setreg(n, w)
                    152: Integer n;
                    153: Word w;
                    154: {
                    155:     process->reg[n] = w;
                    156: }
                    157: 
                    158: /*
                    159:  * Begin execution.
                    160:  *
                    161:  * We set a breakpoint at the end of the code so that the
                    162:  * process data doesn't disappear after the program terminates.
                    163:  */
                    164: 
                    165: private Boolean remade();
                    166: 
                    167: public start(argv, infile, outfile)
                    168: String argv[];
                    169: String infile, outfile;
                    170: {
                    171:     String pargv[4];
                    172:     Node cond;
                    173: 
                    174:     if (coredump) {
                    175:        coredump = false;
                    176:        fclose(corefile);
                    177:        coredump_close();
                    178:     }
                    179:     if (argv == nil) {
                    180:        argv = pargv;
                    181:        pargv[0] = objname;
                    182:        pargv[1] = nil;
                    183:     } else {
                    184:        argv[argc] = nil;
                    185:     }
                    186:     pstart(process, argv, infile, outfile);
                    187:     if (remade(objname)) {
                    188:        reinit(argv, infile, outfile);
                    189:     }
                    190:     if (process->status == STOPPED) {
                    191:        pc = 0;
                    192:        setcurfunc(program);
                    193:        if (objsize != 0) {
                    194:            cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
                    195:            event_once(cond, buildcmdlist(build(O_ENDX)));
                    196:        }
                    197:     }
                    198: }
                    199: 
                    200: /*
                    201:  * Check to see if the object file has changed since the symbolic
                    202:  * information last was read.
                    203:  */
                    204: 
                    205: private time_t modtime;
                    206: 
                    207: private Boolean remade(filename)
                    208: String filename;
                    209: {
                    210:     struct stat s;
                    211:     Boolean b;
                    212: 
                    213:     stat(filename, &s);
                    214:     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
                    215:     modtime = s.st_mtime;
                    216:     return b;
                    217: }
                    218: 
                    219: /*
                    220:  * Set up what signals we want to trace.
                    221:  */
                    222: 
                    223: private setsigtrace()
                    224: {
                    225:     register Integer i;
                    226:     register Process p;
                    227: 
                    228:     p = process;
                    229:     for (i = 1; i <= NSIG; i++) {
                    230:        psigtrace(p, i, true);
                    231:     }
                    232:     psigtrace(p, SIGHUP, false);
                    233:     psigtrace(p, SIGKILL, false);
                    234:     psigtrace(p, SIGALRM, false);
                    235:     psigtrace(p, SIGTSTP, false);
                    236:     psigtrace(p, SIGCONT, false);
                    237:     psigtrace(p, SIGCHLD, false);
                    238: }
                    239: 
                    240: /*
                    241:  * Initialize the argument list.
                    242:  */
                    243: 
                    244: public arginit()
                    245: {
                    246:     infile = nil;
                    247:     outfile = nil;
                    248:     argv[0] = objname;
                    249:     argc = 1;
                    250: }
                    251: 
                    252: /*
                    253:  * Add an argument to the list for the debuggee.
                    254:  */
                    255: 
                    256: public newarg(arg)
                    257: String arg;
                    258: {
                    259:     if (argc >= MAXNCMDARGS) {
                    260:        error("too many arguments");
                    261:     }
                    262:     argv[argc++] = arg;
                    263: }
                    264: 
                    265: /*
                    266:  * Set the standard input for the debuggee.
                    267:  */
                    268: 
                    269: public inarg(filename)
                    270: String filename;
                    271: {
                    272:     if (infile != nil) {
                    273:        error("multiple input redirects");
                    274:     }
                    275:     infile = filename;
                    276: }
                    277: 
                    278: /*
                    279:  * Set the standard output for the debuggee.
                    280:  * Probably should check to avoid overwriting an existing file.
                    281:  */
                    282: 
                    283: public outarg(filename)
                    284: String filename;
                    285: {
                    286:     if (outfile != nil) {
                    287:        error("multiple output redirect");
                    288:     }
                    289:     outfile = filename;
                    290: }
                    291: 
                    292: /*
                    293:  * Start debuggee executing.
                    294:  */
                    295: 
                    296: public run()
                    297: {
                    298:     process->status = STOPPED;
                    299:     fixbps();
                    300:     curline = 0;
                    301:     start(argv, infile, outfile);
                    302:     just_started = true;
                    303:     isstopped = false;
                    304:     cont(0);
                    305: }
                    306: 
                    307: /*
                    308:  * Continue execution wherever we left off.
                    309:  *
                    310:  * Note that this routine never returns.  Eventually bpact() will fail
                    311:  * and we'll call printstatus or step will call it.
                    312:  */
                    313: 
                    314: typedef int Intfunc();
                    315: 
                    316: private Intfunc *dbintr;
                    317: private intr();
                    318: 
                    319: public cont(signo)
                    320: integer signo;
                    321: {
                    322:     integer s;
                    323: 
                    324:     dbintr = signal(SIGINT, intr);
                    325:     if (just_started) {
                    326:        just_started = false;
                    327:     } else {
                    328:        if (not isstopped) {
                    329:            error("can't continue execution");
                    330:        }
                    331:        isstopped = false;
                    332:        stepover();
                    333:     }
                    334:     s = signo;
                    335:     for (;;) {
                    336:        if (single_stepping) {
                    337:            printnews();
                    338:        } else {
                    339:            setallbps();
                    340:            resume(s);
                    341:            unsetallbps();
                    342:            s = DEFSIG;
                    343:            if (not isbperr() or not bpact()) {
                    344:                printstatus();
                    345:            }
                    346:        }
                    347:        stepover();
                    348:     }
                    349:     /* NOTREACHED */
                    350: }
                    351: 
                    352: /*
                    353:  * This routine is called if we get an interrupt while "running"
                    354:  * but actually in the debugger.  Could happen, for example, while
                    355:  * processing breakpoints.
                    356:  *
                    357:  * We basically just want to keep going; the assumption is
                    358:  * that when the process resumes it will get the interrupt,
                    359:  * which will then be handled.
                    360:  */
                    361: 
                    362: private intr()
                    363: {
                    364:     signal(SIGINT, intr);
                    365: }
                    366: 
                    367: public fixintr()
                    368: {
                    369:     signal(SIGINT, dbintr);
                    370: }
                    371: 
                    372: /*
                    373:  * Resume execution.
                    374:  */
                    375: 
                    376: public resume(signo)
                    377: int signo;
                    378: {
                    379:     register Process p;
                    380: 
                    381:     p = process;
                    382:     pcont(p, signo);
                    383:     pc = process->reg[PROGCTR];
                    384:     if (p->status != STOPPED) {
                    385:        if (p->signo != 0) {
                    386:            error("program terminated by signal %d", p->signo);
                    387:        } else if (not runfirst) {
                    388:            if (p->exitval == 0) {
                    389:                error("program exited");
                    390:            } else {
                    391:                error("program exited with code %d", p->exitval);
                    392:            }
                    393:        }
                    394:     }
                    395: }
                    396: 
                    397: /*
                    398:  * Continue execution up to the next source line.
                    399:  *
                    400:  * There are two ways to define the next source line depending on what
                    401:  * is desired when a procedure or function call is encountered.  Step
                    402:  * stops at the beginning of the procedure or call; next skips over it.
                    403:  */
                    404: 
                    405: /*
                    406:  * Stepc is what is called when the step command is given.
                    407:  * It has to play with the "isstopped" information.
                    408:  */
                    409: 
                    410: public stepc()
                    411: {
                    412:     if (not isstopped) {
                    413:        error("can't continue execution");
                    414:     }
                    415:     isstopped = false;
                    416:     dostep(false);
                    417:     isstopped = true;
                    418: }
                    419: 
                    420: public next()
                    421: {
                    422:     Address oldfrp, newfrp;
                    423: 
                    424:     if (not isstopped) {
                    425:        error("can't continue execution");
                    426:     }
                    427:     isstopped = false;
                    428:     oldfrp = reg(FRP);
                    429:     do {
                    430:        dostep(true);
                    431:        pc = reg(PROGCTR);
                    432:        newfrp = reg(FRP);
                    433:     } while (newfrp < oldfrp and newfrp != 0);
                    434:     isstopped = true;
                    435: }
                    436: 
                    437: /*
                    438:  * Continue execution until the current function returns, or,
                    439:  * if the given argument is non-nil, until execution returns to
                    440:  * somewhere within the given function.
                    441:  */
                    442: 
                    443: public rtnfunc (f)
                    444: Symbol f;
                    445: {
                    446:     Address addr;
                    447:     Symbol t;
                    448: 
                    449:     if (not isstopped) {
                    450:        error("can't continue execution");
                    451:     } else if (f != nil and not isactive(f)) {
                    452:        error("%s is not active", symname(f));
                    453:     } else {
                    454:        addr = return_addr();
                    455:        if (addr == nil) {
                    456:            error("no place to return to");
                    457:        } else {
                    458:            isstopped = false;
                    459:            contto(addr);
                    460:            if (f != nil) {
                    461:                for (;;) {
                    462:                    t = whatblock(pc);
                    463:                    addr = return_addr();
                    464:                if (t == f or addr == nil) break;
                    465:                    contto(addr);
                    466:                }
                    467:            }
                    468:            if (not bpact()) {
                    469:                isstopped = true;
                    470:                printstatus();
                    471:            }
                    472:        }
                    473:     }
                    474: }
                    475: 
                    476: /*
                    477:  * Single-step over the current machine instruction.
                    478:  *
                    479:  * If we're single-stepping by source line we want to step to the
                    480:  * next source line.  Otherwise we're going to continue so there's
                    481:  * no reason to do all the work necessary to single-step to the next
                    482:  * source line.
                    483:  */
                    484: 
                    485: public stepover()
                    486: {
                    487:     Boolean b;
                    488: 
                    489:     if (traceexec) {
                    490:        printf("!! stepping over 0x%x\n", process->reg[PROGCTR]);
                    491:     }
                    492:     if (single_stepping) {
                    493:        dostep(false);
                    494:     } else {
                    495:        b = inst_tracing;
                    496:        inst_tracing = true;
                    497:        dostep(false);
                    498:        inst_tracing = b;
                    499:     }
                    500:     if (traceexec) {
                    501:        printf("!! stepped over to 0x%x\n", process->reg[PROGCTR]);
                    502:     }
                    503: }
                    504: 
                    505: /*
                    506:  * Resume execution up to the given address.  We can either ignore
                    507:  * breakpoints (stepto) or catch them (contto).
                    508:  */
                    509: 
                    510: public stepto(addr)
                    511: Address addr;
                    512: {
                    513:     xto(addr, false);
                    514: }
                    515: 
                    516: private contto (addr)
                    517: Address addr;
                    518: {
                    519:     xto(addr, true);
                    520: }
                    521: 
                    522: private xto (addr, catchbps)
                    523: Address addr;
                    524: boolean catchbps;
                    525: {
                    526:     Address curpc;
                    527: 
                    528:     if (catchbps) {
                    529:        stepover();
                    530:     }
                    531:     curpc = process->reg[PROGCTR];
                    532:     if (addr != curpc) {
                    533:        if (traceexec) {
                    534:            printf("!! stepping from 0x%x to 0x%x\n", curpc, addr);
                    535:        }
                    536:        if (catchbps) {
                    537:            setallbps();
                    538:        }
                    539:        setbp(addr);
                    540:        resume(DEFSIG);
                    541:        unsetbp(addr);
                    542:        if (catchbps) {
                    543:            unsetallbps();
                    544:        }
                    545:        if (not isbperr()) {
                    546:            printstatus();
                    547:        }
                    548:     }
                    549: }
                    550: 
                    551: /*
                    552:  * Print the status of the process.
                    553:  * This routine does not return.
                    554:  */
                    555: 
                    556: public printstatus()
                    557: {
                    558:     int status;
                    559: 
                    560:     if (process->status == FINISHED) {
                    561:        exit(0);
                    562:     } else {
                    563:        setcurfunc(whatblock(pc));
                    564:        getsrcpos();
                    565:        if (process->signo == SIGINT) {
                    566:            isstopped = true;
                    567:            printerror();
                    568:        } else if (isbperr() and isstopped) {
                    569:            printf("stopped ");
                    570:            printloc();
                    571:            putchar('\n');
                    572:            if (curline > 0) {
                    573:                printlines(curline, curline);
                    574:            } else {
                    575:                printinst(pc, pc);
                    576:            }
                    577:            erecover();
                    578:        } else {
                    579:            fixintr();
                    580:            isstopped = true;
                    581:            printerror();
                    582:        }
                    583:     }
                    584: }
                    585: 
                    586: /*
                    587:  * Print out the current location in the debuggee.
                    588:  */
                    589: 
                    590: public printloc()
                    591: {
                    592:     printf("in ");
                    593:     printname(stdout, curfunc);
                    594:     putchar(' ');
                    595:     if (curline > 0 and not useInstLoc) {
                    596:        printsrcpos();
                    597:     } else {
                    598:        useInstLoc = false;
                    599:        curline = 0;
                    600:        printf("at 0x%x", pc);
                    601:     }
                    602: }
                    603: 
                    604: /*
                    605:  * Some functions for testing the state of the process.
                    606:  */
                    607: 
                    608: public Boolean notstarted(p)
                    609: Process p;
                    610: {
                    611:     return (Boolean) (p->status == NOTSTARTED);
                    612: }
                    613: 
                    614: public Boolean isfinished(p)
                    615: Process p;
                    616: {
                    617:     return (Boolean) (p->status == FINISHED);
                    618: }
                    619: 
                    620: /*
                    621:  * Predicate to test if the reason the process stopped was because
                    622:  * of a breakpoint.  If so, as a side effect clear the local copy of
                    623:  * signal handler associated with process.  We must do this so as to
                    624:  * not confuse future stepping or continuing by possibly concluding
                    625:  * the process should continue with a SIGTRAP handler.
                    626:  */
                    627: 
                    628: public boolean isbperr()
                    629: {
                    630:     Process p;
                    631:     boolean b;
                    632: 
                    633:     p = process;
                    634:     if (p->status == STOPPED and p->signo == SIGTRAP) {
                    635:        b = true;
                    636:        p->sigstatus = 0;
                    637:     } else {
                    638:        b = false;
                    639:     }
                    640:     return b;
                    641: }
                    642: 
                    643: /*
                    644:  * Return the signal number that stopped the process.
                    645:  */
                    646: 
                    647: public integer errnum (p)
                    648: Process p;
                    649: {
                    650:     return p->signo;
                    651: }
                    652: 
                    653: /*
                    654:  * Return the signal code associated with the signal.
                    655:  */
                    656: 
                    657: public integer errcode (p)
                    658: Process p;
                    659: {
                    660:     return p->sigcode;
                    661: }
                    662: 
                    663: /*
                    664:  * Return the termination code of the process.
                    665:  */
                    666: 
                    667: public integer exitcode (p)
                    668: Process p;
                    669: {
                    670:     return p->exitval;
                    671: }
                    672: 
                    673: /*
                    674:  * These routines are used to access the debuggee process from
                    675:  * outside this module.
                    676:  *
                    677:  * They invoke "pio" which eventually leads to a call to "ptrace".
                    678:  * The system generates an I/O error when a ptrace fails.  During reads
                    679:  * these are ignored, during writes they are reported as an error, and
                    680:  * for anything else they cause a fatal error.
                    681:  */
                    682: 
                    683: extern Intfunc *onsyserr();
                    684: 
                    685: private badaddr;
                    686: private read_err(), write_err();
                    687: 
                    688: /*
                    689:  * Read from the process' instruction area.
                    690:  */
                    691: 
                    692: public iread(buff, addr, nbytes)
                    693: char *buff;
                    694: Address addr;
                    695: int nbytes;
                    696: {
                    697:     Intfunc *f;
                    698: 
                    699:     f = onsyserr(EIO, read_err);
                    700:     badaddr = addr;
                    701:     if (coredump) {
                    702:        coredump_readtext(buff, addr, nbytes);
                    703:     } else {
                    704:        pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
                    705:     }
                    706:     onsyserr(EIO, f);
                    707: }
                    708: 
                    709: /* 
                    710:  * Write to the process' instruction area, usually in order to set
                    711:  * or unset a breakpoint.
                    712:  */
                    713: 
                    714: public iwrite(buff, addr, nbytes)
                    715: char *buff;
                    716: Address addr;
                    717: int nbytes;
                    718: {
                    719:     Intfunc *f;
                    720: 
                    721:     if (coredump) {
                    722:        error("no process to write to");
                    723:     }
                    724:     f = onsyserr(EIO, write_err);
                    725:     badaddr = addr;
                    726:     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
                    727:     onsyserr(EIO, f);
                    728: }
                    729: 
                    730: /*
                    731:  * Read for the process' data area.
                    732:  */
                    733: 
                    734: public dread(buff, addr, nbytes)
                    735: char *buff;
                    736: Address addr;
                    737: int nbytes;
                    738: {
                    739:     Intfunc *f;
                    740: 
                    741:     badaddr = addr;
                    742:     if (coredump) {
                    743:        f = onsyserr(EFAULT, read_err);
                    744:        coredump_readdata(buff, addr, nbytes);
                    745:        onsyserr(EFAULT, f);
                    746:     } else {
                    747:        f = onsyserr(EIO, read_err);
                    748:        pio(process, PREAD, DATASEG, buff, addr, nbytes);
                    749:        onsyserr(EIO, f);
                    750:     }
                    751: }
                    752: 
                    753: /*
                    754:  * Write to the process' data area.
                    755:  */
                    756: 
                    757: public dwrite(buff, addr, nbytes)
                    758: char *buff;
                    759: Address addr;
                    760: int nbytes;
                    761: {
                    762:     Intfunc *f;
                    763: 
                    764:     if (coredump) {
                    765:        error("no process to write to");
                    766:     }
                    767:     f = onsyserr(EIO, write_err);
                    768:     badaddr = addr;
                    769:     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
                    770:     onsyserr(EIO, f);
                    771: }
                    772: 
                    773: /*
                    774:  * Trap for errors in reading or writing to a process.
                    775:  * The current approach is to "ignore" read errors and complain
                    776:  * bitterly about write errors.
                    777:  */
                    778: 
                    779: private read_err()
                    780: {
                    781:     /*
                    782:      * Ignore.
                    783:      */
                    784: }
                    785: 
                    786: private write_err()
                    787: {
                    788:     error("can't write to process (address 0x%x)", badaddr);
                    789: }
                    790: 
                    791: /*
                    792:  * Ptrace interface.
                    793:  */
                    794: 
                    795: /*
                    796:  * This magic macro enables us to look at the process' registers
                    797:  * in its user structure.
                    798:  */
                    799: 
                    800: #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
                    801: 
                    802: #define WMASK           (~(sizeof(Word) - 1))
                    803: #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
                    804: 
                    805: #define FIRSTSIG        SIGINT
                    806: #define LASTSIG         SIGQUIT
                    807: #define ischild(pid)    ((pid) == 0)
                    808: #define traceme()       ptrace(0, 0, 0, 0)
                    809: #define setrep(n)       (1 << ((n)-1))
                    810: #define istraced(p)     (p->sigset&setrep(p->signo))
                    811: 
                    812: /*
                    813:  * Ptrace options (specified in first argument).
                    814:  */
                    815: 
                    816: #define UREAD   3       /* read from process's user structure */
                    817: #define UWRITE  6       /* write to process's user structure */
                    818: #define IREAD   1       /* read from process's instruction space */
                    819: #define IWRITE  4       /* write to process's instruction space */
                    820: #define DREAD   2       /* read from process's data space */
                    821: #define DWRITE  5       /* write to process's data space */
                    822: #define CONT    7       /* continue stopped process */
                    823: #define SSTEP   9       /* continue for approximately one instruction */
                    824: #define PKILL   8       /* terminate the process */
                    825: 
                    826: /*
                    827:  * Start up a new process by forking and exec-ing the
                    828:  * given argument list, returning when the process is loaded
                    829:  * and ready to execute.  The PROCESS information (pointed to
                    830:  * by the first argument) is appropriately filled.
                    831:  *
                    832:  * If the given PROCESS structure is associated with an already running
                    833:  * process, we terminate it.
                    834:  */
                    835: 
                    836: /* VARARGS2 */
                    837: private pstart(p, argv, infile, outfile)
                    838: Process p;
                    839: String argv[];
                    840: String infile;
                    841: String outfile;
                    842: {
                    843:     int status;
                    844: 
                    845:     if (p->pid != 0) {
                    846:        pterm(p);
                    847:        cacheflush(p);
                    848:     }
                    849:     fflush(stdout);
                    850:     psigtrace(p, SIGTRAP, true);
                    851:     p->pid = vfork();
                    852:     if (p->pid == -1) {
                    853:        panic("can't fork");
                    854:     }
                    855:     if (ischild(p->pid)) {
                    856:        nocatcherrs();
                    857:        traceme();
                    858:        if (infile != nil) {
                    859:            infrom(infile);
                    860:        }
                    861:        if (outfile != nil) {
                    862:            outto(outfile);
                    863:        }
                    864:        execv(argv[0], argv);
                    865:        _exit(1);
                    866:     }
                    867:     pwait(p->pid, &status);
                    868:     getinfo(p, status);
                    869:     if (p->status != STOPPED) {
                    870:        beginerrmsg();
                    871:        fprintf(stderr, "warning: cannot execute %s\n", argv[0]);
                    872:     } else {
                    873:        ptraced(p->pid);
                    874:     }
                    875: }
                    876: 
                    877: /*
                    878:  * Terminate a ptrace'd process.
                    879:  */
                    880: 
                    881: public pterm (p)
                    882: Process p;
                    883: {
                    884:     integer status;
                    885: 
                    886:     if (p != nil and p->pid != 0) {
                    887:        ptrace(PKILL, p->pid, 0, 0);
                    888:        pwait(p->pid, &status);
                    889:        unptraced(p->pid);
                    890:     }
                    891: }
                    892: 
                    893: /*
                    894:  * Continue a stopped process.  The first argument points to a Process
                    895:  * structure.  Before the process is restarted it's user area is modified
                    896:  * according to the values in the structure.  When this routine finishes,
                    897:  * the structure has the new values from the process's user area.
                    898:  *
                    899:  * Pcont terminates when the process stops with a signal pending that
                    900:  * is being traced (via psigtrace), or when the process terminates.
                    901:  */
                    902: 
                    903: private pcont(p, signo)
                    904: Process p;
                    905: int signo;
                    906: {
                    907:     int s, status;
                    908: 
                    909:     if (p->pid == 0) {
                    910:        error("program is not active");
                    911:     }
                    912:     s = signo;
                    913:     do {
                    914:        setinfo(p, s);
                    915:        if (traceexec) {
                    916:            printf("!! pcont from 0x%x with signal %d (%d)\n",
                    917:                p->reg[PROGCTR], s, p->signo);
                    918:            fflush(stdout);
                    919:        }
                    920:        sigs_off();
                    921:        if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
                    922:            panic("error %d trying to continue process", errno);
                    923:        }
                    924:        pwait(p->pid, &status);
                    925:        sigs_on();
                    926:        getinfo(p, status);
                    927:        if (p->status == STOPPED and traceexec and not istraced(p)) {
                    928:            printf("!! ignored signal %d at 0x%x\n",
                    929:                p->signo, p->reg[PROGCTR]);
                    930:            fflush(stdout);
                    931:        }
                    932:        s = p->signo;
                    933:     } while (p->status == STOPPED and not istraced(p));
                    934:     if (traceexec) {
                    935:        printf("!! pcont to 0x%x on signal %d\n", p->reg[PROGCTR], p->signo);
                    936:        fflush(stdout);
                    937:     }
                    938: }
                    939: 
                    940: /*
                    941:  * Single step as best ptrace can.
                    942:  */
                    943: 
                    944: public pstep(p, signo)
                    945: Process p;
                    946: integer signo;
                    947: {
                    948:     int s, status;
                    949: 
                    950:     s = signo;
                    951:     do {
                    952:        setinfo(p, s);
                    953:        if (traceexec) {
                    954:            printf("!! pstep from 0x%x with signal %d (%d)\n",
                    955:                p->reg[PROGCTR], s, p->signo);
                    956:            fflush(stdout);
                    957:        }
                    958:        sigs_off();
                    959:        if (ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo) < 0) {
                    960:            panic("error %d trying to step process", errno);
                    961:        }
                    962:        pwait(p->pid, &status);
                    963:        sigs_on();
                    964:        getinfo(p, status);
                    965:        if (p->status == STOPPED and traceexec and not istraced(p)) {
                    966:            printf("!! pstep ignored signal %d at 0x%x\n",
                    967:                p->signo, p->reg[PROGCTR]);
                    968:            fflush(stdout);
                    969:        }
                    970:        s = p->signo;
                    971:     } while (p->status == STOPPED and not istraced(p));
                    972:     if (traceexec) {
                    973:        printf("!! pstep to 0x%x on signal %d\n",
                    974:            p->reg[PROGCTR], p->signo);
                    975:        fflush(stdout);
                    976:     }
                    977:     if (p->status != STOPPED) {
                    978:        if (p->exitval == 0) {
                    979:            error("program exited\n");
                    980:        } else {
                    981:            error("program exited with code %d\n", p->exitval);
                    982:        }
                    983:     }
                    984: }
                    985: 
                    986: /*
                    987:  * Return from execution when the given signal is pending.
                    988:  */
                    989: 
                    990: public psigtrace(p, sig, sw)
                    991: Process p;
                    992: int sig;
                    993: Boolean sw;
                    994: {
                    995:     if (sw) {
                    996:        p->sigset |= setrep(sig);
                    997:     } else {
                    998:        p->sigset &= ~setrep(sig);
                    999:     }
                   1000: }
                   1001: 
                   1002: /*
                   1003:  * Don't catch any signals.
                   1004:  * Particularly useful when letting a process finish uninhibited.
                   1005:  */
                   1006: 
                   1007: public unsetsigtraces(p)
                   1008: Process p;
                   1009: {
                   1010:     p->sigset = 0;
                   1011: }
                   1012: 
                   1013: /*
                   1014:  * Turn off attention to signals not being caught.
                   1015:  */
                   1016: 
                   1017: private Intfunc *sigfunc[NSIG];
                   1018: 
                   1019: private sigs_off()
                   1020: {
                   1021:     register int i;
                   1022: 
                   1023:     for (i = FIRSTSIG; i < LASTSIG; i++) {
                   1024:        if (i != SIGKILL) {
                   1025:            sigfunc[i] = signal(i, SIG_IGN);
                   1026:        }
                   1027:     }
                   1028: }
                   1029: 
                   1030: /*
                   1031:  * Turn back on attention to signals.
                   1032:  */
                   1033: 
                   1034: private sigs_on()
                   1035: {
                   1036:     register int i;
                   1037: 
                   1038:     for (i = FIRSTSIG; i < LASTSIG; i++) {
                   1039:        if (i != SIGKILL) {
                   1040:            signal(i, sigfunc[i]);
                   1041:        }
                   1042:     }
                   1043: }
                   1044: 
                   1045: /*
                   1046:  * Get process information from user area.
                   1047:  */
                   1048: 
                   1049: private int rloc[] ={
                   1050:     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
                   1051: };
                   1052: 
                   1053: private getinfo(p, status)
                   1054: register Process p;
                   1055: register int status;
                   1056: {
                   1057:     register int i;
                   1058:     Address addr;
                   1059: 
                   1060:     p->signo = (status&0177);
                   1061:     p->exitval = ((status >> 8)&0377);
                   1062:     if (p->signo != STOPPED) {
                   1063:        p->status = FINISHED;
                   1064:        p->pid = 0;
                   1065:        p->reg[PROGCTR] = 0;
                   1066:     } else {
                   1067:        p->status = p->signo;
                   1068:        p->signo = p->exitval;
                   1069:        p->sigcode = ptrace(UREAD, p->pid, &((struct user *) 0)->u_code, 0);
                   1070:        p->exitval = 0;
                   1071:        p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
                   1072:        for (i = 0; i < NREG; i++) {
                   1073:            p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
                   1074:            p->oreg[i] = p->reg[i];
                   1075:        }
                   1076:        savetty(stdout, &(p->ttyinfo));
                   1077:        addr = (Address) &(((struct user *) 0)->u_signal[p->signo]);
                   1078:        p->sigstatus = (Address) ptrace(UREAD, p->pid, addr, 0);
                   1079:     }
                   1080: }
                   1081: 
                   1082: /*
                   1083:  * Set process's user area information from given process structure.
                   1084:  */
                   1085: 
                   1086: private setinfo(p, signo)
                   1087: register Process p;
                   1088: int signo;
                   1089: {
                   1090:     register int i;
                   1091:     register int r;
                   1092: 
                   1093:     if (signo == DEFSIG) {
                   1094:        if (istraced(p) and (p->sigstatus == 0 or p->sigstatus == 1)) {
                   1095:            p->signo = 0;
                   1096:        }
                   1097:     } else {
                   1098:        p->signo = signo;
                   1099:     }
                   1100:     for (i = 0; i < NREG; i++) {
                   1101:        if ((r = p->reg[i]) != p->oreg[i]) {
                   1102:            ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
                   1103:        }
                   1104:     }
                   1105:     restoretty(stdout, &(p->ttyinfo));
                   1106: }
                   1107: 
                   1108: /*
                   1109:  * Return the address associated with the current signal.
                   1110:  * (Plus two since the address points to the beginning of a procedure).
                   1111:  */
                   1112: 
                   1113: public Address usignal (p)
                   1114: Process p;
                   1115: {
                   1116:     Address r;
                   1117: 
                   1118:     r = p->sigstatus;
                   1119:     if (r != 0 and r != 1) {
                   1120:        r += 2;
                   1121:     }
                   1122:     return r;
                   1123: }
                   1124: 
                   1125: /*
                   1126:  * Structure for reading and writing by words, but dealing with bytes.
                   1127:  */
                   1128: 
                   1129: typedef union {
                   1130:     Word pword;
                   1131:     Byte pbyte[sizeof(Word)];
                   1132: } Pword;
                   1133: 
                   1134: /*
                   1135:  * Read (write) from (to) the process' address space.
                   1136:  * We must deal with ptrace's inability to look anywhere other
                   1137:  * than at a word boundary.
                   1138:  */
                   1139: 
                   1140: private Word fetch();
                   1141: private store();
                   1142: 
                   1143: private pio(p, op, seg, buff, addr, nbytes)
                   1144: Process p;
                   1145: PioOp op;
                   1146: PioSeg seg;
                   1147: char *buff;
                   1148: Address addr;
                   1149: int nbytes;
                   1150: {
                   1151:     register int i;
                   1152:     register Address newaddr;
                   1153:     register char *cp;
                   1154:     char *bufend;
                   1155:     Pword w;
                   1156:     Address wordaddr;
                   1157:     int byteoff;
                   1158: 
                   1159:     if (p->status != STOPPED) {
                   1160:        error("program is not active");
                   1161:     }
                   1162:     cp = buff;
                   1163:     newaddr = addr;
                   1164:     wordaddr = (newaddr&WMASK);
                   1165:     if (wordaddr != newaddr) {
                   1166:        w.pword = fetch(p, seg, wordaddr);
                   1167:        for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
                   1168:            if (op == PREAD) {
                   1169:                *cp++ = w.pbyte[i];
                   1170:            } else {
                   1171:                w.pbyte[i] = *cp++;
                   1172:            }
                   1173:            nbytes--;
                   1174:        }
                   1175:        if (op == PWRITE) {
                   1176:            store(p, seg, wordaddr, w.pword);
                   1177:        }
                   1178:        newaddr = wordaddr + sizeof(Word);
                   1179:     }
                   1180:     byteoff = (nbytes&(~WMASK));
                   1181:     nbytes -= byteoff;
                   1182:     bufend = cp + nbytes;
                   1183:     while (cp < bufend) {
                   1184:        if (op == PREAD) {
                   1185:            *((Word *) cp) = fetch(p, seg, newaddr);
                   1186:        } else {
                   1187:            store(p, seg, newaddr, *((Word *) cp));
                   1188:        }
                   1189:        cp += sizeof(Word);
                   1190:        newaddr += sizeof(Word);
                   1191:     }
                   1192:     if (byteoff > 0) {
                   1193:        w.pword = fetch(p, seg, newaddr);
                   1194:        for (i = 0; i < byteoff; i++) {
                   1195:            if (op == PREAD) {
                   1196:                *cp++ = w.pbyte[i];
                   1197:            } else {
                   1198:                w.pbyte[i] = *cp++;
                   1199:            }
                   1200:        }
                   1201:        if (op == PWRITE) {
                   1202:            store(p, seg, newaddr, w.pword);
                   1203:        }
                   1204:     }
                   1205: }
                   1206: 
                   1207: /*
                   1208:  * Get a word from a process at the given address.
                   1209:  * The address is assumed to be on a word boundary.
                   1210:  *
                   1211:  * A simple cache scheme is used to avoid redundant ptrace calls
                   1212:  * to the instruction space since it is assumed to be pure.
                   1213:  *
                   1214:  * It is necessary to use a write-through scheme so that
                   1215:  * breakpoints right next to each other don't interfere.
                   1216:  */
                   1217: 
                   1218: private Integer nfetchs, nreads, nwrites;
                   1219: 
                   1220: private Word fetch(p, seg, addr)
                   1221: Process p;
                   1222: PioSeg seg;
                   1223: register int addr;
                   1224: {
                   1225:     register CacheWord *wp;
                   1226:     register Word w;
                   1227: 
                   1228:     switch (seg) {
                   1229:        case TEXTSEG:
                   1230:            ++nfetchs;
                   1231:            wp = &p->word[cachehash(addr)];
                   1232:            if (addr == 0 or wp->addr != addr) {
                   1233:                ++nreads;
                   1234:                w = ptrace(IREAD, p->pid, addr, 0);
                   1235:                wp->addr = addr;
                   1236:                wp->val = w;
                   1237:            } else {
                   1238:                w = wp->val;
                   1239:            }
                   1240:            break;
                   1241: 
                   1242:        case DATASEG:
                   1243:            w = ptrace(DREAD, p->pid, addr, 0);
                   1244:            break;
                   1245: 
                   1246:        default:
                   1247:            panic("fetch: bad seg %d", seg);
                   1248:            /* NOTREACHED */
                   1249:     }
                   1250:     return w;
                   1251: }
                   1252: 
                   1253: /*
                   1254:  * Put a word into the process' address space at the given address.
                   1255:  * The address is assumed to be on a word boundary.
                   1256:  */
                   1257: 
                   1258: private store(p, seg, addr, data)
                   1259: Process p;
                   1260: PioSeg seg;
                   1261: int addr;
                   1262: Word data;
                   1263: {
                   1264:     register CacheWord *wp;
                   1265: 
                   1266:     switch (seg) {
                   1267:        case TEXTSEG:
                   1268:            ++nwrites;
                   1269:            wp = &p->word[cachehash(addr)];
                   1270:            wp->addr = addr;
                   1271:            wp->val = data;
                   1272:            ptrace(IWRITE, p->pid, addr, data);
                   1273:            break;
                   1274: 
                   1275:        case DATASEG:
                   1276:            ptrace(DWRITE, p->pid, addr, data);
                   1277:            break;
                   1278: 
                   1279:        default:
                   1280:            panic("store: bad seg %d", seg);
                   1281:            /* NOTREACHED */
                   1282:     }
                   1283: }
                   1284: 
                   1285: /*
                   1286:  * Flush the instruction cache associated with a process.
                   1287:  */
                   1288: 
                   1289: private cacheflush (p)
                   1290: Process p;
                   1291: {
                   1292:     bzero(p->word, sizeof(p->word));
                   1293: }
                   1294: 
                   1295: public printptraceinfo()
                   1296: {
                   1297:     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
                   1298: }
                   1299: 
                   1300: /*
                   1301:  * Redirect input.
                   1302:  * Assuming this is called from a child, we should be careful to avoid
                   1303:  * (possibly) shared standard I/O buffers.
                   1304:  */
                   1305: 
                   1306: private infrom (filename)
                   1307: String filename;
                   1308: {
                   1309:     Fileid in;
                   1310: 
                   1311:     in = open(filename, 0);
                   1312:     if (in == -1) {
                   1313:        write(2, "can't read ", 11);
                   1314:        write(2, filename, strlen(filename));
                   1315:        write(2, "\n", 1);
                   1316:        _exit(1);
                   1317:     }
                   1318:     fswap(0, in);
                   1319: }
                   1320: 
                   1321: /*
                   1322:  * Redirect standard output.
                   1323:  * Same assumptions as for "infrom" above.
                   1324:  */
                   1325: 
                   1326: private outto (filename)
                   1327: String filename;
                   1328: {
                   1329:     Fileid out;
                   1330: 
                   1331:     out = creat(filename, 0666);
                   1332:     if (out == -1) {
                   1333:        write(2, "can't write ", 12);
                   1334:        write(2, filename, strlen(filename));
                   1335:        write(2, "\n", 1);
                   1336:        _exit(1);
                   1337:     }
                   1338:     fswap(1, out);
                   1339: }
                   1340: 
                   1341: /*
                   1342:  * Swap file numbers, useful for redirecting standard input or output.
                   1343:  */
                   1344: 
                   1345: private fswap(oldfd, newfd)
                   1346: Fileid oldfd;
                   1347: Fileid newfd;
                   1348: {
                   1349:     if (oldfd != newfd) {
                   1350:        close(oldfd);
                   1351:        dup(newfd);
                   1352:        close(newfd);
                   1353:     }
                   1354: }
                   1355: 
                   1356: /*
                   1357:  * Signal name manipulation.
                   1358:  */
                   1359: 
                   1360: private String signames[NSIG] = {
                   1361:     0,
                   1362:     "HUP", "INT", "QUIT", "ILL", "TRAP",
                   1363:     "IOT", "EMT", "FPE", "KILL", "BUS",
                   1364:     "SEGV", "SYS", "PIPE", "ALRM", "TERM",
                   1365:     0, "STOP", "TSTP", "CONT", "CHLD",
                   1366:     "TTIN", "TTOU", "TINT", "XCPU", "XFSZ",
                   1367: };
                   1368: 
                   1369: /*
                   1370:  * Get the signal number associated with a given name.
                   1371:  * The name is first translated to upper case if necessary.
                   1372:  */
                   1373: 
                   1374: public integer siglookup (s)
                   1375: String s;
                   1376: {
                   1377:     register char *p, *q;
                   1378:     char buf[100];
                   1379:     integer i;
                   1380: 
                   1381:     p = s;
                   1382:     q = buf;
                   1383:     while (*p != '\0') {
                   1384:        if (*p >= 'a' and *p <= 'z') {
                   1385:            *q = (*p - 'a') + 'A';
                   1386:        } else {
                   1387:            *q = *p;
                   1388:        }
                   1389:        ++p;
                   1390:        ++q;
                   1391:     }
                   1392:     *q = '\0';
                   1393:     p = buf;
                   1394:     if (buf[0] == 'S' and buf[1] == 'I' and buf[2] == 'G') {
                   1395:        p += 3;
                   1396:     }
                   1397:     i = 1;
                   1398:     for (;;) {
                   1399:        if (i >= sizeof(signames) div sizeof(signames[0])) {
                   1400:            error("signal \"%s\" unknown", s);
                   1401:            i = 0;
                   1402:            break;
                   1403:        }
                   1404:        if (signames[i] != nil and streq(signames[i], p)) {
                   1405:            break;
                   1406:        }
                   1407:        ++i;
                   1408:     }
                   1409:     return i;
                   1410: }
                   1411: 
                   1412: /*
                   1413:  * Print all signals being ignored by the debugger.
                   1414:  * These signals are auotmatically
                   1415:  * passed on to the debugged process.
                   1416:  */
                   1417: 
                   1418: public printsigsignored (p)
                   1419: Process p;
                   1420: {
                   1421:     printsigs(~p->sigset);
                   1422: }
                   1423: 
                   1424: /*
                   1425:  * Print all signals being intercepted by
                   1426:  * the debugger for the specified process.
                   1427:  */
                   1428: 
                   1429: public printsigscaught(p)
                   1430: Process p;
                   1431: {
                   1432:     printsigs(p->sigset);
                   1433: }
                   1434: 
                   1435: private printsigs (set)
                   1436: integer set;
                   1437: {
                   1438:     integer s;
                   1439:     char separator[2];
                   1440: 
                   1441:     separator[0] = '\0';
                   1442:     for (s = 1; s < sizeof(signames) div sizeof(signames[0]); s++) {
                   1443:        if (set & setrep(s)) {
                   1444:            if (signames[s] != nil) {
                   1445:                printf("%s%s", separator, signames[s]);
                   1446:                separator[0] = ' ';
                   1447:                separator[1] = '\0';
                   1448:            }
                   1449:        }
                   1450:     }
                   1451:     if (separator[0] == ' ') {
                   1452:        putchar('\n');
                   1453:     }
                   1454: }

unix.superglobalmegacorp.com

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