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

1.1     ! root        1: 
        !             2: /* Copyright (c) 1982 Regents of the University of California */
        !             3: 
        !             4: static char sccsid[] = "@(#)runtime.c 1.9 8/14/83";
        !             5: 
        !             6: /*
        !             7:  * Runtime organization dependent routines, mostly dealing with
        !             8:  * activation records.
        !             9:  */
        !            10: 
        !            11: #include "defs.h"
        !            12: #include "runtime.h"
        !            13: #include "process.h"
        !            14: #include "machine.h"
        !            15: #include "events.h"
        !            16: #include "mappings.h"
        !            17: #include "symbols.h"
        !            18: #include "tree.h"
        !            19: #include "eval.h"
        !            20: #include "operators.h"
        !            21: #include "object.h"
        !            22: #include <sys/param.h>
        !            23: 
        !            24: #ifndef public
        !            25: typedef struct Frame *Frame;
        !            26: 
        !            27: #include "machine.h"
        !            28: #endif
        !            29: 
        !            30: #define NSAVEREG 12
        !            31: 
        !            32: struct Frame {
        !            33:     Integer condition_handler;
        !            34:     Integer mask;
        !            35:     Address save_ap;           /* argument pointer */
        !            36:     Address save_fp;           /* frame pointer */
        !            37:     Address save_pc;           /* program counter */
        !            38:     Word save_reg[NSAVEREG];   /* not necessarily there */
        !            39: };
        !            40: 
        !            41: private Boolean walkingstack = false;
        !            42: 
        !            43: /*
        !            44:  * Set a frame to the current activation record.
        !            45:  */
        !            46: 
        !            47: private getcurframe(frp)
        !            48: register Frame frp;
        !            49: {
        !            50:     register int i;
        !            51: 
        !            52:     checkref(frp);
        !            53:     frp->mask = reg(NREG);
        !            54:     frp->save_ap = reg(ARGP);
        !            55:     frp->save_fp = reg(FRP);
        !            56:     frp->save_pc = reg(PROGCTR) + 1;
        !            57:     for (i = 0; i < NSAVEREG; i++) {
        !            58:        frp->save_reg[i] = reg(i);
        !            59:     }
        !            60: }
        !            61: 
        !            62: /*
        !            63:  * Return a pointer to the next activation record up the stack.
        !            64:  * Return nil if there is none.
        !            65:  * Writes over space pointed to by given argument.
        !            66:  */
        !            67: 
        !            68: #define bis(b, n) ((b & (1 << (n))) != 0)
        !            69: 
        !            70: private Frame nextframe(frp)
        !            71: Frame frp;
        !            72: {
        !            73:     register Frame newfrp;
        !            74:     struct Frame frame;
        !            75:     register Integer i, j, mask;
        !            76:     Address prev_frame, callpc; 
        !            77:     static Integer ntramp = 0;
        !            78: 
        !            79:     newfrp = frp;
        !            80:     prev_frame = frp->save_fp;
        !            81: 
        !            82: /*
        !            83:  *  The check for interrupt generated frames is taken from adb with only
        !            84:  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
        !            85:  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
        !            86:  *
        !            87:  *  As best I can make out it looks like:
        !            88:  *
        !            89:  *     <main, (machine check exception block + sub), sysframe, sigsub>.
        !            90:  *
        !            91:  *  When the signal occurs an exception block and a frame for the routine
        !            92:  *  in which it occured are pushed on the user stack.  Then another frame
        !            93:  *  is pushed corresponding to a call from the kernel to sigsub.
        !            94:  *
        !            95:  *  The addr in sub at which the exception occured is not in sub.save_pc
        !            96:  *  but in the machine check exception block.  It is at the magic address
        !            97:  *  fp + 84.
        !            98:  *
        !            99:  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
        !           100:  *  and takes the pc for sub from the exception block.  This allows the
        !           101:  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
        !           102:  */
        !           103: 
        !           104: nextf:
        !           105:     dread(&frame, prev_frame, sizeof(struct Frame));
        !           106:     if (ntramp == 1) {
        !           107:        dread(&callpc, prev_frame + 84, sizeof(callpc));
        !           108:     } else {
        !           109:        callpc = frame.save_pc;
        !           110:     }
        !           111:     if (frame.save_fp == nil) {
        !           112:        newfrp = nil;
        !           113:     } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
        !           114:         ntramp++;
        !           115:         prev_frame = frame.save_fp;
        !           116:         goto nextf;
        !           117:     } else {
        !           118:        frame.save_pc = callpc;
        !           119:         ntramp = 0;
        !           120:        mask = ((frame.mask >> 16) & 0x0fff);
        !           121:        j = 0;
        !           122:        for (i = 0; i < NSAVEREG; i++) {
        !           123:            if (bis(mask, i)) {
        !           124:                newfrp->save_reg[i] = frame.save_reg[j];
        !           125:                ++j;
        !           126:            }
        !           127:        }
        !           128:        newfrp->condition_handler = frame.condition_handler;
        !           129:        newfrp->mask = mask;
        !           130:        newfrp->save_ap = frame.save_ap;
        !           131:        newfrp->save_fp = frame.save_fp;
        !           132:        newfrp->save_pc = frame.save_pc;
        !           133:     }
        !           134:     return newfrp;
        !           135: }
        !           136: 
        !           137: /*
        !           138:  * Return the frame associated with the given function.
        !           139:  * If the function is nil, return the most recently activated frame.
        !           140:  *
        !           141:  * Static allocation for the frame.
        !           142:  */
        !           143: 
        !           144: public Frame findframe(f)
        !           145: Symbol f;
        !           146: {
        !           147:     register Frame frp;
        !           148:     static struct Frame frame;
        !           149:     Symbol p;
        !           150:     Boolean done;
        !           151: 
        !           152:     frp = &frame;
        !           153:     getcurframe(frp);
        !           154:     if (f != nil) {
        !           155:        done = false;
        !           156:        do {
        !           157:            p = whatblock(frp->save_pc);
        !           158:            if (p == f) {
        !           159:                done = true;
        !           160:            } else if (p == program) {
        !           161:                done = true;
        !           162:                frp = nil;
        !           163:            } else {
        !           164:                frp = nextframe(frp);
        !           165:                if (frp == nil) {
        !           166:                    done = true;
        !           167:                }
        !           168:            }
        !           169:        } while (not done);
        !           170:     }
        !           171:     return frp;
        !           172: }
        !           173: 
        !           174: /*
        !           175:  * Find the return address of the current procedure/function.
        !           176:  */
        !           177: 
        !           178: public Address return_addr()
        !           179: {
        !           180:     Frame frp;
        !           181:     Address addr;
        !           182:     struct Frame frame;
        !           183: 
        !           184:     frp = &frame;
        !           185:     getcurframe(frp);
        !           186:     frp = nextframe(frp);
        !           187:     if (frp == nil) {
        !           188:        addr = 0;
        !           189:     } else {
        !           190:        addr = frp->save_pc;
        !           191:     }
        !           192:     return addr;
        !           193: }
        !           194: 
        !           195: /*
        !           196:  * Push the value associated with the current function.
        !           197:  */
        !           198: 
        !           199: public pushretval(len, isindirect)
        !           200: Integer len;
        !           201: Boolean isindirect;
        !           202: {
        !           203:     Word r0;
        !           204: 
        !           205:     r0 = reg(0);
        !           206:     if (isindirect) {
        !           207:        rpush((Address) r0, len);
        !           208:     } else {
        !           209:        switch (len) {
        !           210:            case sizeof(char):
        !           211:                push(char, r0);
        !           212:                break;
        !           213: 
        !           214:            case sizeof(short):
        !           215:                push(short, r0);
        !           216:                break;
        !           217: 
        !           218:            default:
        !           219:                if (len == sizeof(Word)) {
        !           220:                    push(Word, r0);
        !           221:                } else if (len == 2*sizeof(Word)) {
        !           222:                    push(Word, r0);
        !           223:                    push(Word, reg(1));
        !           224:                } else {
        !           225:                    panic("not indirect in pushretval?");
        !           226:                }
        !           227:                break;
        !           228:        }
        !           229:     }
        !           230: }
        !           231: 
        !           232: /*
        !           233:  * Return the base address for locals in the given frame.
        !           234:  */
        !           235: 
        !           236: public Address locals_base(frp)
        !           237: register Frame frp;
        !           238: {
        !           239:     return (frp == nil) ? reg(FRP) : frp->save_fp;
        !           240: }
        !           241: 
        !           242: /*
        !           243:  * Return the base address for arguments in the given frame.
        !           244:  */
        !           245: 
        !           246: public Address args_base(frp)
        !           247: register Frame frp;
        !           248: {
        !           249:     return (frp == nil) ? reg(ARGP) : frp->save_ap;
        !           250: }
        !           251: 
        !           252: /*
        !           253:  * Return saved register n from the given frame.
        !           254:  */
        !           255: 
        !           256: public Word savereg(n, frp)
        !           257: register Integer n;
        !           258: register Frame frp;
        !           259: {
        !           260:     register Word w;
        !           261: 
        !           262:     if (frp == nil) {
        !           263:        w = reg(n);
        !           264:     } else {
        !           265:        switch (n) {
        !           266:            case ARGP:
        !           267:                w = frp->save_ap;
        !           268:                break;
        !           269: 
        !           270:            case FRP:
        !           271:                w = frp->save_fp;
        !           272:                break;
        !           273: 
        !           274:            case STKP:
        !           275:                w = reg(STKP);
        !           276:                break;
        !           277: 
        !           278:            case PROGCTR:
        !           279:                w = frp->save_pc;
        !           280:                break;
        !           281: 
        !           282:            default:
        !           283:                assert(n >= 0 and n < NSAVEREG);
        !           284:                w = frp->save_reg[n];
        !           285:                break;
        !           286:        }
        !           287:     }
        !           288:     return w;
        !           289: }
        !           290: 
        !           291: /*
        !           292:  * Return the nth argument to the current procedure.
        !           293:  */
        !           294: 
        !           295: public Word argn(n, frp)
        !           296: Integer n;
        !           297: Frame frp;
        !           298: {
        !           299:     Word w;
        !           300: 
        !           301:     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
        !           302:     return w;
        !           303: }
        !           304: 
        !           305: /*
        !           306:  * Calculate the entry address for a procedure or function parameter,
        !           307:  * given the address of the descriptor.
        !           308:  */
        !           309: 
        !           310: public Address fparamaddr(a)
        !           311: Address a;
        !           312: {
        !           313:     Address r;
        !           314: 
        !           315:     dread(&r, a, sizeof(r));
        !           316:     return r;
        !           317: }
        !           318: 
        !           319: /*
        !           320:  * Print a list of currently active blocks starting with most recent.
        !           321:  */
        !           322: 
        !           323: public wherecmd()
        !           324: {
        !           325:     walkstack(false);
        !           326: }
        !           327: 
        !           328: /*
        !           329:  * Dump the world to the given file.
        !           330:  * Like "where", but variables are dumped also.
        !           331:  */
        !           332: 
        !           333: public dump()
        !           334: {
        !           335:     walkstack(true);
        !           336: }
        !           337: 
        !           338: /*
        !           339:  * Walk the stack of active procedures printing information
        !           340:  * about each active procedure.
        !           341:  */
        !           342: 
        !           343: private walkstack(dumpvariables)
        !           344: Boolean dumpvariables;
        !           345: {
        !           346:     register Frame frp;
        !           347:     register Symbol f;
        !           348:     register Boolean save;
        !           349:     register Lineno line;
        !           350:     struct Frame frame;
        !           351: 
        !           352:     if (notstarted(process)) {
        !           353:        error("program is not active");
        !           354:     } else {
        !           355:        save = walkingstack;
        !           356:        walkingstack = true;
        !           357:        frp = &frame;
        !           358:        getcurframe(frp);
        !           359:        f = whatblock(frp->save_pc);
        !           360:        do {
        !           361:            printf("%s", symname(f));
        !           362:            if (not isinline(f)) {
        !           363:                printparams(f, frp);
        !           364:            }
        !           365:            line = srcline(frp->save_pc - 1);
        !           366:            if (line != 0) {
        !           367:                printf(", line %d", line);
        !           368:                printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
        !           369:            } else {
        !           370:                printf(" at 0x%x\n", frp->save_pc);
        !           371:            }
        !           372:            if (dumpvariables) {
        !           373:                dumpvars(f, frp);
        !           374:                putchar('\n');
        !           375:            }
        !           376:            if (isinline(f)) {
        !           377:                f = container(f);
        !           378:            } else {
        !           379:                frp = nextframe(frp);
        !           380:                if (frp != nil) {
        !           381:                    f = whatblock(frp->save_pc);
        !           382:                }
        !           383:            }
        !           384:        } while (frp != nil and f != program);
        !           385:        if (dumpvariables) {
        !           386:            printf("in \"%s\":\n", symname(program));
        !           387:            dumpvars(program, nil);
        !           388:            putchar('\n');
        !           389:        }
        !           390:        walkingstack = save;
        !           391:     }
        !           392: }
        !           393: 
        !           394: /*
        !           395:  * Find the entry point of a procedure or function.
        !           396:  */
        !           397: 
        !           398: public findbeginning(f)
        !           399: Symbol f;
        !           400: {
        !           401:     f->symvalue.funcv.beginaddr += 2;
        !           402: }
        !           403: 
        !           404: /*
        !           405:  * Return the address corresponding to the first line in a function.
        !           406:  */
        !           407: 
        !           408: public Address firstline(f)
        !           409: Symbol f;
        !           410: {
        !           411:     Address addr;
        !           412: 
        !           413:     addr = codeloc(f);
        !           414:     while (linelookup(addr) == 0 and addr < objsize) {
        !           415:        ++addr;
        !           416:     }
        !           417:     if (addr == objsize) {
        !           418:        addr = -1;
        !           419:     }
        !           420:     return addr;
        !           421: }
        !           422: 
        !           423: /*
        !           424:  * Catcher drops strike three ...
        !           425:  */
        !           426: 
        !           427: public runtofirst()
        !           428: {
        !           429:     Address addr;
        !           430: 
        !           431:     addr = pc;
        !           432:     while (linelookup(addr) == 0 and addr < objsize) {
        !           433:        ++addr;
        !           434:     }
        !           435:     if (addr < objsize) {
        !           436:        stepto(addr);
        !           437:     }
        !           438: }
        !           439: 
        !           440: /*
        !           441:  * Return the address corresponding to the end of the program.
        !           442:  *
        !           443:  * We look for the entry to "exit".
        !           444:  */
        !           445: 
        !           446: public Address lastaddr()
        !           447: {
        !           448:     register Symbol s;
        !           449: 
        !           450:     s = lookup(identname("exit", true));
        !           451:     if (s == nil) {
        !           452:        panic("can't find exit");
        !           453:     }
        !           454:     return codeloc(s);
        !           455: }
        !           456: 
        !           457: /*
        !           458:  * Decide if the given function is currently active.
        !           459:  *
        !           460:  * We avoid calls to "findframe" during a stack trace for efficiency.
        !           461:  * Presumably information evaluated while walking the stack is active.
        !           462:  */
        !           463: 
        !           464: public Boolean isactive(f)
        !           465: Symbol f;
        !           466: {
        !           467:     register Boolean b;
        !           468: 
        !           469:     if (isfinished(process)) {
        !           470:        b = false;
        !           471:     } else {
        !           472:        if (walkingstack or f == program or
        !           473:          (ismodule(f) and isactive(container(f)))) {
        !           474:            b = true;
        !           475:        } else {
        !           476:            b = (Boolean) (findframe(f) != nil);
        !           477:        }
        !           478:     }
        !           479:     return b;
        !           480: }
        !           481: 
        !           482: /*
        !           483:  * Evaluate a call to a procedure.
        !           484:  */
        !           485: 
        !           486: public callproc(procnode, arglist)
        !           487: Node procnode;
        !           488: Node arglist;
        !           489: {
        !           490:     Symbol proc;
        !           491:     Integer argc;
        !           492: 
        !           493:     if (procnode->op != O_SYM) {
        !           494:        beginerrmsg();
        !           495:        fprintf(stderr, "can't call \"");
        !           496:        prtree(stderr, procnode);
        !           497:        fprintf(stderr, "\"");
        !           498:        enderrmsg();
        !           499:     }
        !           500:     assert(procnode->op == O_SYM);
        !           501:     proc = procnode->value.sym;
        !           502:     if (not isblock(proc)) {
        !           503:        error("\"%s\" is not a procedure or function", symname(proc));
        !           504:     }
        !           505:     pushenv();
        !           506:     pc = codeloc(proc);
        !           507:     argc = pushargs(proc, arglist);
        !           508:     beginproc(proc, argc);
        !           509:     isstopped = true;
        !           510:     event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
        !           511:        buildcmdlist(build(O_PROCRTN, proc)));
        !           512:     cont();
        !           513:     /* NOTREACHED */
        !           514: }
        !           515: 
        !           516: /*
        !           517:  * Push the arguments on the process' stack.  We do this by first
        !           518:  * evaluating them on the "eval" stack, then copying into the process'
        !           519:  * space.
        !           520:  */
        !           521: 
        !           522: private Integer pushargs(proc, arglist)
        !           523: Symbol proc;
        !           524: Node arglist;
        !           525: {
        !           526:     Stack *savesp;
        !           527:     int argc, args_size;
        !           528: 
        !           529:     savesp = sp;
        !           530:     argc = evalargs(proc, arglist);
        !           531:     args_size = sp - savesp;
        !           532:     setreg(STKP, reg(STKP) - args_size);
        !           533:     dwrite(savesp, reg(STKP), args_size);
        !           534:     sp = savesp;
        !           535:     return argc;
        !           536: }
        !           537: 
        !           538: /*
        !           539:  * Evaluate arguments left-to-right.
        !           540:  */
        !           541: 
        !           542: private Integer evalargs(proc, arglist)
        !           543: Symbol proc;
        !           544: Node arglist;
        !           545: {
        !           546:     Node p, exp;
        !           547:     Symbol arg;
        !           548:     Stack *savesp;
        !           549:     Address addr;
        !           550:     Integer count;
        !           551: 
        !           552:     savesp = sp;
        !           553:     count = 0;
        !           554:     arg = proc->chain;
        !           555:     for (p = arglist; p != nil; p = p->value.arg[1]) {
        !           556:        if (p->op != O_COMMA) {
        !           557:            panic("evalargs: arglist missing comma");
        !           558:        }
        !           559:        if (arg == nil) {
        !           560:            sp = savesp;
        !           561:            error("too many parameters to %s", symname(proc));
        !           562:        }
        !           563:        exp = p->value.arg[0];
        !           564:        if (not compatible(arg->type, exp->nodetype)) {
        !           565:            sp = savesp;
        !           566:            error("expression for parameter %s is of wrong type", symname(arg));
        !           567:        }
        !           568:        if (arg->class == REF) {
        !           569:            if (exp->op != O_RVAL) {
        !           570:                sp = savesp;
        !           571:                error("variable expected for parameter \"%s\"", symname(arg));
        !           572:            }
        !           573:            addr = lval(exp->value.arg[0]);
        !           574:            push(Address, addr);
        !           575:        } else {
        !           576:            eval(exp);
        !           577:        }
        !           578:        arg = arg->chain;
        !           579:        ++count;
        !           580:     }
        !           581:     if (arg != nil) {
        !           582:        sp = savesp;
        !           583:        error("not enough parameters to %s", symname(proc));
        !           584:     }
        !           585:     return count;
        !           586: }
        !           587: 
        !           588: public procreturn(f)
        !           589: Symbol f;
        !           590: {
        !           591:     flushoutput();
        !           592:     putchar('\n');
        !           593:     printname(stdout, f);
        !           594:     printf(" returns successfully\n", symname(f));
        !           595:     popenv();
        !           596:     erecover();
        !           597: }
        !           598: 
        !           599: /*
        !           600:  * Push the current environment.
        !           601:  */
        !           602: 
        !           603: private pushenv()
        !           604: {
        !           605:     push(Address, pc);
        !           606:     push(Lineno, curline);
        !           607:     push(String, cursource);
        !           608:     push(Boolean, isstopped);
        !           609:     push(Symbol, curfunc);
        !           610:     push(Word, reg(PROGCTR));
        !           611:     push(Word, reg(STKP));
        !           612: }
        !           613: 
        !           614: /*
        !           615:  * Pop back to the real world.
        !           616:  */
        !           617: 
        !           618: public popenv()
        !           619: {
        !           620:     register String filename;
        !           621: 
        !           622:     setreg(STKP, pop(Word));
        !           623:     setreg(PROGCTR, pop(Word));
        !           624:     curfunc = pop(Symbol);
        !           625:     isstopped = pop(Boolean);
        !           626:     filename = pop(String);
        !           627:     curline = pop(Lineno);
        !           628:     pc = pop(Address);
        !           629:     setsource(filename);
        !           630: }
        !           631: 
        !           632: /*
        !           633:  * Flush the debuggee's standard output.
        !           634:  *
        !           635:  * This is VERY dependent on the use of stdio.
        !           636:  */
        !           637: 
        !           638: public flushoutput()
        !           639: {
        !           640:     register Symbol p, iob;
        !           641:     register Stack *savesp;
        !           642: 
        !           643:     p = lookup(identname("fflush", true));
        !           644:     while (p != nil and not isblock(p)) {
        !           645:        p = p->next_sym;
        !           646:     }
        !           647:     if (p != nil) {
        !           648:        iob = lookup(identname("_iob", true));
        !           649:        if (iob != nil) {
        !           650:            pushenv();
        !           651:            pc = codeloc(p);
        !           652:            savesp = sp;
        !           653:            push(long, address(iob, nil) + sizeof(struct _iobuf));
        !           654:            setreg(STKP, reg(STKP) - sizeof(long));
        !           655:            dwrite(savesp, reg(STKP), sizeof(long));
        !           656:            sp = savesp;
        !           657:            beginproc(p, 1);
        !           658:            stepto(return_addr());
        !           659:            popenv();
        !           660:        }
        !           661:     }
        !           662: }

unix.superglobalmegacorp.com

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