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