Annotation of 42BSD/ucb/dbx/process.c, revision 1.1

1.1     ! root        1: /* Copyright (c) 1982 Regents of the University of California */
        !             2: 
        !             3: static char sccsid[] = "@(#)process.c 1.12 8/19/83";
        !             4: 
        !             5: /*
        !             6:  * Process management.
        !             7:  *
        !             8:  * This module contains the routines to manage the execution and
        !             9:  * tracing of the debuggee process.
        !            10:  */
        !            11: 
        !            12: #include "defs.h"
        !            13: #include "process.h"
        !            14: #include "machine.h"
        !            15: #include "events.h"
        !            16: #include "tree.h"
        !            17: #include "eval.h"
        !            18: #include "operators.h"
        !            19: #include "source.h"
        !            20: #include "object.h"
        !            21: #include "mappings.h"
        !            22: #include "main.h"
        !            23: #include "coredump.h"
        !            24: #include <signal.h>
        !            25: #include <errno.h>
        !            26: #include <sys/param.h>
        !            27: #include <machine/reg.h>
        !            28: #include <sys/stat.h>
        !            29: 
        !            30: #ifndef public
        !            31: 
        !            32: typedef struct Process *Process;
        !            33: 
        !            34: Process process;
        !            35: 
        !            36: #define DEFSIG -1
        !            37: 
        !            38: #include "machine.h"
        !            39: 
        !            40: #endif
        !            41: 
        !            42: #define NOTSTARTED 1
        !            43: #define STOPPED 0177
        !            44: #define FINISHED 0
        !            45: 
        !            46: /*
        !            47:  * Cache-ing of instruction segment is done to reduce the number
        !            48:  * of system calls.
        !            49:  */
        !            50: 
        !            51: #define CSIZE 1003       /* size of instruction cache */
        !            52: 
        !            53: typedef struct {
        !            54:     Word addr;
        !            55:     Word val;
        !            56: } CacheWord;
        !            57: 
        !            58: /*
        !            59:  * This structure holds the information we need from the user structure.
        !            60:  */
        !            61: 
        !            62: struct Process {
        !            63:     int pid;                   /* process being traced */
        !            64:     int mask;                  /* process status word */
        !            65:     Word reg[NREG];            /* process' registers */
        !            66:     Word oreg[NREG];           /* registers when process last stopped */
        !            67:     short status;              /* either STOPPED or FINISHED */
        !            68:     short signo;               /* signal that stopped process */
        !            69:     int exitval;               /* return value from exit() */
        !            70:     long sigset;               /* bit array of traced signals */
        !            71:     CacheWord word[CSIZE];     /* text segment cache */
        !            72:     Ttyinfo ttyinfo;           /* process' terminal characteristics */
        !            73: };
        !            74: 
        !            75: /*
        !            76:  * These definitions are for the arguments to "pio".
        !            77:  */
        !            78: 
        !            79: typedef enum { PREAD, PWRITE } PioOp;
        !            80: typedef enum { TEXTSEG, DATASEG } PioSeg;
        !            81: 
        !            82: private struct Process pbuf;
        !            83: 
        !            84: #define MAXNCMDARGS 100         /* maximum number of arguments to RUN */
        !            85: 
        !            86: extern int errno;
        !            87: 
        !            88: private Boolean just_started;
        !            89: private int argc;
        !            90: private String argv[MAXNCMDARGS];
        !            91: private String infile, outfile;
        !            92: 
        !            93: /*
        !            94:  * Initialize process information.
        !            95:  */
        !            96: 
        !            97: public process_init()
        !            98: {
        !            99:     register Integer i;
        !           100:     Char buf[10];
        !           101: 
        !           102:     process = &pbuf;
        !           103:     process->status = (coredump) ? STOPPED : NOTSTARTED;
        !           104:     setsigtrace();
        !           105:     for (i = 0; i < NREG; i++) {
        !           106:        sprintf(buf, "$r%d", i);
        !           107:        defregname(identname(buf, false), i);
        !           108:     }
        !           109:     defregname(identname("$ap", true), ARGP);
        !           110:     defregname(identname("$fp", true), FRP);
        !           111:     defregname(identname("$sp", true), STKP);
        !           112:     defregname(identname("$pc", true), PROGCTR);
        !           113:     if (coredump) {
        !           114:        coredump_readin(process->mask, process->reg, process->signo);
        !           115:        pc = process->reg[PROGCTR];
        !           116:        getsrcpos();
        !           117:     }
        !           118:     arginit();
        !           119: }
        !           120: 
        !           121: /*
        !           122:  * Routines to get at process information from outside this module.
        !           123:  */
        !           124: 
        !           125: public Word reg(n)
        !           126: Integer n;
        !           127: {
        !           128:     register Word w;
        !           129: 
        !           130:     if (n == NREG) {
        !           131:        w = process->mask;
        !           132:     } else {
        !           133:        w = process->reg[n];
        !           134:     }
        !           135:     return w;
        !           136: }
        !           137: 
        !           138: public setreg(n, w)
        !           139: Integer n;
        !           140: Word w;
        !           141: {
        !           142:     process->reg[n] = w;
        !           143: }
        !           144: 
        !           145: /*
        !           146:  * Begin execution.
        !           147:  *
        !           148:  * We set a breakpoint at the end of the code so that the
        !           149:  * process data doesn't disappear after the program terminates.
        !           150:  */
        !           151: 
        !           152: private Boolean remade();
        !           153: 
        !           154: public start(argv, infile, outfile)
        !           155: String argv[];
        !           156: String infile, outfile;
        !           157: {
        !           158:     String pargv[4];
        !           159:     Node cond;
        !           160: 
        !           161:     if (coredump) {
        !           162:        coredump = false;
        !           163:        fclose(corefile);
        !           164:        coredump_close();
        !           165:     }
        !           166:     if (argv == nil) {
        !           167:        argv = pargv;
        !           168:        pargv[0] = objname;
        !           169:        pargv[1] = nil;
        !           170:     } else {
        !           171:        argv[argc] = nil;
        !           172:     }
        !           173:     if (remade(objname)) {
        !           174:        reinit(argv, infile, outfile);
        !           175:     }
        !           176:     pstart(process, argv, infile, outfile);
        !           177:     if (process->status == STOPPED) {
        !           178:        pc = 0;
        !           179:        curfunc = program;
        !           180:        if (objsize != 0) {
        !           181:            cond = build(O_EQ, build(O_SYM, pcsym), build(O_LCON, lastaddr()));
        !           182:            event_once(cond, buildcmdlist(build(O_ENDX)));
        !           183:        }
        !           184:     }
        !           185: }
        !           186: 
        !           187: /*
        !           188:  * Check to see if the object file has changed since the symbolic
        !           189:  * information last was read.
        !           190:  */
        !           191: 
        !           192: private time_t modtime;
        !           193: 
        !           194: private Boolean remade(filename)
        !           195: String filename;
        !           196: {
        !           197:     struct stat s;
        !           198:     Boolean b;
        !           199: 
        !           200:     stat(filename, &s);
        !           201:     b = (Boolean) (modtime != 0 and modtime < s.st_mtime);
        !           202:     modtime = s.st_mtime;
        !           203:     return b;
        !           204: }
        !           205: 
        !           206: /*
        !           207:  * Set up what signals we want to trace.
        !           208:  */
        !           209: 
        !           210: private setsigtrace()
        !           211: {
        !           212:     register Integer i;
        !           213:     register Process p;
        !           214: 
        !           215:     p = process;
        !           216:     for (i = 1; i <= NSIG; i++) {
        !           217:        psigtrace(p, i, true);
        !           218:     }
        !           219:     psigtrace(p, SIGHUP, false);
        !           220:     psigtrace(p, SIGKILL, false);
        !           221:     psigtrace(p, SIGALRM, false);
        !           222:     psigtrace(p, SIGTSTP, false);
        !           223:     psigtrace(p, SIGCONT, false);
        !           224:     psigtrace(p, SIGCHLD, false);
        !           225: }
        !           226: 
        !           227: /*
        !           228:  * Initialize the argument list.
        !           229:  */
        !           230: 
        !           231: public arginit()
        !           232: {
        !           233:     infile = nil;
        !           234:     outfile = nil;
        !           235:     argv[0] = objname;
        !           236:     argc = 1;
        !           237: }
        !           238: 
        !           239: /*
        !           240:  * Add an argument to the list for the debuggee.
        !           241:  */
        !           242: 
        !           243: public newarg(arg)
        !           244: String arg;
        !           245: {
        !           246:     if (argc >= MAXNCMDARGS) {
        !           247:        error("too many arguments");
        !           248:     }
        !           249:     argv[argc++] = arg;
        !           250: }
        !           251: 
        !           252: /*
        !           253:  * Set the standard input for the debuggee.
        !           254:  */
        !           255: 
        !           256: public inarg(filename)
        !           257: String filename;
        !           258: {
        !           259:     if (infile != nil) {
        !           260:        error("multiple input redirects");
        !           261:     }
        !           262:     infile = filename;
        !           263: }
        !           264: 
        !           265: /*
        !           266:  * Set the standard output for the debuggee.
        !           267:  * Probably should check to avoid overwriting an existing file.
        !           268:  */
        !           269: 
        !           270: public outarg(filename)
        !           271: String filename;
        !           272: {
        !           273:     if (outfile != nil) {
        !           274:        error("multiple output redirect");
        !           275:     }
        !           276:     outfile = filename;
        !           277: }
        !           278: 
        !           279: /*
        !           280:  * Start debuggee executing.
        !           281:  */
        !           282: 
        !           283: public run()
        !           284: {
        !           285:     process->status = STOPPED;
        !           286:     fixbps();
        !           287:     curline = 0;
        !           288:     start(argv, infile, outfile);
        !           289:     just_started = true;
        !           290:     isstopped = false;
        !           291:     cont(0);
        !           292: }
        !           293: 
        !           294: /*
        !           295:  * Continue execution wherever we left off.
        !           296:  *
        !           297:  * Note that this routine never returns.  Eventually bpact() will fail
        !           298:  * and we'll call printstatus or step will call it.
        !           299:  */
        !           300: 
        !           301: typedef int Intfunc();
        !           302: 
        !           303: private Intfunc *dbintr;
        !           304: private intr();
        !           305: 
        !           306: #define succeeds    == true
        !           307: #define fails       == false
        !           308: 
        !           309: public cont(signo)
        !           310: int signo;
        !           311: {
        !           312:     dbintr = signal(SIGINT, intr);
        !           313:     if (just_started) {
        !           314:        just_started = false;
        !           315:     } else {
        !           316:        if (not isstopped) {
        !           317:            error("can't continue execution");
        !           318:        }
        !           319:        isstopped = false;
        !           320:        stepover();
        !           321:     }
        !           322:     for (;;) {
        !           323:        if (single_stepping) {
        !           324:            printnews();
        !           325:        } else {
        !           326:            setallbps();
        !           327:            resume(signo);
        !           328:            unsetallbps();
        !           329:            if (bpact() fails) {
        !           330:                printstatus();
        !           331:            }
        !           332:        }
        !           333:        stepover();
        !           334:     }
        !           335:     /* NOTREACHED */
        !           336: }
        !           337: 
        !           338: /*
        !           339:  * This routine is called if we get an interrupt while "running" px
        !           340:  * but actually in the debugger.  Could happen, for example, while
        !           341:  * processing breakpoints.
        !           342:  *
        !           343:  * We basically just want to keep going; the assumption is
        !           344:  * that when the process resumes it will get the interrupt
        !           345:  * which will then be handled.
        !           346:  */
        !           347: 
        !           348: private intr()
        !           349: {
        !           350:     signal(SIGINT, intr);
        !           351: }
        !           352: 
        !           353: public fixintr()
        !           354: {
        !           355:     signal(SIGINT, dbintr);
        !           356: }
        !           357: 
        !           358: /*
        !           359:  * Resume execution.
        !           360:  */
        !           361: 
        !           362: public resume(signo)
        !           363: int signo;
        !           364: {
        !           365:     register Process p;
        !           366: 
        !           367:     p = process;
        !           368:     if (traceexec) {
        !           369:        printf("execution resumes at pc 0x%x\n", process->reg[PROGCTR]);
        !           370:        fflush(stdout);
        !           371:     }
        !           372:     pcont(p, signo);
        !           373:     pc = process->reg[PROGCTR];
        !           374:     if (traceexec) {
        !           375:        printf("execution stops at pc 0x%x on sig %d\n",
        !           376:            process->reg[PROGCTR], p->signo);
        !           377:        fflush(stdout);
        !           378:     }
        !           379:     if (p->status != STOPPED) {
        !           380:        if (p->signo != 0) {
        !           381:            error("program terminated by signal %d", p->signo);
        !           382:        } else if (not runfirst) {
        !           383:            error("program unexpectedly exited with %d", p->exitval);
        !           384:        }
        !           385:     }
        !           386: }
        !           387: 
        !           388: /*
        !           389:  * Continue execution up to the next source line.
        !           390:  *
        !           391:  * There are two ways to define the next source line depending on what
        !           392:  * is desired when a procedure or function call is encountered.  Step
        !           393:  * stops at the beginning of the procedure or call; next skips over it.
        !           394:  */
        !           395: 
        !           396: /*
        !           397:  * Stepc is what is called when the step command is given.
        !           398:  * It has to play with the "isstopped" information.
        !           399:  */
        !           400: 
        !           401: public stepc()
        !           402: {
        !           403:     if (not isstopped) {
        !           404:        error("can't continue execution");
        !           405:     }
        !           406:     isstopped = false;
        !           407:     dostep(false);
        !           408:     isstopped = true;
        !           409: }
        !           410: 
        !           411: public next()
        !           412: {
        !           413:     if (not isstopped) {
        !           414:        error("can't continue execution");
        !           415:     }
        !           416:     isstopped = false;
        !           417:     dostep(true);
        !           418:     isstopped = true;
        !           419: }
        !           420: 
        !           421: /*
        !           422:  * Single-step over the current machine instruction.
        !           423:  *
        !           424:  * If we're single-stepping by source line we want to step to the
        !           425:  * next source line.  Otherwise we're going to continue so there's
        !           426:  * no reason to do all the work necessary to single-step to the next
        !           427:  * source line.
        !           428:  */
        !           429: 
        !           430: private stepover()
        !           431: {
        !           432:     Boolean b;
        !           433: 
        !           434:     if (single_stepping) {
        !           435:        dostep(false);
        !           436:     } else {
        !           437:        b = inst_tracing;
        !           438:        inst_tracing = true;
        !           439:        dostep(false);
        !           440:        inst_tracing = b;
        !           441:     }
        !           442: }
        !           443: 
        !           444: /*
        !           445:  * Resume execution up to the given address.  It is assumed that
        !           446:  * no breakpoints exist between the current address and the one
        !           447:  * we're stepping to.  This saves us from setting all the breakpoints.
        !           448:  */
        !           449: 
        !           450: public stepto(addr)
        !           451: Address addr;
        !           452: {
        !           453:     setbp(addr);
        !           454:     resume(DEFSIG);
        !           455:     unsetbp(addr);
        !           456:     if (not isbperr()) {
        !           457:        printstatus();
        !           458:     }
        !           459: }
        !           460: 
        !           461: /*
        !           462:  * Print the status of the process.
        !           463:  * This routine does not return.
        !           464:  */
        !           465: 
        !           466: public printstatus()
        !           467: {
        !           468:     int status;
        !           469: 
        !           470:     if (process->status == FINISHED) {
        !           471:        exit(0);
        !           472:     } else {
        !           473:        curfunc = whatblock(pc);
        !           474:        getsrcpos();
        !           475:        if (process->signo == SIGINT) {
        !           476:            isstopped = true;
        !           477:            printerror();
        !           478:        } else if (isbperr() and isstopped) {
        !           479:            printf("stopped ");
        !           480:            printloc();
        !           481:            putchar('\n');
        !           482:            if (curline > 0) {
        !           483:                printlines(curline, curline);
        !           484:            } else {
        !           485:                printinst(pc, pc);
        !           486:            }
        !           487:            erecover();
        !           488:        } else {
        !           489:            fixbps();
        !           490:            fixintr();
        !           491:            isstopped = true;
        !           492:            printerror();
        !           493:        }
        !           494:     }
        !           495: }
        !           496: 
        !           497: /*
        !           498:  * Print out the current location in the debuggee.
        !           499:  */
        !           500: 
        !           501: public printloc()
        !           502: {
        !           503:     printf("in ");
        !           504:     printname(stdout, curfunc);
        !           505:     putchar(' ');
        !           506:     if (curline > 0 and not useInstLoc) {
        !           507:        printsrcpos();
        !           508:     } else {
        !           509:        useInstLoc = false;
        !           510:        curline = 0;
        !           511:        printf("at 0x%x", pc);
        !           512:     }
        !           513: }
        !           514: 
        !           515: /*
        !           516:  * Some functions for testing the state of the process.
        !           517:  */
        !           518: 
        !           519: public Boolean notstarted(p)
        !           520: Process p;
        !           521: {
        !           522:     return (Boolean) (p->status == NOTSTARTED);
        !           523: }
        !           524: 
        !           525: public Boolean isfinished(p)
        !           526: Process p;
        !           527: {
        !           528:     return (Boolean) (p->status == FINISHED);
        !           529: }
        !           530: 
        !           531: /*
        !           532:  * Return the signal number which stopped the process.
        !           533:  */
        !           534: 
        !           535: public Integer errnum(p)
        !           536: Process p;
        !           537: {
        !           538:     return p->signo;
        !           539: }
        !           540: 
        !           541: /*
        !           542:  * Return the termination code of the process.
        !           543:  */
        !           544: 
        !           545: public Integer exitcode(p)
        !           546: Process p;
        !           547: {
        !           548:     return p->exitval;
        !           549: }
        !           550: 
        !           551: /*
        !           552:  * These routines are used to access the debuggee process from
        !           553:  * outside this module.
        !           554:  *
        !           555:  * They invoke "pio" which eventually leads to a call to "ptrace".
        !           556:  * The system generates an I/O error when a ptrace fails.  During reads
        !           557:  * these are ignored, during writes they are reported as an error, and
        !           558:  * for anything else they cause a fatal error.
        !           559:  */
        !           560: 
        !           561: extern Intfunc *onsyserr();
        !           562: 
        !           563: private badaddr;
        !           564: private read_err(), write_err();
        !           565: 
        !           566: /*
        !           567:  * Read from the process' instruction area.
        !           568:  */
        !           569: 
        !           570: public iread(buff, addr, nbytes)
        !           571: char *buff;
        !           572: Address addr;
        !           573: int nbytes;
        !           574: {
        !           575:     Intfunc *f;
        !           576: 
        !           577:     f = onsyserr(EIO, read_err);
        !           578:     badaddr = addr;
        !           579:     if (coredump) {
        !           580:        coredump_readtext(buff, addr, nbytes);
        !           581:     } else {
        !           582:        pio(process, PREAD, TEXTSEG, buff, addr, nbytes);
        !           583:     }
        !           584:     onsyserr(EIO, f);
        !           585: }
        !           586: 
        !           587: /* 
        !           588:  * Write to the process' instruction area, usually in order to set
        !           589:  * or unset a breakpoint.
        !           590:  */
        !           591: 
        !           592: public iwrite(buff, addr, nbytes)
        !           593: char *buff;
        !           594: Address addr;
        !           595: int nbytes;
        !           596: {
        !           597:     Intfunc *f;
        !           598: 
        !           599:     if (coredump) {
        !           600:        error("no process to write to");
        !           601:     }
        !           602:     f = onsyserr(EIO, write_err);
        !           603:     badaddr = addr;
        !           604:     pio(process, PWRITE, TEXTSEG, buff, addr, nbytes);
        !           605:     onsyserr(EIO, f);
        !           606: }
        !           607: 
        !           608: /*
        !           609:  * Read for the process' data area.
        !           610:  */
        !           611: 
        !           612: public dread(buff, addr, nbytes)
        !           613: char *buff;
        !           614: Address addr;
        !           615: int nbytes;
        !           616: {
        !           617:     Intfunc *f;
        !           618: 
        !           619:     f = onsyserr(EIO, read_err);
        !           620:     badaddr = addr;
        !           621:     if (coredump) {
        !           622:        coredump_readdata(buff, addr, nbytes);
        !           623:     } else {
        !           624:        pio(process, PREAD, DATASEG, buff, addr, nbytes);
        !           625:     }
        !           626:     onsyserr(EIO, f);
        !           627: }
        !           628: 
        !           629: /*
        !           630:  * Write to the process' data area.
        !           631:  */
        !           632: 
        !           633: public dwrite(buff, addr, nbytes)
        !           634: char *buff;
        !           635: Address addr;
        !           636: int nbytes;
        !           637: {
        !           638:     Intfunc *f;
        !           639: 
        !           640:     if (coredump) {
        !           641:        error("no process to write to");
        !           642:     }
        !           643:     f = onsyserr(EIO, write_err);
        !           644:     badaddr = addr;
        !           645:     pio(process, PWRITE, DATASEG, buff, addr, nbytes);
        !           646:     onsyserr(EIO, f);
        !           647: }
        !           648: 
        !           649: /*
        !           650:  * Trap for errors in reading or writing to a process.
        !           651:  * The current approach is to "ignore" read errors and complain
        !           652:  * bitterly about write errors.
        !           653:  */
        !           654: 
        !           655: private read_err()
        !           656: {
        !           657:     /*
        !           658:      * Ignore.
        !           659:      */
        !           660: }
        !           661: 
        !           662: private write_err()
        !           663: {
        !           664:     error("can't write to process (address 0x%x)", badaddr);
        !           665: }
        !           666: 
        !           667: /*
        !           668:  * Ptrace interface.
        !           669:  */
        !           670: 
        !           671: /*
        !           672:  * This magic macro enables us to look at the process' registers
        !           673:  * in its user structure.
        !           674:  */
        !           675: 
        !           676: #define regloc(reg)     (ctob(UPAGES) + ( sizeof(int) * (reg) ))
        !           677: 
        !           678: #define WMASK           (~(sizeof(Word) - 1))
        !           679: #define cachehash(addr) ((unsigned) ((addr >> 2) % CSIZE))
        !           680: 
        !           681: #define FIRSTSIG        SIGINT
        !           682: #define LASTSIG         SIGQUIT
        !           683: #define ischild(pid)    ((pid) == 0)
        !           684: #define traceme()       ptrace(0, 0, 0, 0)
        !           685: #define setrep(n)       (1 << ((n)-1))
        !           686: #define istraced(p)     (p->sigset&setrep(p->signo))
        !           687: 
        !           688: /*
        !           689:  * Ptrace options (specified in first argument).
        !           690:  */
        !           691: 
        !           692: #define UREAD   3       /* read from process's user structure */
        !           693: #define UWRITE  6       /* write to process's user structure */
        !           694: #define IREAD   1       /* read from process's instruction space */
        !           695: #define IWRITE  4       /* write to process's instruction space */
        !           696: #define DREAD   2       /* read from process's data space */
        !           697: #define DWRITE  5       /* write to process's data space */
        !           698: #define CONT    7       /* continue stopped process */
        !           699: #define SSTEP   9       /* continue for approximately one instruction */
        !           700: #define PKILL   8       /* terminate the process */
        !           701: 
        !           702: /*
        !           703:  * Start up a new process by forking and exec-ing the
        !           704:  * given argument list, returning when the process is loaded
        !           705:  * and ready to execute.  The PROCESS information (pointed to
        !           706:  * by the first argument) is appropriately filled.
        !           707:  *
        !           708:  * If the given PROCESS structure is associated with an already running
        !           709:  * process, we terminate it.
        !           710:  */
        !           711: 
        !           712: /* VARARGS2 */
        !           713: private pstart(p, argv, infile, outfile)
        !           714: Process p;
        !           715: String argv[];
        !           716: String infile;
        !           717: String outfile;
        !           718: {
        !           719:     int status;
        !           720:     Fileid in, out;
        !           721: 
        !           722:     if (p->pid != 0) {                 /* child already running? */
        !           723:        ptrace(PKILL, p->pid, 0, 0);    /* ... kill it! */
        !           724:        pwait(p->pid, &status);         /* wait for it to exit */
        !           725:        unptraced(p->pid);
        !           726:     }
        !           727:     psigtrace(p, SIGTRAP, true);
        !           728:     p->pid = vfork();
        !           729:     if (p->pid == -1) {
        !           730:        panic("can't fork");
        !           731:     }
        !           732:     if (ischild(p->pid)) {
        !           733:        traceme();
        !           734:        if (infile != nil) {
        !           735:            in = open(infile, 0);
        !           736:            if (in == -1) {
        !           737:                write(2, "can't read ", 11);
        !           738:                write(2, infile, strlen(infile));
        !           739:                write(2, "\n", 1);
        !           740:                _exit(1);
        !           741:            }
        !           742:            fswap(0, in);
        !           743:        }
        !           744:        if (outfile != nil) {
        !           745:            out = creat(outfile, 0666);
        !           746:            if (out == -1) {
        !           747:                write(2, "can't write ", 12);
        !           748:                write(2, outfile, strlen(outfile));
        !           749:                write(2, "\n", 1);
        !           750:                _exit(1);
        !           751:            }
        !           752:            fswap(1, out);
        !           753:        }
        !           754:        execv(argv[0], argv);
        !           755:        write(2, "can't exec ", 11);
        !           756:        write(2, argv[0], strlen(argv[0]));
        !           757:        write(2, "\n", 1);
        !           758:        _exit(1);
        !           759:     }
        !           760:     pwait(p->pid, &status);
        !           761:     getinfo(p, status);
        !           762:     if (p->status != STOPPED) {
        !           763:        error("program could not begin execution");
        !           764:     }
        !           765:     ptraced(p->pid);
        !           766: }
        !           767: 
        !           768: /*
        !           769:  * Continue a stopped process.  The first argument points to a Process
        !           770:  * structure.  Before the process is restarted it's user area is modified
        !           771:  * according to the values in the structure.  When this routine finishes,
        !           772:  * the structure has the new values from the process's user area.
        !           773:  *
        !           774:  * Pcont terminates when the process stops with a signal pending that
        !           775:  * is being traced (via psigtrace), or when the process terminates.
        !           776:  */
        !           777: 
        !           778: private pcont(p, signo)
        !           779: Process p;
        !           780: int signo;
        !           781: {
        !           782:     int status;
        !           783: 
        !           784:     if (p->pid == 0) {
        !           785:        error("program not active");
        !           786:     }
        !           787:     do {
        !           788:        setinfo(p, signo);
        !           789:        sigs_off();
        !           790:        if (ptrace(CONT, p->pid, p->reg[PROGCTR], p->signo) < 0) {
        !           791:            panic("error %d trying to continue process", errno);
        !           792:        }
        !           793:        pwait(p->pid, &status);
        !           794:        sigs_on();
        !           795:        getinfo(p, status);
        !           796:     } while (p->status == STOPPED and not istraced(p));
        !           797: }
        !           798: 
        !           799: /*
        !           800:  * Single step as best ptrace can.
        !           801:  */
        !           802: 
        !           803: public pstep(p)
        !           804: Process p;
        !           805: {
        !           806:     int status;
        !           807: 
        !           808:     setinfo(p, DEFSIG);
        !           809:     sigs_off();
        !           810:     ptrace(SSTEP, p->pid, p->reg[PROGCTR], p->signo);
        !           811:     pwait(p->pid, &status);
        !           812:     sigs_on();
        !           813:     getinfo(p, status);
        !           814: }
        !           815: 
        !           816: /*
        !           817:  * Return from execution when the given signal is pending.
        !           818:  */
        !           819: 
        !           820: public psigtrace(p, sig, sw)
        !           821: Process p;
        !           822: int sig;
        !           823: Boolean sw;
        !           824: {
        !           825:     if (sw) {
        !           826:        p->sigset |= setrep(sig);
        !           827:     } else {
        !           828:        p->sigset &= ~setrep(sig);
        !           829:     }
        !           830: }
        !           831: 
        !           832: /*
        !           833:  * Don't catch any signals.
        !           834:  * Particularly useful when letting a process finish uninhibited.
        !           835:  */
        !           836: 
        !           837: public unsetsigtraces(p)
        !           838: Process p;
        !           839: {
        !           840:     p->sigset = 0;
        !           841: }
        !           842: 
        !           843: /*
        !           844:  * Turn off attention to signals not being caught.
        !           845:  */
        !           846: 
        !           847: private Intfunc *sigfunc[NSIG];
        !           848: 
        !           849: private sigs_off()
        !           850: {
        !           851:     register int i;
        !           852: 
        !           853:     for (i = FIRSTSIG; i < LASTSIG; i++) {
        !           854:        if (i != SIGKILL) {
        !           855:            sigfunc[i] = signal(i, SIG_IGN);
        !           856:        }
        !           857:     }
        !           858: }
        !           859: 
        !           860: /*
        !           861:  * Turn back on attention to signals.
        !           862:  */
        !           863: 
        !           864: private sigs_on()
        !           865: {
        !           866:     register int i;
        !           867: 
        !           868:     for (i = FIRSTSIG; i < LASTSIG; i++) {
        !           869:        if (i != SIGKILL) {
        !           870:            signal(i, sigfunc[i]);
        !           871:        }
        !           872:     }
        !           873: }
        !           874: 
        !           875: /*
        !           876:  * Get process information from user area.
        !           877:  */
        !           878: 
        !           879: private int rloc[] ={
        !           880:     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
        !           881: };
        !           882: 
        !           883: private getinfo(p, status)
        !           884: register Process p;
        !           885: register int status;
        !           886: {
        !           887:     register int i;
        !           888: 
        !           889:     p->signo = (status&0177);
        !           890:     p->exitval = ((status >> 8)&0377);
        !           891:     if (p->signo != STOPPED) {
        !           892:        p->status = FINISHED;
        !           893:        p->pid = 0;
        !           894:     } else {
        !           895:        p->status = p->signo;
        !           896:        p->signo = p->exitval;
        !           897:        p->exitval = 0;
        !           898:        p->mask = ptrace(UREAD, p->pid, regloc(PS), 0);
        !           899:        for (i = 0; i < NREG; i++) {
        !           900:            p->reg[i] = ptrace(UREAD, p->pid, regloc(rloc[i]), 0);
        !           901:            p->oreg[i] = p->reg[i];
        !           902:        }
        !           903:        savetty(stdout, &(p->ttyinfo));
        !           904:     }
        !           905: }
        !           906: 
        !           907: /*
        !           908:  * Set process's user area information from given process structure.
        !           909:  */
        !           910: 
        !           911: private setinfo(p, signo)
        !           912: register Process p;
        !           913: int signo;
        !           914: {
        !           915:     register int i;
        !           916:     register int r;
        !           917: 
        !           918:     if (signo == DEFSIG) {
        !           919:        if (istraced(p)) {
        !           920:            p->signo = 0;
        !           921:        }
        !           922:     } else {
        !           923:        p->signo = signo;
        !           924:     }
        !           925:     for (i = 0; i < NREG; i++) {
        !           926:        if ((r = p->reg[i]) != p->oreg[i]) {
        !           927:            ptrace(UWRITE, p->pid, regloc(rloc[i]), r);
        !           928:        }
        !           929:     }
        !           930:     restoretty(stdout, &(p->ttyinfo));
        !           931: }
        !           932: 
        !           933: /*
        !           934:  * Structure for reading and writing by words, but dealing with bytes.
        !           935:  */
        !           936: 
        !           937: typedef union {
        !           938:     Word pword;
        !           939:     Byte pbyte[sizeof(Word)];
        !           940: } Pword;
        !           941: 
        !           942: /*
        !           943:  * Read (write) from (to) the process' address space.
        !           944:  * We must deal with ptrace's inability to look anywhere other
        !           945:  * than at a word boundary.
        !           946:  */
        !           947: 
        !           948: private Word fetch();
        !           949: private store();
        !           950: 
        !           951: private pio(p, op, seg, buff, addr, nbytes)
        !           952: Process p;
        !           953: PioOp op;
        !           954: PioSeg seg;
        !           955: char *buff;
        !           956: Address addr;
        !           957: int nbytes;
        !           958: {
        !           959:     register int i;
        !           960:     register Address newaddr;
        !           961:     register char *cp;
        !           962:     char *bufend;
        !           963:     Pword w;
        !           964:     Address wordaddr;
        !           965:     int byteoff;
        !           966: 
        !           967:     if (p->status != STOPPED) {
        !           968:        error("program is not active");
        !           969:     }
        !           970:     cp = buff;
        !           971:     newaddr = addr;
        !           972:     wordaddr = (newaddr&WMASK);
        !           973:     if (wordaddr != newaddr) {
        !           974:        w.pword = fetch(p, seg, wordaddr);
        !           975:        for (i = newaddr - wordaddr; i < sizeof(Word) and nbytes > 0; i++) {
        !           976:            if (op == PREAD) {
        !           977:                *cp++ = w.pbyte[i];
        !           978:            } else {
        !           979:                w.pbyte[i] = *cp++;
        !           980:            }
        !           981:            nbytes--;
        !           982:        }
        !           983:        if (op == PWRITE) {
        !           984:            store(p, seg, wordaddr, w.pword);
        !           985:        }
        !           986:        newaddr = wordaddr + sizeof(Word);
        !           987:     }
        !           988:     byteoff = (nbytes&(~WMASK));
        !           989:     nbytes -= byteoff;
        !           990:     bufend = cp + nbytes;
        !           991:     while (cp < bufend) {
        !           992:        if (op == PREAD) {
        !           993:            *((Word *) cp) = fetch(p, seg, newaddr);
        !           994:        } else {
        !           995:            store(p, seg, newaddr, *((Word *) cp));
        !           996:        }
        !           997:        cp += sizeof(Word);
        !           998:        newaddr += sizeof(Word);
        !           999:     }
        !          1000:     if (byteoff > 0) {
        !          1001:        w.pword = fetch(p, seg, newaddr);
        !          1002:        for (i = 0; i < byteoff; i++) {
        !          1003:            if (op == PREAD) {
        !          1004:                *cp++ = w.pbyte[i];
        !          1005:            } else {
        !          1006:                w.pbyte[i] = *cp++;
        !          1007:            }
        !          1008:        }
        !          1009:        if (op == PWRITE) {
        !          1010:            store(p, seg, newaddr, w.pword);
        !          1011:        }
        !          1012:     }
        !          1013: }
        !          1014: 
        !          1015: /*
        !          1016:  * Get a word from a process at the given address.
        !          1017:  * The address is assumed to be on a word boundary.
        !          1018:  *
        !          1019:  * A simple cache scheme is used to avoid redundant ptrace calls
        !          1020:  * to the instruction space since it is assumed to be pure.
        !          1021:  *
        !          1022:  * It is necessary to use a write-through scheme so that
        !          1023:  * breakpoints right next to each other don't interfere.
        !          1024:  */
        !          1025: 
        !          1026: private Integer nfetchs, nreads, nwrites;
        !          1027: 
        !          1028: private Word fetch(p, seg, addr)
        !          1029: Process p;
        !          1030: PioSeg seg;
        !          1031: register int addr;
        !          1032: {
        !          1033:     register CacheWord *wp;
        !          1034:     register Word w;
        !          1035: 
        !          1036:     switch (seg) {
        !          1037:        case TEXTSEG:
        !          1038:            ++nfetchs;
        !          1039:            wp = &p->word[cachehash(addr)];
        !          1040:            if (addr == 0 or wp->addr != addr) {
        !          1041:                ++nreads;
        !          1042:                w = ptrace(IREAD, p->pid, addr, 0);
        !          1043:                wp->addr = addr;
        !          1044:                wp->val = w;
        !          1045:            } else {
        !          1046:                w = wp->val;
        !          1047:            }
        !          1048:            break;
        !          1049: 
        !          1050:        case DATASEG:
        !          1051:            w = ptrace(DREAD, p->pid, addr, 0);
        !          1052:            break;
        !          1053: 
        !          1054:        default:
        !          1055:            panic("fetch: bad seg %d", seg);
        !          1056:            /* NOTREACHED */
        !          1057:     }
        !          1058:     return w;
        !          1059: }
        !          1060: 
        !          1061: /*
        !          1062:  * Put a word into the process' address space at the given address.
        !          1063:  * The address is assumed to be on a word boundary.
        !          1064:  */
        !          1065: 
        !          1066: private store(p, seg, addr, data)
        !          1067: Process p;
        !          1068: PioSeg seg;
        !          1069: int addr;
        !          1070: Word data;
        !          1071: {
        !          1072:     register CacheWord *wp;
        !          1073: 
        !          1074:     switch (seg) {
        !          1075:        case TEXTSEG:
        !          1076:            ++nwrites;
        !          1077:            wp = &p->word[cachehash(addr)];
        !          1078:            wp->addr = addr;
        !          1079:            wp->val = data;
        !          1080:            ptrace(IWRITE, p->pid, addr, data);
        !          1081:            break;
        !          1082: 
        !          1083:        case DATASEG:
        !          1084:            ptrace(DWRITE, p->pid, addr, data);
        !          1085:            break;
        !          1086: 
        !          1087:        default:
        !          1088:            panic("store: bad seg %d", seg);
        !          1089:            /* NOTREACHED */
        !          1090:     }
        !          1091: }
        !          1092: 
        !          1093: public printptraceinfo()
        !          1094: {
        !          1095:     printf("%d fetchs, %d reads, %d writes\n", nfetchs, nreads, nwrites);
        !          1096: }
        !          1097: 
        !          1098: /*
        !          1099:  * Swap file numbers so as to redirect standard input and output.
        !          1100:  */
        !          1101: 
        !          1102: private fswap(oldfd, newfd)
        !          1103: int oldfd;
        !          1104: int newfd;
        !          1105: {
        !          1106:     if (oldfd != newfd) {
        !          1107:        close(oldfd);
        !          1108:        dup(newfd);
        !          1109:        close(newfd);
        !          1110:     }
        !          1111: }

unix.superglobalmegacorp.com

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