xref: /csrg-svn/old/dbx/runtime.vax.c (revision 13937)
112546Scsvaf 
29678Slinton /* Copyright (c) 1982 Regents of the University of California */
39678Slinton 
4*13937Slinton static char sccsid[] = "@(#)runtime.vax.c 1.7 07/15/83";
59678Slinton 
69678Slinton /*
79678Slinton  * Runtime organization dependent routines, mostly dealing with
89678Slinton  * activation records.
99678Slinton  */
109678Slinton 
119678Slinton #include "defs.h"
129678Slinton #include "runtime.h"
139678Slinton #include "process.h"
149678Slinton #include "machine.h"
159678Slinton #include "events.h"
169678Slinton #include "mappings.h"
179678Slinton #include "symbols.h"
189678Slinton #include "tree.h"
199678Slinton #include "eval.h"
209678Slinton #include "operators.h"
219678Slinton #include "object.h"
2212546Scsvaf #include <sys/param.h>
239678Slinton 
249678Slinton #ifndef public
259678Slinton typedef struct Frame *Frame;
269678Slinton 
279678Slinton #include "machine.h"
289678Slinton #endif
299678Slinton 
309678Slinton #define NSAVEREG 12
319678Slinton 
329678Slinton struct Frame {
339678Slinton     Integer condition_handler;
349678Slinton     Integer mask;
359678Slinton     Address save_ap;		/* argument pointer */
369678Slinton     Address save_fp;		/* frame pointer */
379678Slinton     Address save_pc;		/* program counter */
389678Slinton     Word save_reg[NSAVEREG];	/* not necessarily there */
399678Slinton };
409678Slinton 
419678Slinton private Boolean walkingstack = false;
429678Slinton 
439678Slinton /*
449678Slinton  * Set a frame to the current activation record.
459678Slinton  */
469678Slinton 
479678Slinton private getcurframe(frp)
489678Slinton register Frame frp;
499678Slinton {
509678Slinton     register int i;
519678Slinton 
529678Slinton     checkref(frp);
539678Slinton     frp->mask = reg(NREG);
549678Slinton     frp->save_ap = reg(ARGP);
559678Slinton     frp->save_fp = reg(FRP);
5612051Slinton     frp->save_pc = reg(PROGCTR) + 1;
579678Slinton     for (i = 0; i < NSAVEREG; i++) {
589678Slinton 	frp->save_reg[i] = reg(i);
599678Slinton     }
609678Slinton }
619678Slinton 
629678Slinton /*
639678Slinton  * Return a pointer to the next activation record up the stack.
649678Slinton  * Return nil if there is none.
659678Slinton  * Writes over space pointed to by given argument.
669678Slinton  */
679678Slinton 
689678Slinton #define bis(b, n) ((b & (1 << (n))) != 0)
699678Slinton 
709678Slinton private Frame nextframe(frp)
719678Slinton Frame frp;
729678Slinton {
739678Slinton     register Frame newfrp;
749678Slinton     struct Frame frame;
759678Slinton     register Integer i, j, mask;
7612546Scsvaf     Address prev_frame, callpc;
77*13937Slinton     static Integer ntramp = 0;
789678Slinton 
799678Slinton     newfrp = frp;
8012546Scsvaf     prev_frame = frp->save_fp;
8112546Scsvaf 
82*13937Slinton /*
83*13937Slinton  *  The check for interrupt generated frames is taken from adb with only
84*13937Slinton  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
85*13937Slinton  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
8612546Scsvaf  *
8712546Scsvaf  *  As best I can make out it looks like:
8812546Scsvaf  *
89*13937Slinton  *     <main, (machine check exception block + sub), sysframe, sigsub>.
90*13937Slinton  *
91*13937Slinton  *  When the signal occurs an exception block and a frame for the routine
92*13937Slinton  *  in which it occured are pushed on the user stack.  Then another frame
93*13937Slinton  *  is pushed corresponding to a call from the kernel to sigsub.
94*13937Slinton  *
9512546Scsvaf  *  The addr in sub at which the exception occured is not in sub.save_pc
96*13937Slinton  *  but in the machine check exception block.  It is at the magic address
97*13937Slinton  *  fp + 76.
9812546Scsvaf  *
9912546Scsvaf  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
100*13937Slinton  *  and takes the pc for sub from the exception block.  This allows the
101*13937Slinton  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
10212546Scsvaf  */
10312546Scsvaf 
104*13937Slinton nextf:
105*13937Slinton     dread(&frame, prev_frame, sizeof(struct Frame));
106*13937Slinton     if (ntramp == 1) {
107*13937Slinton 	dread(&callpc, prev_frame + 76, sizeof(callpc));
108*13937Slinton     } else {
109*13937Slinton 	callpc = frame.save_pc;
110*13937Slinton     }
1119678Slinton     if (frame.save_fp == nil) {
1129678Slinton 	newfrp = nil;
113*13937Slinton     } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
11412546Scsvaf 	 ntramp++;
11512546Scsvaf 	 prev_frame = frame.save_fp;
11612546Scsvaf 	 goto nextf;
117*13937Slinton     } else {
11812546Scsvaf 	frame.save_pc = callpc;
119*13937Slinton         ntramp = 0;
1209678Slinton 	mask = ((frame.mask >> 16) & 0x0fff);
1219678Slinton 	j = 0;
1229678Slinton 	for (i = 0; i < NSAVEREG; i++) {
1239678Slinton 	    if (bis(mask, i)) {
1249678Slinton 		newfrp->save_reg[i] = frame.save_reg[j];
1259678Slinton 		++j;
1269678Slinton 	    }
1279678Slinton 	}
1289678Slinton 	newfrp->condition_handler = frame.condition_handler;
1299678Slinton 	newfrp->mask = mask;
1309678Slinton 	newfrp->save_ap = frame.save_ap;
1319678Slinton 	newfrp->save_fp = frame.save_fp;
1329678Slinton 	newfrp->save_pc = frame.save_pc;
1339678Slinton     }
1349678Slinton     return newfrp;
1359678Slinton }
1369678Slinton 
1379678Slinton /*
1389678Slinton  * Return the frame associated with the given function.
1399678Slinton  * If the function is nil, return the most recently activated frame.
1409678Slinton  *
1419678Slinton  * Static allocation for the frame.
1429678Slinton  */
1439678Slinton 
1449678Slinton public Frame findframe(f)
1459678Slinton Symbol f;
1469678Slinton {
1479678Slinton     register Frame frp;
1489678Slinton     static struct Frame frame;
14911866Slinton     Symbol p;
15011866Slinton     Boolean done;
1519678Slinton 
1529678Slinton     frp = &frame;
1539678Slinton     getcurframe(frp);
1549678Slinton     if (f != nil) {
15511866Slinton 	done = false;
15611866Slinton 	do {
15711866Slinton 	    p = whatblock(frp->save_pc);
15811866Slinton 	    if (p == f) {
15911866Slinton 		done = true;
16011866Slinton 	    } else if (p == program) {
16111866Slinton 		done = true;
16211866Slinton 		frp = nil;
16311866Slinton 	    } else {
16411866Slinton 		frp = nextframe(frp);
16511866Slinton 		if (frp == nil) {
16611866Slinton 		    done = true;
16711866Slinton 		}
16811866Slinton 	    }
16911866Slinton 	} while (not done);
1709678Slinton     }
1719678Slinton     return frp;
1729678Slinton }
1739678Slinton 
1749678Slinton /*
1759678Slinton  * Find the return address of the current procedure/function.
1769678Slinton  */
1779678Slinton 
1789678Slinton public Address return_addr()
1799678Slinton {
1809678Slinton     Frame frp;
1819678Slinton     Address addr;
1829678Slinton     struct Frame frame;
1839678Slinton 
1849678Slinton     frp = &frame;
1859678Slinton     getcurframe(frp);
1869678Slinton     frp = nextframe(frp);
1879678Slinton     if (frp == nil) {
1889678Slinton 	addr = 0;
1899678Slinton     } else {
1909678Slinton 	addr = frp->save_pc;
1919678Slinton     }
1929678Slinton     return addr;
1939678Slinton }
1949678Slinton 
1959678Slinton /*
1969678Slinton  * Push the value associated with the current function.
1979678Slinton  */
1989678Slinton 
1999678Slinton public pushretval(len, isindirect)
2009678Slinton Integer len;
2019678Slinton Boolean isindirect;
2029678Slinton {
2039678Slinton     Word r0;
2049678Slinton 
2059678Slinton     r0 = reg(0);
2069678Slinton     if (isindirect) {
2079678Slinton 	rpush((Address) r0, len);
2089678Slinton     } else {
2099678Slinton 	switch (len) {
2109678Slinton 	    case sizeof(char):
2119678Slinton 		push(char, r0);
2129678Slinton 		break;
2139678Slinton 
2149678Slinton 	    case sizeof(short):
2159678Slinton 		push(short, r0);
2169678Slinton 		break;
2179678Slinton 
2189678Slinton 	    default:
2199678Slinton 		if (len == sizeof(Word)) {
2209678Slinton 		    push(Word, r0);
2219678Slinton 		} else if (len == 2*sizeof(Word)) {
2229678Slinton 		    push(Word, r0);
2239678Slinton 		    push(Word, reg(1));
2249678Slinton 		} else {
2259678Slinton 		    panic("not indirect in pushretval?");
2269678Slinton 		}
2279678Slinton 		break;
2289678Slinton 	}
2299678Slinton     }
2309678Slinton }
2319678Slinton 
2329678Slinton /*
2339678Slinton  * Return the base address for locals in the given frame.
2349678Slinton  */
2359678Slinton 
2369678Slinton public Address locals_base(frp)
2379678Slinton register Frame frp;
2389678Slinton {
2399678Slinton     return (frp == nil) ? reg(FRP) : frp->save_fp;
2409678Slinton }
2419678Slinton 
2429678Slinton /*
2439678Slinton  * Return the base address for arguments in the given frame.
2449678Slinton  */
2459678Slinton 
2469678Slinton public Address args_base(frp)
2479678Slinton register Frame frp;
2489678Slinton {
2499678Slinton     return (frp == nil) ? reg(ARGP) : frp->save_ap;
2509678Slinton }
2519678Slinton 
2529678Slinton /*
2539678Slinton  * Return saved register n from the given frame.
2549678Slinton  */
2559678Slinton 
2569678Slinton public Word savereg(n, frp)
2579678Slinton register Integer n;
2589678Slinton register Frame frp;
2599678Slinton {
2609678Slinton     register Word w;
2619678Slinton 
2629678Slinton     if (frp == nil) {
2639678Slinton 	w = reg(n);
2649678Slinton     } else {
2659678Slinton 	switch (n) {
2669678Slinton 	    case ARGP:
2679678Slinton 		w = frp->save_ap;
2689678Slinton 		break;
2699678Slinton 
2709678Slinton 	    case FRP:
2719678Slinton 		w = frp->save_fp;
2729678Slinton 		break;
2739678Slinton 
2749678Slinton 	    case STKP:
2759678Slinton 		w = reg(STKP);
2769678Slinton 		break;
2779678Slinton 
2789678Slinton 	    case PROGCTR:
2799678Slinton 		w = frp->save_pc;
2809678Slinton 		break;
2819678Slinton 
2829678Slinton 	    default:
2839678Slinton 		assert(n >= 0 and n < NSAVEREG);
2849678Slinton 		w = frp->save_reg[n];
2859678Slinton 		break;
2869678Slinton 	}
2879678Slinton     }
2889678Slinton     return w;
2899678Slinton }
2909678Slinton 
2919678Slinton /*
2929678Slinton  * Return the nth argument to the current procedure.
2939678Slinton  */
2949678Slinton 
2959678Slinton public Word argn(n, frp)
2969678Slinton Integer n;
2979678Slinton Frame frp;
2989678Slinton {
2999678Slinton     Word w;
3009678Slinton 
3019678Slinton     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
3029678Slinton     return w;
3039678Slinton }
3049678Slinton 
3059678Slinton /*
3069678Slinton  * Calculate the entry address for a procedure or function parameter,
3079678Slinton  * given the address of the descriptor.
3089678Slinton  */
3099678Slinton 
3109678Slinton public Address fparamaddr(a)
3119678Slinton Address a;
3129678Slinton {
3139678Slinton     Address r;
3149678Slinton 
3159678Slinton     dread(&r, a, sizeof(r));
3169678Slinton     return r;
3179678Slinton }
3189678Slinton 
3199678Slinton /*
3209678Slinton  * Print a list of currently active blocks starting with most recent.
3219678Slinton  */
3229678Slinton 
3239678Slinton public wherecmd()
3249678Slinton {
3259678Slinton     walkstack(false);
3269678Slinton }
3279678Slinton 
3289678Slinton /*
3299678Slinton  * Dump the world to the given file.
3309678Slinton  * Like "where", but variables are dumped also.
3319678Slinton  */
3329678Slinton 
3339678Slinton public dump()
3349678Slinton {
3359678Slinton     walkstack(true);
3369678Slinton }
3379678Slinton 
3389678Slinton /*
3399678Slinton  * Walk the stack of active procedures printing information
3409678Slinton  * about each active procedure.
3419678Slinton  */
3429678Slinton 
3439678Slinton private walkstack(dumpvariables)
3449678Slinton Boolean dumpvariables;
3459678Slinton {
3469678Slinton     register Frame frp;
3479678Slinton     register Symbol f;
3489678Slinton     register Boolean save;
3499678Slinton     register Lineno line;
3509678Slinton     struct Frame frame;
3519678Slinton 
3529678Slinton     if (notstarted(process)) {
3539678Slinton 	error("program is not active");
3549678Slinton     } else {
3559678Slinton 	save = walkingstack;
3569678Slinton 	walkingstack = true;
3579678Slinton 	frp = &frame;
3589678Slinton 	getcurframe(frp);
3599678Slinton 	f = whatblock(frp->save_pc);
3609678Slinton 	do {
3619678Slinton 	    printf("%s", symname(f));
3629678Slinton 	    printparams(f, frp);
3639841Slinton 	    line = srcline(frp->save_pc - 1);
3649678Slinton 	    if (line != 0) {
3659678Slinton 		printf(", line %d", line);
3669841Slinton 		printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
3679678Slinton 	    } else {
3689678Slinton 		printf(" at 0x%x\n", frp->save_pc);
3699678Slinton 	    }
3709678Slinton 	    if (dumpvariables) {
3719678Slinton 		dumpvars(f, frp);
3729678Slinton 		putchar('\n');
3739678Slinton 	    }
3749678Slinton 	    frp = nextframe(frp);
3759678Slinton 	    if (frp != nil) {
3769678Slinton 		f = whatblock(frp->save_pc);
3779678Slinton 	    }
37811866Slinton 	} while (frp != nil and f != program);
3799678Slinton 	if (dumpvariables) {
3809678Slinton 	    printf("in \"%s\":\n", symname(program));
3819678Slinton 	    dumpvars(program, nil);
3829678Slinton 	    putchar('\n');
3839678Slinton 	}
3849678Slinton 	walkingstack = save;
3859678Slinton     }
3869678Slinton }
3879678Slinton 
3889678Slinton /*
3899678Slinton  * Find the entry point of a procedure or function.
3909678Slinton  */
3919678Slinton 
3929678Slinton public findbeginning(f)
3939678Slinton Symbol f;
3949678Slinton {
3959678Slinton     f->symvalue.funcv.beginaddr += 2;
3969678Slinton }
3979678Slinton 
3989678Slinton /*
3999678Slinton  * Return the address corresponding to the first line in a function.
4009678Slinton  */
4019678Slinton 
4029678Slinton public Address firstline(f)
4039678Slinton Symbol f;
4049678Slinton {
4059678Slinton     Address addr;
4069678Slinton 
4079678Slinton     addr = codeloc(f);
4089678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
4099678Slinton 	++addr;
4109678Slinton     }
4119678Slinton     if (addr == objsize) {
4129678Slinton 	addr = -1;
4139678Slinton     }
4149678Slinton     return addr;
4159678Slinton }
4169678Slinton 
4179678Slinton /*
4189678Slinton  * Catcher drops strike three ...
4199678Slinton  */
4209678Slinton 
4219678Slinton public runtofirst()
4229678Slinton {
4239678Slinton     Address addr;
4249678Slinton 
4259678Slinton     addr = pc;
4269678Slinton     while (linelookup(addr) == 0 and addr < objsize) {
4279678Slinton 	++addr;
4289678Slinton     }
4299678Slinton     if (addr < objsize) {
4309678Slinton 	stepto(addr);
4319678Slinton     }
4329678Slinton }
4339678Slinton 
4349678Slinton /*
4359678Slinton  * Return the address corresponding to the end of the program.
4369678Slinton  *
4379678Slinton  * We look for the entry to "exit".
4389678Slinton  */
4399678Slinton 
4409678Slinton public Address lastaddr()
4419678Slinton {
4429678Slinton     register Symbol s;
4439678Slinton 
4449678Slinton     s = lookup(identname("exit", true));
4459678Slinton     if (s == nil) {
4469678Slinton 	panic("can't find exit");
4479678Slinton     }
4489678Slinton     return codeloc(s);
4499678Slinton }
4509678Slinton 
4519678Slinton /*
4529678Slinton  * Decide if the given function is currently active.
4539678Slinton  *
4549678Slinton  * We avoid calls to "findframe" during a stack trace for efficiency.
4559678Slinton  * Presumably information evaluated while walking the stack is active.
4569678Slinton  */
4579678Slinton 
4589678Slinton public Boolean isactive(f)
4599678Slinton Symbol f;
4609678Slinton {
4619678Slinton     register Boolean b;
4629678Slinton 
4639678Slinton     if (isfinished(process)) {
4649678Slinton 	b = false;
4659678Slinton     } else {
4669678Slinton 	if (walkingstack or f == program or
4679678Slinton 	  (ismodule(f) and isactive(container(f)))) {
4689678Slinton 	    b = true;
4699678Slinton 	} else {
4709678Slinton 	    b = (Boolean) (findframe(f) != nil);
4719678Slinton 	}
4729678Slinton     }
4739678Slinton     return b;
4749678Slinton }
4759678Slinton 
4769678Slinton /*
4779678Slinton  * Evaluate a call to a procedure.
4789678Slinton  */
4799678Slinton 
4809678Slinton public callproc(procnode, arglist)
4819678Slinton Node procnode;
4829678Slinton Node arglist;
4839678Slinton {
4849678Slinton     Symbol proc;
4859678Slinton     Integer argc;
4869678Slinton 
4879678Slinton     if (procnode->op != O_SYM) {
4889678Slinton 	beginerrmsg();
4899678Slinton 	fprintf(stderr, "can't call \"");
4909678Slinton 	prtree(stderr, procnode);
4919678Slinton 	fprintf(stderr, "\"");
4929678Slinton 	enderrmsg();
4939678Slinton     }
4949678Slinton     assert(procnode->op == O_SYM);
4959678Slinton     proc = procnode->value.sym;
4969678Slinton     if (not isblock(proc)) {
4979678Slinton 	error("\"%s\" is not a procedure or function", symname(proc));
4989678Slinton     }
4999678Slinton     pushenv();
5009678Slinton     pc = codeloc(proc);
5019678Slinton     argc = pushargs(proc, arglist);
5029678Slinton     beginproc(proc, argc);
5039678Slinton     isstopped = true;
5049678Slinton     event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
5059678Slinton 	buildcmdlist(build(O_PROCRTN, proc)));
5069678Slinton     cont();
5079678Slinton     /* NOTREACHED */
5089678Slinton }
5099678Slinton 
5109678Slinton /*
5119678Slinton  * Push the arguments on the process' stack.  We do this by first
5129678Slinton  * evaluating them on the "eval" stack, then copying into the process'
5139678Slinton  * space.
5149678Slinton  */
5159678Slinton 
5169678Slinton private Integer pushargs(proc, arglist)
5179678Slinton Symbol proc;
5189678Slinton Node arglist;
5199678Slinton {
5209678Slinton     Stack *savesp;
5219678Slinton     int argc, args_size;
5229678Slinton 
5239678Slinton     savesp = sp;
5249678Slinton     argc = evalargs(proc, arglist);
5259678Slinton     args_size = sp - savesp;
5269678Slinton     setreg(STKP, reg(STKP) - args_size);
5279678Slinton     dwrite(savesp, reg(STKP), args_size);
5289678Slinton     sp = savesp;
5299678Slinton     return argc;
5309678Slinton }
5319678Slinton 
5329678Slinton /*
5339678Slinton  * Evaluate arguments left-to-right.
5349678Slinton  */
5359678Slinton 
5369678Slinton private Integer evalargs(proc, arglist)
5379678Slinton Symbol proc;
5389678Slinton Node arglist;
5399678Slinton {
5409678Slinton     Node p, exp;
5419678Slinton     Symbol arg;
5429678Slinton     Stack *savesp;
5439678Slinton     Address addr;
5449678Slinton     Integer count;
5459678Slinton 
5469678Slinton     savesp = sp;
5479678Slinton     count = 0;
5489678Slinton     arg = proc->chain;
5499678Slinton     for (p = arglist; p != nil; p = p->value.arg[1]) {
5509678Slinton 	if (p->op != O_COMMA) {
5519678Slinton 	    panic("evalargs: arglist missing comma");
5529678Slinton 	}
5539678Slinton 	if (arg == nil) {
5549678Slinton 	    sp = savesp;
5559678Slinton 	    error("too many parameters to %s", symname(proc));
5569678Slinton 	}
5579678Slinton 	exp = p->value.arg[0];
5589678Slinton 	if (not compatible(arg->type, exp->nodetype)) {
5599678Slinton 	    sp = savesp;
5609678Slinton 	    error("expression for parameter %s is of wrong type", symname(arg));
5619678Slinton 	}
5629678Slinton 	if (arg->class == REF) {
5639678Slinton 	    if (exp->op != O_RVAL) {
5649678Slinton 		sp = savesp;
5659678Slinton 		error("variable expected for parameter \"%s\"", symname(arg));
5669678Slinton 	    }
5679678Slinton 	    addr = lval(exp->value.arg[0]);
5689678Slinton 	    push(Address, addr);
5699678Slinton 	} else {
5709678Slinton 	    eval(exp);
5719678Slinton 	}
5729678Slinton 	arg = arg->chain;
5739678Slinton 	++count;
5749678Slinton     }
5759678Slinton     if (arg != nil) {
5769678Slinton 	sp = savesp;
5779678Slinton 	error("not enough parameters to %s", symname(proc));
5789678Slinton     }
5799678Slinton     return count;
5809678Slinton }
5819678Slinton 
5829678Slinton public procreturn(f)
5839678Slinton Symbol f;
5849678Slinton {
5859678Slinton     flushoutput();
5869678Slinton     putchar('\n');
5879678Slinton     printname(stdout, f);
5889678Slinton     printf(" returns successfully\n", symname(f));
5899678Slinton     popenv();
5909678Slinton     erecover();
5919678Slinton }
5929678Slinton 
5939678Slinton /*
5949678Slinton  * Push the current environment.
5959678Slinton  */
5969678Slinton 
5979678Slinton private pushenv()
5989678Slinton {
5999678Slinton     push(Address, pc);
6009678Slinton     push(Lineno, curline);
6019678Slinton     push(String, cursource);
6029678Slinton     push(Boolean, isstopped);
6039678Slinton     push(Symbol, curfunc);
6049678Slinton     push(Word, reg(PROGCTR));
6059678Slinton     push(Word, reg(STKP));
6069678Slinton }
6079678Slinton 
6089678Slinton /*
6099678Slinton  * Pop back to the real world.
6109678Slinton  */
6119678Slinton 
6129678Slinton public popenv()
6139678Slinton {
6149678Slinton     register String filename;
6159678Slinton 
6169678Slinton     setreg(STKP, pop(Word));
6179678Slinton     setreg(PROGCTR, pop(Word));
6189678Slinton     curfunc = pop(Symbol);
6199678Slinton     isstopped = pop(Boolean);
6209678Slinton     filename = pop(String);
6219678Slinton     curline = pop(Lineno);
6229678Slinton     pc = pop(Address);
6239678Slinton     setsource(filename);
6249678Slinton }
6259678Slinton 
6269678Slinton /*
6279678Slinton  * Flush the debuggee's standard output.
6289678Slinton  *
6299678Slinton  * This is VERY dependent on the use of stdio.
6309678Slinton  */
6319678Slinton 
6329678Slinton public flushoutput()
6339678Slinton {
6349678Slinton     register Symbol p, iob;
6359678Slinton     register Stack *savesp;
6369678Slinton 
6379678Slinton     p = lookup(identname("fflush", true));
6389678Slinton     while (p != nil and not isblock(p)) {
6399678Slinton 	p = p->next_sym;
6409678Slinton     }
6419678Slinton     if (p != nil) {
6429678Slinton 	iob = lookup(identname("_iob", true));
6439678Slinton 	if (iob != nil) {
6449678Slinton 	    pushenv();
6459678Slinton 	    pc = codeloc(p);
6469678Slinton 	    savesp = sp;
6479678Slinton 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
6489678Slinton 	    setreg(STKP, reg(STKP) - sizeof(long));
6499678Slinton 	    dwrite(savesp, reg(STKP), sizeof(long));
6509678Slinton 	    sp = savesp;
6519678Slinton 	    beginproc(p, 1);
6529678Slinton 	    stepto(return_addr());
6539678Slinton 	    popenv();
6549678Slinton 	}
6559678Slinton     }
6569678Slinton }
657