Annotation of 42BSD/ucb/dbx/process.c, revision 1.1.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.