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: }