1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)runtime.c	5.2 (Berkeley) 1/10/86";
   9: #endif not lint
  10: 
  11: static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $";
  12: 
  13: /*
  14:  * Runtime organization dependent routines, mostly dealing with
  15:  * activation records.
  16:  */
  17: 
  18: #include "defs.h"
  19: #include "runtime.h"
  20: #include "process.h"
  21: #include "machine.h"
  22: #include "events.h"
  23: #include "mappings.h"
  24: #include "symbols.h"
  25: #include "tree.h"
  26: #include "eval.h"
  27: #include "operators.h"
  28: #include "object.h"
  29: #include <sys/param.h>
  30: 
  31: #ifndef public
  32: typedef struct Frame *Frame;
  33: 
  34: #include "machine.h"
  35: #endif
  36: 
  37: #define NSAVEREG 12
  38: 
  39: struct Frame {
  40:     integer condition_handler;
  41:     integer mask;
  42:     Address save_ap;        /* argument pointer */
  43:     Address save_fp;        /* frame pointer */
  44:     Address save_pc;        /* program counter */
  45:     Word save_reg[NSAVEREG];    /* not necessarily there */
  46: };
  47: 
  48: private Frame curframe = nil;
  49: private struct Frame curframerec;
  50: private Boolean walkingstack = false;
  51: 
  52: #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
  53: 
  54: #define isstackaddr(addr) \
  55:     (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * UPAGES))
  56: 
  57: typedef struct {
  58:     Node callnode;
  59:     Node cmdnode;
  60:     boolean isfunc;
  61: } CallEnv;
  62: 
  63: private CallEnv endproc;
  64: 
  65: /*
  66:  * Set a frame to the current activation record.
  67:  */
  68: 
  69: private getcurframe(frp)
  70: Frame frp;
  71: {
  72:     register int i;
  73: 
  74:     checkref(frp);
  75:     frp->mask = reg(NREG);
  76:     frp->save_ap = reg(ARGP);
  77:     frp->save_fp = reg(FRP);
  78:     frp->save_pc = reg(PROGCTR);
  79:     for (i = 0; i < NSAVEREG; i++) {
  80:     frp->save_reg[i] = reg(i);
  81:     }
  82: }
  83: 
  84: /*
  85:  * Get the saved registers from one frame to another
  86:  * given mask specifying which registers were actually saved.
  87:  */
  88: 
  89: #define bis(b, n) ((b & (1 << (n))) != 0)
  90: 
  91: private getsaveregs (newfrp, frp, mask)
  92: Frame newfrp, frp;
  93: integer mask;
  94: {
  95:     integer i, j;
  96: 
  97:     j = 0;
  98:     for (i = 0; i < NSAVEREG; i++) {
  99:     if (bis(mask, i)) {
 100:         newfrp->save_reg[i] = frp->save_reg[j];
 101:         ++j;
 102:     }
 103:     }
 104: }
 105: 
 106: /*
 107:  * Return a pointer to the next activation record up the stack.
 108:  * Return nil if there is none.
 109:  * Writes over space pointed to by given argument.
 110:  */
 111: 
 112: private Frame nextframe(frp)
 113: Frame frp;
 114: {
 115:     Frame newfrp;
 116:     struct Frame frame;
 117:     integer mask;
 118:     Address prev_frame, callpc;
 119:     static integer ntramp = 0;
 120: 
 121:     newfrp = frp;
 122:     prev_frame = frp->save_fp;
 123: 
 124: /*
 125:  *  The check for interrupt generated frames is taken from adb with only
 126:  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
 127:  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
 128:  *
 129:  *  As best I can make out it looks like:
 130:  *
 131:  *     <main, (machine check exception block + sub), sysframe, sigsub>.
 132:  *
 133:  *  When the signal occurs an exception block and a frame for the routine
 134:  *  in which it occured are pushed on the user stack.  Then another frame
 135:  *  is pushed corresponding to a call from the kernel to sigsub.
 136:  *
 137:  *  The addr in sub at which the exception occured is not in sub.save_pc
 138:  *  but in the machine check exception block.  It is at the magic address
 139:  *  fp + 84.
 140:  *
 141:  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
 142:  *  and takes the pc for sub from the exception block.  This allows the
 143:  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
 144:  */
 145: 
 146: nextf:
 147:     dread(&frame, prev_frame, sizeof(struct Frame));
 148:     if (ntramp == 1) {
 149:     dread(&callpc, prev_frame + 84, sizeof(callpc));
 150:     } else {
 151:     callpc = frame.save_pc;
 152:     }
 153:     if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
 154:     newfrp = nil;
 155:     } else if (isstackaddr(callpc)) {
 156:     ntramp++;
 157:     prev_frame = frame.save_fp;
 158:     goto nextf;
 159:     } else {
 160:     frame.save_pc = callpc;
 161:         ntramp = 0;
 162:     mask = ((frame.mask >> 16) & 0x0fff);
 163:     getsaveregs(newfrp, &frame, mask);
 164:     newfrp->condition_handler = frame.condition_handler;
 165:     newfrp->mask = mask;
 166:     newfrp->save_ap = frame.save_ap;
 167:     newfrp->save_fp = frame.save_fp;
 168:     newfrp->save_pc = frame.save_pc;
 169:     }
 170:     return newfrp;
 171: }
 172: 
 173: /*
 174:  * Get the current frame information in the given Frame and store the
 175:  * associated function in the given value-result parameter.
 176:  */
 177: 
 178: private getcurfunc (frp, fp)
 179: Frame frp;
 180: Symbol *fp;
 181: {
 182:     getcurframe(frp);
 183:     *fp = whatblock(frp->save_pc);
 184: }
 185: 
 186: /*
 187:  * Return the frame associated with the next function up the call stack, or
 188:  * nil if there is none.  The function is returned in a value-result parameter.
 189:  * For "inline" functions the statically outer function and same frame
 190:  * are returned.
 191:  */
 192: 
 193: public Frame nextfunc (frp, fp)
 194: Frame frp;
 195: Symbol *fp;
 196: {
 197:     Symbol t;
 198:     Frame nfrp;
 199: 
 200:     t = *fp;
 201:     checkref(t);
 202:     if (isinline(t)) {
 203:     t = container(t);
 204:     nfrp = frp;
 205:     } else {
 206:     nfrp = nextframe(frp);
 207:     if (nfrp == nil) {
 208:         t = nil;
 209:     } else {
 210:         t = whatblock(nfrp->save_pc);
 211:     }
 212:     }
 213:     *fp = t;
 214:     return nfrp;
 215: }
 216: 
 217: /*
 218:  * Return the frame associated with the given function.
 219:  * If the function is nil, return the most recently activated frame.
 220:  *
 221:  * Static allocation for the frame.
 222:  */
 223: 
 224: public Frame findframe(f)
 225: Symbol f;
 226: {
 227:     Frame frp;
 228:     static struct Frame frame;
 229:     Symbol p;
 230:     Boolean done;
 231: 
 232:     frp = &frame;
 233:     getcurframe(frp);
 234:     if (f != nil) {
 235:     if (f == curfunc and curframe != nil) {
 236:         *frp = *curframe;
 237:     } else {
 238:         done = false;
 239:         p = whatblock(frp->save_pc);
 240:         do {
 241:         if (p == f) {
 242:             done = true;
 243:         } else if (p == program) {
 244:             done = true;
 245:             frp = nil;
 246:         } else {
 247:             frp = nextfunc(frp, &p);
 248:             if (frp == nil) {
 249:             done = true;
 250:             }
 251:         }
 252:         } while (not done);
 253:     }
 254:     }
 255:     return frp;
 256: }
 257: 
 258: /*
 259:  * Set the registers according to the given frame pointer.
 260:  */
 261: 
 262: public getnewregs (addr)
 263: Address addr;
 264: {
 265:     struct Frame frame;
 266:     integer i, j, mask;
 267: 
 268:     dread(&frame, addr, sizeof(frame));
 269:     setreg(ARGP, frame.save_ap);
 270:     setreg(FRP, frame.save_fp);
 271:     setreg(PROGCTR, frame.save_pc);
 272:     mask = ((frame.mask >> 16) & 0x0fff);
 273:     j = 0;
 274:     for (i = 0; i < NSAVEREG; i++) {
 275:     if (bis(mask, i)) {
 276:         setreg(i, frame.save_reg[j]);
 277:         ++j;
 278:     }
 279:     }
 280:     pc = frame.save_pc;
 281:     setcurfunc(whatblock(pc));
 282: }
 283: 
 284: /*
 285:  * Find the return address of the current procedure/function.
 286:  */
 287: 
 288: public Address return_addr()
 289: {
 290:     Frame frp;
 291:     Address addr;
 292:     struct Frame frame;
 293: 
 294:     frp = &frame;
 295:     getcurframe(frp);
 296:     frp = nextframe(frp);
 297:     if (frp == nil) {
 298:     addr = 0;
 299:     } else {
 300:     addr = frp->save_pc;
 301:     }
 302:     return addr;
 303: }
 304: 
 305: /*
 306:  * Push the value associated with the current function.
 307:  */
 308: 
 309: public pushretval(len, isindirect)
 310: integer len;
 311: boolean isindirect;
 312: {
 313:     Word r0;
 314: 
 315:     r0 = reg(0);
 316:     if (isindirect) {
 317:     rpush((Address) r0, len);
 318:     } else {
 319:     switch (len) {
 320:         case sizeof(char):
 321:         push(char, r0);
 322:         break;
 323: 
 324:         case sizeof(short):
 325:         push(short, r0);
 326:         break;
 327: 
 328:         default:
 329:         if (len == sizeof(Word)) {
 330:             push(Word, r0);
 331:         } else if (len == 2*sizeof(Word)) {
 332:             push(Word, r0);
 333:             push(Word, reg(1));
 334:         } else {
 335:             error("[internal error: bad size %d in pushretval]", len);
 336:         }
 337:         break;
 338:     }
 339:     }
 340: }
 341: 
 342: /*
 343:  * Return the base address for locals in the given frame.
 344:  */
 345: 
 346: public Address locals_base(frp)
 347: Frame frp;
 348: {
 349:     return (frp == nil) ? reg(FRP) : frp->save_fp;
 350: }
 351: 
 352: /*
 353:  * Return the base address for arguments in the given frame.
 354:  */
 355: 
 356: public Address args_base(frp)
 357: Frame frp;
 358: {
 359:     return (frp == nil) ? reg(ARGP) : frp->save_ap;
 360: }
 361: 
 362: /*
 363:  * Return saved register n from the given frame.
 364:  */
 365: 
 366: public Word savereg(n, frp)
 367: integer n;
 368: Frame frp;
 369: {
 370:     Word w;
 371: 
 372:     if (frp == nil) {
 373:     w = reg(n);
 374:     } else {
 375:     switch (n) {
 376:         case ARGP:
 377:         w = frp->save_ap;
 378:         break;
 379: 
 380:         case FRP:
 381:         w = frp->save_fp;
 382:         break;
 383: 
 384:         case STKP:
 385:         w = reg(STKP);
 386:         break;
 387: 
 388:         case PROGCTR:
 389:         w = frp->save_pc;
 390:         break;
 391: 
 392:         default:
 393:         assert(n >= 0 and n < NSAVEREG);
 394:         w = frp->save_reg[n];
 395:         break;
 396:     }
 397:     }
 398:     return w;
 399: }
 400: 
 401: /*
 402:  * Return the nth argument to the current procedure.
 403:  */
 404: 
 405: public Word argn(n, frp)
 406: integer n;
 407: Frame frp;
 408: {
 409:     Word w;
 410: 
 411:     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
 412:     return w;
 413: }
 414: 
 415: /*
 416:  * Print a list of currently active blocks starting with most recent.
 417:  */
 418: 
 419: public wherecmd()
 420: {
 421:     walkstack(false);
 422: }
 423: 
 424: /*
 425:  * Print the variables in the given frame or the current one if nil.
 426:  */
 427: 
 428: public dump (func)
 429: Symbol func;
 430: {
 431:     Symbol f;
 432:     Frame frp;
 433: 
 434:     if (func == nil) {
 435:     f = curfunc;
 436:     if (curframe != nil) {
 437:         frp = curframe;
 438:     } else {
 439:         frp = findframe(f);
 440:     }
 441:     } else {
 442:     f = func;
 443:     frp = findframe(f);
 444:     }
 445:     showaggrs = true;
 446:     printcallinfo(f, frp);
 447:     dumpvars(f, frp);
 448: }
 449: 
 450: /*
 451:  * Dump all values.
 452:  */
 453: 
 454: public dumpall ()
 455: {
 456:     walkstack(true);
 457: }
 458: 
 459: /*
 460:  * Walk the stack of active procedures printing information
 461:  * about each active procedure.
 462:  */
 463: 
 464: private walkstack(dumpvariables)
 465: Boolean dumpvariables;
 466: {
 467:     Frame frp;
 468:     boolean save;
 469:     Symbol f;
 470:     struct Frame frame;
 471: 
 472:     if (notstarted(process) or isfinished(process)) {
 473:     error("program is not active");
 474:     } else {
 475:     save = walkingstack;
 476:     walkingstack = true;
 477:     showaggrs = dumpvariables;
 478:     frp = &frame;
 479:     getcurfunc(frp, &f);
 480:     for (;;) {
 481:         printcallinfo(f, frp);
 482:         if (dumpvariables) {
 483:         dumpvars(f, frp);
 484:         putchar('\n');
 485:         }
 486:         frp = nextfunc(frp, &f);
 487:         if (frp == nil or f == program) {
 488:         break;
 489:         }
 490:     }
 491:     if (dumpvariables) {
 492:         printf("in \"%s\":\n", symname(program));
 493:         dumpvars(program, nil);
 494:         putchar('\n');
 495:     }
 496:     walkingstack = save;
 497:     }
 498: }
 499: 
 500: /*
 501:  * Print out the information about a call, i.e.,
 502:  * routine name, parameter values, and source location.
 503:  */
 504: 
 505: private printcallinfo (f, frp)
 506: Symbol f;
 507: Frame frp;
 508: {
 509:     Lineno line;
 510:     Address savepc;
 511: 
 512:     savepc = frp->save_pc;
 513:     if (frp->save_fp != reg(FRP)) {
 514:     savepc -= 1;
 515:     }
 516:     printname(stdout, f);
 517:     if (not isinline(f)) {
 518:     printparams(f, frp);
 519:     }
 520:     line = srcline(savepc);
 521:     if (line != 0) {
 522:     printf(", line %d", line);
 523:     printf(" in \"%s\"\n", srcfilename(savepc));
 524:     } else {
 525:     printf(" at 0x%x\n", savepc);
 526:     }
 527: }
 528: 
 529: /*
 530:  * Set the current function to the given symbol.
 531:  * We must adjust "curframe" so that subsequent operations are
 532:  * not confused; for simplicity we simply clear it.
 533:  */
 534: 
 535: public setcurfunc (f)
 536: Symbol f;
 537: {
 538:     curfunc = f;
 539:     curframe = nil;
 540: }
 541: 
 542: /*
 543:  * Return the frame for the current function.
 544:  * The space for the frame is allocated statically.
 545:  */
 546: 
 547: public Frame curfuncframe ()
 548: {
 549:     static struct Frame frame;
 550:     Frame frp;
 551: 
 552:     if (curframe == nil) {
 553:     frp = findframe(curfunc);
 554:     curframe = &curframerec;
 555:     *curframe = *frp;
 556:     } else {
 557:     frp = &frame;
 558:     *frp = *curframe;
 559:     }
 560:     return frp;
 561: }
 562: 
 563: /*
 564:  * Set curfunc to be N up/down the stack from its current value.
 565:  */
 566: 
 567: public up (n)
 568: integer n;
 569: {
 570:     integer i;
 571:     Symbol f;
 572:     Frame frp;
 573:     boolean done;
 574: 
 575:     if (not isactive(program)) {
 576:     error("program is not active");
 577:     } else if (curfunc == nil) {
 578:     error("no current function");
 579:     } else {
 580:     i = 0;
 581:     f = curfunc;
 582:     frp = curfuncframe();
 583:     done = false;
 584:     do {
 585:         if (frp == nil) {
 586:         done = true;
 587:         error("not that many levels");
 588:         } else if (i >= n) {
 589:         done = true;
 590:         curfunc = f;
 591:         curframe = &curframerec;
 592:         *curframe = *frp;
 593:         showaggrs = false;
 594:         printcallinfo(curfunc, curframe);
 595:         } else if (f == program) {
 596:         done = true;
 597:         error("not that many levels");
 598:         } else {
 599:         frp = nextfunc(frp, &f);
 600:         }
 601:         ++i;
 602:     } while (not done);
 603:     }
 604: }
 605: 
 606: public down (n)
 607: integer n;
 608: {
 609:     integer i, depth;
 610:     Frame frp, curfrp;
 611:     Symbol f;
 612:     struct Frame frame;
 613: 
 614:     if (not isactive(program)) {
 615:     error("program is not active");
 616:     } else if (curfunc == nil) {
 617:     error("no current function");
 618:     } else {
 619:     depth = 0;
 620:     frp = &frame;
 621:     getcurfunc(frp, &f);
 622:     if (curframe == nil) {
 623:         curfrp = findframe(curfunc);
 624:         curframe = &curframerec;
 625:         *curframe = *curfrp;
 626:     }
 627:     while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
 628:         frp = nextfunc(frp, &f);
 629:         ++depth;
 630:     }
 631:     if (f == nil or n > depth) {
 632:         error("not that many levels");
 633:     } else {
 634:         depth -= n;
 635:         frp = &frame;
 636:         getcurfunc(frp, &f);
 637:         for (i = 0; i < depth; i++) {
 638:         frp = nextfunc(frp, &f);
 639:         assert(frp != nil);
 640:         }
 641:         curfunc = f;
 642:         *curframe = *frp;
 643:         showaggrs = false;
 644:         printcallinfo(curfunc, curframe);
 645:     }
 646:     }
 647: }
 648: 
 649: /*
 650:  * Find the entry point of a procedure or function.
 651:  */
 652: 
 653: public findbeginning (f)
 654: Symbol f;
 655: {
 656:     if (isinternal(f)) {
 657:     f->symvalue.funcv.beginaddr += 15;
 658:     } else {
 659:     f->symvalue.funcv.beginaddr += 2;
 660:     }
 661: }
 662: 
 663: /*
 664:  * Return the address corresponding to the first line in a function.
 665:  */
 666: 
 667: public Address firstline(f)
 668: Symbol f;
 669: {
 670:     Address addr;
 671: 
 672:     addr = codeloc(f);
 673:     while (linelookup(addr) == 0 and addr < objsize) {
 674:     ++addr;
 675:     }
 676:     if (addr == objsize) {
 677:     addr = -1;
 678:     }
 679:     return addr;
 680: }
 681: 
 682: /*
 683:  * Catcher drops strike three ...
 684:  */
 685: 
 686: public runtofirst()
 687: {
 688:     Address addr;
 689: 
 690:     addr = pc;
 691:     while (linelookup(addr) == 0 and addr < objsize) {
 692:     ++addr;
 693:     }
 694:     if (addr < objsize) {
 695:     stepto(addr);
 696:     }
 697: }
 698: 
 699: /*
 700:  * Return the address corresponding to the end of the program.
 701:  *
 702:  * We look for the entry to "exit".
 703:  */
 704: 
 705: public Address lastaddr()
 706: {
 707:     Symbol s;
 708: 
 709:     s = lookup(identname("exit", true));
 710:     if (s == nil) {
 711:     panic("can't find exit");
 712:     }
 713:     return codeloc(s);
 714: }
 715: 
 716: /*
 717:  * Decide if the given function is currently active.
 718:  *
 719:  * We avoid calls to "findframe" during a stack trace for efficiency.
 720:  * Presumably information evaluated while walking the stack is active.
 721:  */
 722: 
 723: public Boolean isactive(f)
 724: Symbol f;
 725: {
 726:     Boolean b;
 727: 
 728:     if (isfinished(process)) {
 729:     b = false;
 730:     } else {
 731:     if (walkingstack or f == program or
 732:       (ismodule(f) and isactive(container(f)))) {
 733:         b = true;
 734:     } else {
 735:         b = (Boolean) (findframe(f) != nil);
 736:     }
 737:     }
 738:     return b;
 739: }
 740: 
 741: /*
 742:  * Evaluate a call to a procedure.
 743:  */
 744: 
 745: public callproc(exprnode, isfunc)
 746: Node exprnode;
 747: boolean isfunc;
 748: {
 749:     Node procnode, arglist;
 750:     Symbol proc;
 751:     integer argc;
 752: 
 753:     procnode = exprnode->value.arg[0];
 754:     arglist = exprnode->value.arg[1];
 755:     if (procnode->op != O_SYM) {
 756:     beginerrmsg();
 757:     fprintf(stderr, "can't call \"");
 758:     prtree(stderr, procnode);
 759:     fprintf(stderr, "\"");
 760:     enderrmsg();
 761:     }
 762:     assert(procnode->op == O_SYM);
 763:     proc = procnode->value.sym;
 764:     if (not isblock(proc)) {
 765:     error("\"%s\" is not a procedure or function", symname(proc));
 766:     }
 767:     endproc.isfunc = isfunc;
 768:     endproc.callnode = exprnode;
 769:     endproc.cmdnode = topnode;
 770:     pushenv();
 771:     pc = codeloc(proc);
 772:     argc = pushargs(proc, arglist);
 773:     beginproc(proc, argc);
 774:     event_once(
 775:     build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
 776:     buildcmdlist(build(O_PROCRTN, proc))
 777:     );
 778:     isstopped = false;
 779:     if (not bpact()) {
 780:     isstopped = true;
 781:     cont(0);
 782:     }
 783:     /*
 784:      * bpact() won't return true, it will call printstatus() and go back
 785:      * to command input if a breakpoint is found.
 786:      */
 787:     /* NOTREACHED */
 788: }
 789: 
 790: /*
 791:  * Push the arguments on the process' stack.  We do this by first
 792:  * evaluating them on the "eval" stack, then copying into the process'
 793:  * space.
 794:  */
 795: 
 796: private integer pushargs(proc, arglist)
 797: Symbol proc;
 798: Node arglist;
 799: {
 800:     Stack *savesp;
 801:     int argc, args_size;
 802: 
 803:     savesp = sp;
 804:     if (varIsSet("$unsafecall")) {
 805:     argc = unsafe_evalargs(proc, arglist);
 806:     } else {
 807:     argc = evalargs(proc, arglist);
 808:     }
 809:     args_size = sp - savesp;
 810:     setreg(STKP, reg(STKP) - args_size);
 811:     dwrite(savesp, reg(STKP), args_size);
 812:     sp = savesp;
 813:     return argc;
 814: }
 815: 
 816: /*
 817:  * Check to see if an expression is correct for a given parameter.
 818:  * If the given parameter is false, don't worry about type inconsistencies.
 819:  *
 820:  * Return whether or not it is ok.
 821:  */
 822: 
 823: private boolean chkparam (actual, formal, chk)
 824: Node actual;
 825: Symbol formal;
 826: boolean chk;
 827: {
 828:     boolean b;
 829: 
 830:     b = true;
 831:     if (chk) {
 832:     if (formal == nil) {
 833:         beginerrmsg();
 834:         fprintf(stderr, "too many parameters");
 835:         b = false;
 836:     } else if (not compatible(formal->type, actual->nodetype)) {
 837:         beginerrmsg();
 838:         fprintf(stderr, "type mismatch for %s", symname(formal));
 839:         b = false;
 840:     }
 841:     }
 842:     if (b and formal != nil and
 843:     isvarparam(formal) and not isopenarray(formal->type) and
 844:     not (
 845:         actual->op == O_RVAL or actual->nodetype == t_addr or
 846:         (
 847:         actual->op == O_TYPERENAME and
 848:         (
 849:             actual->value.arg[0]->op == O_RVAL or
 850:             actual->value.arg[0]->nodetype == t_addr
 851:         )
 852:         )
 853:     )
 854:     ) {
 855:     beginerrmsg();
 856:     fprintf(stderr, "expected variable, found \"");
 857:     prtree(stderr, actual);
 858:     fprintf(stderr, "\"");
 859:     b = false;
 860:     }
 861:     return b;
 862: }
 863: 
 864: /*
 865:  * Pass an expression to a particular parameter.
 866:  *
 867:  * Normally we pass either the address or value, but in some cases
 868:  * (such as C strings) we want to copy the value onto the stack and
 869:  * pass its address.
 870:  *
 871:  * Another special case raised by strings is the possibility that
 872:  * the actual parameter will be larger than the formal, even with
 873:  * appropriate type-checking.  This occurs because we assume during
 874:  * evaluation that strings are null-terminated, whereas some languages,
 875:  * notably Pascal, do not work under that assumption.
 876:  */
 877: 
 878: private passparam (actual, formal)
 879: Node actual;
 880: Symbol formal;
 881: {
 882:     boolean b;
 883:     Address addr;
 884:     Stack *savesp;
 885:     integer actsize, formsize;
 886: 
 887:     if (formal != nil and isvarparam(formal) and
 888:     (not isopenarray(formal->type))
 889:     ) {
 890:     addr = lval(actual->value.arg[0]);
 891:     push(Address, addr);
 892:     } else if (passaddr(formal, actual->nodetype)) {
 893:     savesp = sp;
 894:     eval(actual);
 895:     actsize = sp - savesp;
 896:     setreg(STKP,
 897:         reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
 898:     );
 899:     dwrite(savesp, reg(STKP), actsize);
 900:     sp = savesp;
 901:     push(Address, reg(STKP));
 902:     if (formal != nil and isopenarray(formal->type)) {
 903:         push(integer, actsize div size(formal->type->type));
 904:     }
 905:     } else if (formal != nil) {
 906:     formsize = size(formal);
 907:     savesp = sp;
 908:     eval(actual);
 909:     actsize = sp - savesp;
 910:     if (actsize > formsize) {
 911:         sp -= (actsize - formsize);
 912:     }
 913:     } else {
 914:     eval(actual);
 915:     }
 916: }
 917: 
 918: /*
 919:  * Evaluate an argument list left-to-right.
 920:  */
 921: 
 922: private integer evalargs(proc, arglist)
 923: Symbol proc;
 924: Node arglist;
 925: {
 926:     Node p, actual;
 927:     Symbol formal;
 928:     Stack *savesp;
 929:     integer count;
 930:     boolean chk;
 931: 
 932:     savesp = sp;
 933:     count = 0;
 934:     formal = proc->chain;
 935:     chk = (boolean) (not nosource(proc));
 936:     for (p = arglist; p != nil; p = p->value.arg[1]) {
 937:     assert(p->op == O_COMMA);
 938:     actual = p->value.arg[0];
 939:     if (not chkparam(actual, formal, chk)) {
 940:         fprintf(stderr, " in call to %s", symname(proc));
 941:         sp = savesp;
 942:         enderrmsg();
 943:     }
 944:     passparam(actual, formal);
 945:     if (formal != nil) {
 946:         formal = formal->chain;
 947:     }
 948:     ++count;
 949:     }
 950:     if (chk) {
 951:     if (formal != nil) {
 952:         sp = savesp;
 953:         error("not enough parameters to %s", symname(proc));
 954:     }
 955:     }
 956:     return count;
 957: }
 958: 
 959: /*
 960:  * Evaluate an argument list without concern for matching the formal
 961:  * parameters of a function in type or quantity.  Useful for functions
 962:  * like C's printf().
 963:  */
 964: 
 965: private integer unsafe_evalargs(proc, arglist)
 966: Symbol proc;
 967: Node arglist;
 968: {
 969:     Node p;
 970:     Integer count;
 971: 
 972:     count = 0;
 973:     for (p = arglist; p != nil; p = p->value.arg[1]) {
 974:     assert(p->op == O_COMMA);
 975:     eval(p->value.arg[0]);
 976:     ++count;
 977:     }
 978:     return count;
 979: }
 980: 
 981: public procreturn(f)
 982: Symbol f;
 983: {
 984:     integer retvalsize;
 985:     Node tmp;
 986:     char *copy;
 987: 
 988:     flushoutput();
 989:     popenv();
 990:     if (endproc.isfunc) {
 991:     retvalsize = size(f->type);
 992:     if (retvalsize > sizeof(long)) {
 993:         pushretval(retvalsize, true);
 994:         copy = newarr(char, retvalsize);
 995:         popn(retvalsize, copy);
 996:         tmp = build(O_SCON, copy);
 997:     } else {
 998:         tmp = build(O_LCON, (long) (reg(0)));
 999:     }
1000:     tmp->nodetype = f->type;
1001:     tfree(endproc.callnode);
1002:     *(endproc.callnode) = *(tmp);
1003:     dispose(tmp);
1004:     eval(endproc.cmdnode);
1005:     } else {
1006:     putchar('\n');
1007:     printname(stdout, f);
1008:     printf(" returns successfully\n", symname(f));
1009:     }
1010:     erecover();
1011: }
1012: 
1013: /*
1014:  * Push the current environment.
1015:  */
1016: 
1017: private pushenv()
1018: {
1019:     push(Address, pc);
1020:     push(Lineno, curline);
1021:     push(String, cursource);
1022:     push(Boolean, isstopped);
1023:     push(Symbol, curfunc);
1024:     push(Frame, curframe);
1025:     push(struct Frame, curframerec);
1026:     push(CallEnv, endproc);
1027:     push(Word, reg(PROGCTR));
1028:     push(Word, reg(STKP));
1029: }
1030: 
1031: /*
1032:  * Pop back to the real world.
1033:  */
1034: 
1035: public popenv()
1036: {
1037:     String filename;
1038: 
1039:     setreg(STKP, pop(Word));
1040:     setreg(PROGCTR, pop(Word));
1041:     endproc = pop(CallEnv);
1042:     curframerec = pop(struct Frame);
1043:     curframe = pop(Frame);
1044:     curfunc = pop(Symbol);
1045:     isstopped = pop(Boolean);
1046:     filename = pop(String);
1047:     curline = pop(Lineno);
1048:     pc = pop(Address);
1049:     setsource(filename);
1050: }
1051: 
1052: /*
1053:  * Flush the debuggee's standard output.
1054:  *
1055:  * This is VERY dependent on the use of stdio.
1056:  */
1057: 
1058: public flushoutput()
1059: {
1060:     Symbol p, iob;
1061:     Stack *savesp;
1062: 
1063:     p = lookup(identname("fflush", true));
1064:     while (p != nil and not isblock(p)) {
1065:     p = p->next_sym;
1066:     }
1067:     if (p != nil) {
1068:     iob = lookup(identname("_iob", true));
1069:     if (iob != nil) {
1070:         pushenv();
1071:         pc = codeloc(p);
1072:         savesp = sp;
1073:         push(long, address(iob, nil) + sizeof(struct _iobuf));
1074:         setreg(STKP, reg(STKP) - sizeof(long));
1075:         dwrite(savesp, reg(STKP), sizeof(long));
1076:         sp = savesp;
1077:         beginproc(p, 1);
1078:         stepto(return_addr());
1079:         popenv();
1080:     }
1081:     }
1082: }

Defined functions

argn defined in line 405; used 3 times
args_base defined in line 356; used 3 times
callproc defined in line 745; used 2 times
chkparam defined in line 823; used 1 times
curfuncframe defined in line 547; used 2 times
down defined in line 606; used 1 times
dump defined in line 428; used 2 times
dumpall defined in line 454; used 1 times
evalargs defined in line 922; used 1 times
findbeginning defined in line 653; used 6 times
findframe defined in line 224; used 7 times
firstline defined in line 667; used 3 times
flushoutput defined in line 1058; used 1 times
getcurframe defined in line 69; used 3 times
getcurfunc defined in line 178; used 3 times
getnewregs defined in line 262; used 1 times
getsaveregs defined in line 91; used 1 times
lastaddr defined in line 705; used 1 times
locals_base defined in line 346; used 2 times
nextframe defined in line 112; used 2 times
nextfunc defined in line 193; used 7 times
passparam defined in line 878; used 1 times
popenv defined in line 1035; used 2 times
printcallinfo defined in line 505; used 4 times
procreturn defined in line 981; used 1 times
pushargs defined in line 796; used 1 times
pushenv defined in line 1017; used 2 times
pushretval defined in line 309; used 2 times
runtofirst defined in line 686; never used
savereg defined in line 366; used 1 times
unsafe_evalargs defined in line 965; used 1 times
up defined in line 567; used 1 times
walkstack defined in line 464; used 2 times
wherecmd defined in line 419; used 1 times

Defined variables

curframe defined in line 48; used 20 times
curframerec defined in line 49; used 5 times
public defined in line 567; never used
rcsid defined in line 11; never used
sccsid defined in line 8; never used

Defined struct's

Frame defined in line 39; used 23 times

Defined typedef's

Frame defined in line 32; used 26 times

Defined macros

NSAVEREG defined in line 37; used 5 times
bis defined in line 89; used 2 times
frameeq defined in line 52; used 1 times
isstackaddr defined in line 54; used 1 times
Last modified: 1986-03-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2793
Valid CSS Valid XHTML 1.0 Strict