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