Annotation of 43BSDReno/pgrm/dbx/process.c, revision 1.1

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

unix.superglobalmegacorp.com

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