133332Sdonn /* 2*38105Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*38105Sbostic * All rights reserved. 4*38105Sbostic * 5*38105Sbostic * Redistribution and use in source and binary forms are permitted 6*38105Sbostic * provided that the above copyright notice and this paragraph are 7*38105Sbostic * duplicated in all such forms and that any documentation, 8*38105Sbostic * advertising materials, and other materials related to such 9*38105Sbostic * distribution and use acknowledge that the software was developed 10*38105Sbostic * by the University of California, Berkeley. The name of the 11*38105Sbostic * University may not be used to endorse or promote products derived 12*38105Sbostic * from this software without specific prior written permission. 13*38105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38105Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633332Sdonn */ 1733332Sdonn 1833332Sdonn #ifndef lint 19*38105Sbostic static char sccsid[] = "@(#)runtime.iris.c 5.2 (Berkeley) 05/23/89"; 20*38105Sbostic #endif /* not lint */ 2133332Sdonn 2233332Sdonn /* 2333332Sdonn * Runtime organization dependent routines, mostly dealing with 2433332Sdonn * activation records. 2533332Sdonn */ 2633332Sdonn 2733332Sdonn #include "defs.h" 2833332Sdonn #include "runtime.h" 2933332Sdonn #include "process.h" 3033332Sdonn #include "machine.h" 3133332Sdonn #include "events.h" 3233332Sdonn #include "mappings.h" 3333332Sdonn #include "symbols.h" 3433332Sdonn #include "tree.h" 3533332Sdonn #include "eval.h" 3633332Sdonn #include "operators.h" 3733332Sdonn #include "object.h" 3833332Sdonn #include <sys/param.h> 3933332Sdonn #include <signal.h> 4033332Sdonn 4133332Sdonn #ifndef public 4233332Sdonn typedef struct Frame *Frame; 4333332Sdonn 4433332Sdonn #include "machine.h" 4533332Sdonn #endif 4633332Sdonn 4733332Sdonn #define NSAVEREG 14 4833332Sdonn 4933332Sdonn struct Frame { 5033332Sdonn Address save_fp; /* frame pointer */ 5133332Sdonn Address save_pc; /* program counter */ 5233332Sdonn Word save_reg[NSAVEREG]; /* not necessarily there */ 5333332Sdonn integer nargwords; /* computed, not stored */ 5433332Sdonn }; 5533332Sdonn 5633332Sdonn private Frame curframe = nil; 5733332Sdonn private struct Frame curframerec; 5833332Sdonn private Boolean walkingstack = false; 5933332Sdonn 6033332Sdonn #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 6133332Sdonn 6233332Sdonn private boolean inSignalHandler (addr) 6333332Sdonn Address addr; 6433332Sdonn { 6533332Sdonn Symbol f; 6633332Sdonn 6733332Sdonn #ifdef IRIS 6833332Sdonn return false; 6933332Sdonn #else /* sun */ 7033332Sdonn f = whatblock(addr); 7133332Sdonn return (boolean) (f != nil and streq(symname(f), "_sigtramp")); 7233332Sdonn #endif 7333332Sdonn } 7433332Sdonn 7533332Sdonn typedef struct { 7633332Sdonn Node callnode; 7733332Sdonn Node cmdnode; 7833332Sdonn boolean isfunc; 7933332Sdonn } CallEnv; 8033332Sdonn 8133332Sdonn private CallEnv endproc; 8233332Sdonn 8333332Sdonn /* 8433332Sdonn * Set a frame to the current activation record. 8533332Sdonn */ 8633332Sdonn 8733332Sdonn private getcurframe(frp) 8833332Sdonn Frame frp; 8933332Sdonn { 9033332Sdonn register int i; 9133332Sdonn 9233332Sdonn checkref(frp); 9333332Sdonn frp->save_fp = reg(FRP); 9433332Sdonn frp->save_pc = reg(PROGCTR); 9533332Sdonn for (i = 0; i < NSAVEREG; i++) { 9633332Sdonn frp->save_reg[i] = reg(i); 9733332Sdonn } 9833332Sdonn if (frp->save_fp == nil) { 9933332Sdonn frp->nargwords = 0; 10033332Sdonn } else { 10133332Sdonn findnumargs(frp); 10233332Sdonn } 10333332Sdonn } 10433332Sdonn 10533332Sdonn /* 10633332Sdonn * Get the saved registers from one frame to another 10733332Sdonn * given mask specifying which registers were actually saved. 10833332Sdonn */ 10933332Sdonn 11033332Sdonn #define bis(b, n) ((b & (1 << (n))) != 0) 11133332Sdonn 11233332Sdonn private getsaveregs (newfrp, frp, mask) 11333332Sdonn Frame newfrp, frp; 11433332Sdonn integer mask; 11533332Sdonn { 11633332Sdonn integer i, j; 11733332Sdonn 11833332Sdonn j = 0; 11933332Sdonn for (i = 0; i < NSAVEREG; i++) { 12033332Sdonn if (bis(mask, i)) { 12133332Sdonn newfrp->save_reg[i] = frp->save_reg[j]; 12233332Sdonn ++j; 12333332Sdonn } 12433332Sdonn } 12533332Sdonn } 12633332Sdonn 12733332Sdonn /* 12833332Sdonn * Return a pointer to the next activation record up the stack. 12933332Sdonn * Return nil if there is none. 13033332Sdonn * Writes over space pointed to by given argument. 13133332Sdonn */ 13233332Sdonn 13333332Sdonn private Frame nextframe(frp) 13433332Sdonn Frame frp; 13533332Sdonn { 13633332Sdonn Frame newfrp; 13733332Sdonn struct Frame frame; 13833332Sdonn integer mask; 13933332Sdonn Address prev_frame, callpc, higher_fp, higher_pc; 14033332Sdonn static integer ntramp = 0; 14133332Sdonn 14233332Sdonn newfrp = frp; 14333332Sdonn prev_frame = frp->save_fp; 14433332Sdonn 14533332Sdonn /* 14633332Sdonn * The check for interrupt generated frames is taken from adb with only 14733332Sdonn * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 14833332Sdonn * gets control, then the stack does NOT look like <main, sub, sigsub>. 14933332Sdonn * 15033332Sdonn * As best I can make out it looks like: 15133332Sdonn * 15233332Sdonn * <main, (machine check exception block + sub), sysframe, sigsub>. 15333332Sdonn * 15433332Sdonn * When the signal occurs an exception block and a frame for the routine 15533332Sdonn * in which it occured are pushed on the user stack. Then another frame 15633332Sdonn * is pushed corresponding to a call from the kernel to sigsub. 15733332Sdonn * 15833332Sdonn * The addr in sub at which the exception occured is not in sub.save_pc 15933332Sdonn * but in the machine check exception block. It is at the magic address 16033332Sdonn * fp + 84. 16133332Sdonn * 16233332Sdonn * The current approach ignores the sys_frame (what adb reports as sigtramp) 16333332Sdonn * and takes the pc for sub from the exception block. This allows the 16433332Sdonn * "where" command to report <main, sub, sigsub>, which seems reasonable. 16533332Sdonn */ 16633332Sdonn 16733332Sdonn nextf: 16833332Sdonn if (prev_frame + sizeof(struct Frame) <= USRSTACK) { 16933332Sdonn dread(&frame, prev_frame, sizeof(struct Frame)); 17033332Sdonn } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) { 17133332Sdonn dread(&frame, prev_frame, USRSTACK - prev_frame); 17233332Sdonn } else { 17333332Sdonn frame.save_fp = nil; 17433332Sdonn } 17533332Sdonn if (ntramp == 1) { 17633332Sdonn dread(&callpc, prev_frame + 92, sizeof(callpc)); 17733332Sdonn } else { 17833332Sdonn callpc = frame.save_pc; 17933332Sdonn } 18033332Sdonn if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 18133332Sdonn newfrp = nil; 18233332Sdonn } else { 18333332Sdonn if (inSignalHandler(callpc)) { 18433332Sdonn # ifdef sun 18533332Sdonn Address scp; 18633332Sdonn 18733332Sdonn dread(&scp, prev_frame + 16, sizeof(scp)); 18833332Sdonn dread(&callpc, 18933332Sdonn &(((struct sigcontext *)scp)->sc_pc), sizeof(Word) 19033332Sdonn ); 19133332Sdonn # endif /* sun */ 19233332Sdonn } 19333332Sdonn frame.save_pc = callpc; 19433332Sdonn ntramp = 0; 19533332Sdonn higher_fp = frp->save_fp; 19633332Sdonn higher_pc = frp->save_pc; 19733332Sdonn newfrp->save_fp = frame.save_fp; 19833332Sdonn newfrp->save_pc = frame.save_pc; 19933332Sdonn findnumargs(newfrp); 20033332Sdonn findsavedregs(newfrp, higher_fp, higher_pc); 20133332Sdonn } 20233332Sdonn return newfrp; 20333332Sdonn } 20433332Sdonn 20533332Sdonn /* 20633332Sdonn * Finding the saved registers and number of arguments passed to 20733332Sdonn * the current procedure is painful for the 68000. 20833332Sdonn * 20933332Sdonn * This is a version of the way adb for the 68000 does this. 21033332Sdonn */ 21133332Sdonn 21233332Sdonn #define HIWORD 0xffff0000 21333332Sdonn #define LOWORD 0x0000ffff 21433332Sdonn #define LINKA6 0x4e560000 /* link a6,#x */ 21533332Sdonn #define ADDLSP 0xdffc0000 /* addl #x,sp */ 21633332Sdonn #define ADDWSP 0xdefc0000 /* addw #x,sp */ 21733332Sdonn #define LEASP 0x4fef0000 /* lea sp@(x),sp*/ 21833332Sdonn #define TSTBSP 0x4a2f0000 /* tstb sp@(x) */ 21933332Sdonn #define INSMSK 0xfff80000 22033332Sdonn #define MOVLSP 0x2e800000 /* movl dx,sp@ */ 22133332Sdonn #define MOVLD0 0x20000000 /* movl d0,dx */ 22233332Sdonn #define MOVLA0 0x20400000 /* movl d0,ax */ 22333332Sdonn #define MVLMSK 0xf1ff0000 22433332Sdonn #define MOVEML 0x48d70000 /* moveml #x,sp@ */ 22533332Sdonn #define JSR 0x4eb80000 /* jsr x.[WL] */ 22633332Sdonn #define JSRPC 0x4eba0000 /* jsr PC@( ) */ 22733332Sdonn #define LONGBIT 0x00010000 22833332Sdonn #define BSR 0x61000000 /* bsr x */ 22933332Sdonn #define BYTE3 0x0000ff00 23033332Sdonn #define LOBYTE 0x000000ff 23133332Sdonn #define ADQMSK 0xf1ff0000 23233332Sdonn #define ADDQSP 0x508f0000 /* addql #x,sp */ 23333332Sdonn #define ADDQWSP 0x504f0000 /* addqw #x,sp */ 23433332Sdonn 23533332Sdonn private int savedregsmask; 23633332Sdonn private int savedregp; 23733332Sdonn 23833332Sdonn /* 23933332Sdonn * Find out how many words of arguments were passed to 24033332Sdonn * the current procedure. 24133332Sdonn */ 24233332Sdonn 24333332Sdonn private findnumargs (newfrp) 24433332Sdonn Frame newfrp; 24533332Sdonn { 24633332Sdonn integer val; 24733332Sdonn integer instruc; 24833332Sdonn Address addr; 24933332Sdonn 25033332Sdonn dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr)); 25133332Sdonn iread(&instruc, addr, sizeof(instruc)); 25233332Sdonn if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) { 25333332Sdonn addr += 2; 25433332Sdonn iread(&instruc, addr, sizeof(instruc)); 25533332Sdonn } 25633332Sdonn if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){ 25733332Sdonn val = (instruc >> (16+9)) & 07; 25833332Sdonn if (val == 0) { 25933332Sdonn val = 8; 26033332Sdonn } 26133332Sdonn } else if ((instruc&HIWORD) == ADDLSP){ 26233332Sdonn iread(&val, addr + 2, sizeof(val)); 26333332Sdonn } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){ 26433332Sdonn val = instruc&LOWORD; 26533332Sdonn } else { 26633332Sdonn val = 0; 26733332Sdonn } 26833332Sdonn newfrp->nargwords = val / sizeof(Word); 26933332Sdonn } 27033332Sdonn 27133332Sdonn /* 27233332Sdonn * Get the saved registers for the given Frame. 27333332Sdonn */ 27433332Sdonn 27533332Sdonn private findsavedregs (newfrp, higher_fp, higher_pc) 27633332Sdonn Frame newfrp; 27733332Sdonn register Address higher_fp, higher_pc; 27833332Sdonn { 27933332Sdonn int val, regp, i; 28033332Sdonn Address addr; 28133332Sdonn Symbol func; 28233332Sdonn Address calladdr; 28333332Sdonn int instruc; 28433332Sdonn 28533332Sdonn /* 28633332Sdonn * Find the entry point of the current procedure. 28733332Sdonn * This is done by finding the procedure for the higher frame's pc 28833332Sdonn * and taking its starting address. 28933332Sdonn */ 29033332Sdonn func = whatblock(higher_pc, true); 29133332Sdonn calladdr = codeloc(func) - FUNCOFFSET; 29233332Sdonn 29333332Sdonn /* 29433332Sdonn * Look at the entry code for the current procedure 29533332Sdonn * to determine which registers were saved, and where they are. 29633332Sdonn * 29733332Sdonn * First find the size of the activation record. 29833332Sdonn */ 29933332Sdonn addr = calladdr; 30033332Sdonn iread(&instruc, addr, sizeof(instruc)); 30133332Sdonn if ((instruc&HIWORD) == LINKA6) { 30233332Sdonn if ((instruc &= LOWORD) == 0) { 30333332Sdonn /* look for addl */ 30433332Sdonn addr += 4; 30533332Sdonn iread(&instruc, addr, sizeof(instruc)); 30633332Sdonn if ((instruc&HIWORD) == ADDLSP) { 30733332Sdonn iread(&instruc, addr + 2, sizeof(instruc)); 30833332Sdonn addr += 6; 30933332Sdonn } else { 31033332Sdonn instruc = 0; 31133332Sdonn } 31233332Sdonn } else { 31333332Sdonn /* link offset was non-zero -- sign extend it */ 31433332Sdonn instruc <<= 16; 31533332Sdonn instruc >>= 16; 31633332Sdonn } 31733332Sdonn /* we now have the negative frame size */ 31833332Sdonn regp = higher_fp + instruc; 31933332Sdonn savedregp = regp; 32033332Sdonn } 32133332Sdonn 32233332Sdonn /* 32333332Sdonn * Now find which registers were saved. 32433332Sdonn * (expecting a probe instruction next) 32533332Sdonn */ 32633332Sdonn iread(&instruc, addr, sizeof(instruc)); 32733332Sdonn if ((instruc&HIWORD) == TSTBSP) { 32833332Sdonn addr += 4; 32933332Sdonn iread(&instruc, addr, sizeof(instruc)); 33033332Sdonn } 33133332Sdonn /* 33233332Sdonn * expect either a moveml or a movl next 33333332Sdonn */ 33433332Sdonn if ((instruc&INSMSK) == MOVLSP){ 33533332Sdonn /* 33633332Sdonn * Only one register saved. 33733332Sdonn */ 33833332Sdonn i = (instruc>>16) & 07; 33933332Sdonn dread(&(newfrp->save_reg[i]), regp, sizeof(Word)); 34033332Sdonn savedregsmask = 1 << i; 34133332Sdonn } else if ((instruc&HIWORD) == MOVEML) { 34233332Sdonn /* 34333332Sdonn * Saving multiple registers or unoptimized code 34433332Sdonn */ 34533332Sdonn val = instruc & LOWORD; 34633332Sdonn savedregsmask = val; 34733332Sdonn i = 0; 34833332Sdonn while (val != 0) { 34933332Sdonn if (val&1) { 35033332Sdonn dread(&(newfrp->save_reg[i]), regp, sizeof(Word)); 35133332Sdonn regp += sizeof(Word); 35233332Sdonn } 35333332Sdonn val >>= 1; 35433332Sdonn ++i; 35533332Sdonn } 35633332Sdonn } else { 35733332Sdonn savedregsmask = 0; 35833332Sdonn } 35933332Sdonn } 36033332Sdonn 36133332Sdonn /* 36233332Sdonn * Get the current frame information in the given Frame and store the 36333332Sdonn * associated function in the given value-result parameter. 36433332Sdonn */ 36533332Sdonn 36633332Sdonn private getcurfunc (frp, fp) 36733332Sdonn Frame frp; 36833332Sdonn Symbol *fp; 36933332Sdonn { 37033332Sdonn getcurframe(frp); 37133332Sdonn *fp = whatblock(frp->save_pc); 37233332Sdonn } 37333332Sdonn 37433332Sdonn /* 37533332Sdonn * Return the frame associated with the next function up the call stack, or 37633332Sdonn * nil if there is none. The function is returned in a value-result parameter. 37733332Sdonn * For "inline" functions the statically outer function and same frame 37833332Sdonn * are returned. 37933332Sdonn */ 38033332Sdonn 38133332Sdonn public Frame nextfunc (frp, fp) 38233332Sdonn Frame frp; 38333332Sdonn Symbol *fp; 38433332Sdonn { 38533332Sdonn Symbol t; 38633332Sdonn Frame nfrp; 38733332Sdonn 38833332Sdonn t = *fp; 38933332Sdonn checkref(t); 39033332Sdonn if (isinline(t)) { 39133332Sdonn t = container(t); 39233332Sdonn nfrp = frp; 39333332Sdonn } else { 39433332Sdonn nfrp = nextframe(frp); 39533332Sdonn if (nfrp == nil) { 39633332Sdonn t = nil; 39733332Sdonn } else { 39833332Sdonn t = whatblock(nfrp->save_pc); 39933332Sdonn } 40033332Sdonn } 40133332Sdonn *fp = t; 40233332Sdonn return nfrp; 40333332Sdonn } 40433332Sdonn 40533332Sdonn /* 40633332Sdonn * Return the frame associated with the given function. 40733332Sdonn * If the function is nil, return the most recently activated frame. 40833332Sdonn * 40933332Sdonn * Static allocation for the frame. 41033332Sdonn */ 41133332Sdonn 41233332Sdonn public Frame findframe(f) 41333332Sdonn Symbol f; 41433332Sdonn { 41533332Sdonn Frame frp; 41633332Sdonn static struct Frame frame; 41733332Sdonn Symbol p; 41833332Sdonn Boolean done; 41933332Sdonn 42033332Sdonn frp = &frame; 42133332Sdonn getcurframe(frp); 42233332Sdonn if (f != nil) { 42333332Sdonn if (f == curfunc and curframe != nil) { 42433332Sdonn *frp = *curframe; 42533332Sdonn } else { 42633332Sdonn done = false; 42733332Sdonn p = whatblock(frp->save_pc); 42833332Sdonn do { 42933332Sdonn if (p == f) { 43033332Sdonn done = true; 43133332Sdonn } else if (p == program) { 43233332Sdonn done = true; 43333332Sdonn frp = nil; 43433332Sdonn } else { 43533332Sdonn frp = nextfunc(frp, &p); 43633332Sdonn if (frp == nil) { 43733332Sdonn done = true; 43833332Sdonn } 43933332Sdonn } 44033332Sdonn } while (not done); 44133332Sdonn } 44233332Sdonn } 44333332Sdonn return frp; 44433332Sdonn } 44533332Sdonn 44633332Sdonn /* 44733332Sdonn * Set the registers according to the given frame pointer. 44833332Sdonn */ 44933332Sdonn 45033332Sdonn public getnewregs (addr) 45133332Sdonn Address addr; 45233332Sdonn { 45333332Sdonn struct Frame frame; 45433332Sdonn integer i, j, mask; 45533332Sdonn 45633332Sdonn dread(&frame, addr, sizeof(frame)); 45733332Sdonn setreg(FRP, frame.save_fp); 45833332Sdonn setreg(PROGCTR, frame.save_pc); 45933332Sdonn pc = frame.save_pc; 46033332Sdonn setcurfunc(whatblock(pc)); 46133332Sdonn } 46233332Sdonn 46333332Sdonn /* 46433332Sdonn * Find the return address of the current procedure/function. 46533332Sdonn */ 46633332Sdonn 46733332Sdonn public Address return_addr() 46833332Sdonn { 46933332Sdonn Frame frp; 47033332Sdonn Address addr; 47133332Sdonn struct Frame frame; 47233332Sdonn 47333332Sdonn frp = &frame; 47433332Sdonn getcurframe(frp); 47533332Sdonn frp = nextframe(frp); 47633332Sdonn if (frp == nil) { 47733332Sdonn addr = 0; 47833332Sdonn } else { 47933332Sdonn addr = frp->save_pc; 48033332Sdonn } 48133332Sdonn return addr; 48233332Sdonn } 48333332Sdonn 48433332Sdonn /* 48533332Sdonn * Push the value associated with the current function. 48633332Sdonn */ 48733332Sdonn 48833332Sdonn public pushretval(len, isindirect) 48933332Sdonn integer len; 49033332Sdonn boolean isindirect; 49133332Sdonn { 49233332Sdonn Word r0; 49333332Sdonn 49433332Sdonn r0 = reg(0); 49533332Sdonn if (isindirect) { 49633332Sdonn rpush((Address) r0, len); 49733332Sdonn } else { 49833332Sdonn switch (len) { 49933332Sdonn case sizeof(char): 50033332Sdonn push(char, r0); 50133332Sdonn break; 50233332Sdonn 50333332Sdonn case sizeof(short): 50433332Sdonn push(short, r0); 50533332Sdonn break; 50633332Sdonn 50733332Sdonn default: 50833332Sdonn if (len == sizeof(Word)) { 50933332Sdonn push(Word, r0); 51033332Sdonn } else if (len == 2*sizeof(Word)) { 51133332Sdonn push(Word, r0); 51233332Sdonn push(Word, reg(1)); 51333332Sdonn } else { 51433332Sdonn error("[internal error: bad size %d in pushretval]", len); 51533332Sdonn } 51633332Sdonn break; 51733332Sdonn } 51833332Sdonn } 51933332Sdonn } 52033332Sdonn 52133332Sdonn /* 52233332Sdonn * Return the base address for locals in the given frame. 52333332Sdonn */ 52433332Sdonn 52533332Sdonn public Address locals_base(frp) 52633332Sdonn Frame frp; 52733332Sdonn { 52833332Sdonn return (frp == nil) ? reg(FRP) : frp->save_fp; 52933332Sdonn } 53033332Sdonn 53133332Sdonn /* 53233332Sdonn * Return the base address for arguments in the given frame. 53333332Sdonn */ 53433332Sdonn 53533332Sdonn public Address args_base(frp) 53633332Sdonn Frame frp; 53733332Sdonn { 53833332Sdonn return (frp == nil) ? reg(FRP) : frp->save_fp; 53933332Sdonn } 54033332Sdonn 54133332Sdonn /* 54233332Sdonn * Return saved register n from the given frame. 54333332Sdonn */ 54433332Sdonn 54533332Sdonn public Word savereg(n, frp) 54633332Sdonn integer n; 54733332Sdonn Frame frp; 54833332Sdonn { 54933332Sdonn Word w; 55033332Sdonn 55133332Sdonn if (frp == nil) { 55233332Sdonn w = reg(n); 55333332Sdonn } else { 55433332Sdonn switch (n) { 55533332Sdonn case FRP: 55633332Sdonn w = frp->save_fp; 55733332Sdonn break; 55833332Sdonn 55933332Sdonn case STKP: 56033332Sdonn w = reg(STKP); 56133332Sdonn break; 56233332Sdonn 56333332Sdonn case PROGCTR: 56433332Sdonn w = frp->save_pc; 56533332Sdonn break; 56633332Sdonn 56733332Sdonn default: 56833332Sdonn assert(n >= 0 and n < NSAVEREG); 56933332Sdonn w = frp->save_reg[n]; 57033332Sdonn break; 57133332Sdonn } 57233332Sdonn } 57333332Sdonn return w; 57433332Sdonn } 57533332Sdonn 57633332Sdonn /* 57733332Sdonn * Return the nth argument to the current procedure. 57833332Sdonn */ 57933332Sdonn 58033332Sdonn public Word argn(n, frp) 58133332Sdonn integer n; 58233332Sdonn Frame frp; 58333332Sdonn { 58433332Sdonn Address argaddr; 58533332Sdonn Word w; 58633332Sdonn 58733332Sdonn argaddr = args_base(frp) + 4 + (n * sizeof(Word)); 58833332Sdonn dread(&w, argaddr, sizeof(w)); 58933332Sdonn return w; 59033332Sdonn } 59133332Sdonn 59233332Sdonn /* 59333332Sdonn * Return the number of words of arguments passed to the procedure 59433332Sdonn * associated with the given frame (it's a macro for the VAX). 59533332Sdonn */ 59633332Sdonn 59733332Sdonn public integer nargspassed (frp) 59833332Sdonn Frame frp; 59933332Sdonn { 60033332Sdonn integer n; 60133332Sdonn struct Frame frame; 60233332Sdonn 60333332Sdonn if (frp == nil) { 60433332Sdonn getcurframe(&frame); 60533332Sdonn n = frame.nargwords; 60633332Sdonn } else { 60733332Sdonn n = frp->nargwords; 60833332Sdonn } 60933332Sdonn return n; 61033332Sdonn } 61133332Sdonn 61233332Sdonn /* 61333332Sdonn * Print a list of currently active blocks starting with most recent. 61433332Sdonn */ 61533332Sdonn 61633332Sdonn public wherecmd() 61733332Sdonn { 61833332Sdonn walkstack(false); 61933332Sdonn } 62033332Sdonn 62133332Sdonn /* 62233332Sdonn * Print the variables in the given frame or the current one if nil. 62333332Sdonn */ 62433332Sdonn 62533332Sdonn public dump (func) 62633332Sdonn Symbol func; 62733332Sdonn { 62833332Sdonn Symbol f; 62933332Sdonn Frame frp; 63033332Sdonn 63133332Sdonn if (func == nil) { 63233332Sdonn f = curfunc; 63333332Sdonn if (curframe != nil) { 63433332Sdonn frp = curframe; 63533332Sdonn } else { 63633332Sdonn frp = findframe(f); 63733332Sdonn } 63833332Sdonn } else { 63933332Sdonn f = func; 64033332Sdonn frp = findframe(f); 64133332Sdonn } 64233332Sdonn showaggrs = true; 64333332Sdonn printcallinfo(f, frp); 64433332Sdonn dumpvars(f, frp); 64533332Sdonn } 64633332Sdonn 64733332Sdonn /* 64833332Sdonn * Dump all values. 64933332Sdonn */ 65033332Sdonn 65133332Sdonn public dumpall () 65233332Sdonn { 65333332Sdonn walkstack(true); 65433332Sdonn } 65533332Sdonn 65633332Sdonn /* 65733332Sdonn * Walk the stack of active procedures printing information 65833332Sdonn * about each active procedure. 65933332Sdonn */ 66033332Sdonn 66133332Sdonn private walkstack(dumpvariables) 66233332Sdonn Boolean dumpvariables; 66333332Sdonn { 66433332Sdonn Frame frp; 66533332Sdonn boolean save; 66633332Sdonn Symbol f; 66733332Sdonn struct Frame frame; 66833332Sdonn 66933332Sdonn if (notstarted(process) or isfinished(process)) { 67033332Sdonn error("program is not active"); 67133332Sdonn } else { 67233332Sdonn save = walkingstack; 67333332Sdonn walkingstack = true; 67433332Sdonn showaggrs = dumpvariables; 67533332Sdonn frp = &frame; 67633332Sdonn getcurfunc(frp, &f); 67733332Sdonn for (;;) { 67833332Sdonn printcallinfo(f, frp); 67933332Sdonn if (dumpvariables) { 68033332Sdonn dumpvars(f, frp); 68133332Sdonn putchar('\n'); 68233332Sdonn } 68333332Sdonn frp = nextfunc(frp, &f); 68433332Sdonn if (frp == nil or f == program) { 68533332Sdonn break; 68633332Sdonn } 68733332Sdonn } 68833332Sdonn if (dumpvariables) { 68933332Sdonn printf("in \"%s\":\n", symname(program)); 69033332Sdonn dumpvars(program, nil); 69133332Sdonn putchar('\n'); 69233332Sdonn } 69333332Sdonn walkingstack = save; 69433332Sdonn } 69533332Sdonn } 69633332Sdonn 69733332Sdonn /* 69833332Sdonn * Print out the information about a call, i.e., 69933332Sdonn * routine name, parameter values, and source location. 70033332Sdonn */ 70133332Sdonn 70233332Sdonn private printcallinfo (f, frp) 70333332Sdonn Symbol f; 70433332Sdonn Frame frp; 70533332Sdonn { 70633332Sdonn Lineno line; 70733332Sdonn Address savepc; 70833332Sdonn 70933332Sdonn savepc = frp->save_pc; 71033332Sdonn if (frp->save_fp != reg(FRP)) { 71133332Sdonn savepc -= 1; 71233332Sdonn } 71333332Sdonn printname(stdout, f); 71433332Sdonn if (not isinline(f)) { 71533332Sdonn printparams(f, frp); 71633332Sdonn } 71733332Sdonn line = srcline(savepc); 71833332Sdonn if (line != 0) { 71933332Sdonn printf(", line %d", line); 72033332Sdonn printf(" in \"%s\"\n", srcfilename(savepc)); 72133332Sdonn } else { 72233332Sdonn printf(" at 0x%x\n", savepc); 72333332Sdonn } 72433332Sdonn } 72533332Sdonn 72633332Sdonn /* 72733332Sdonn * Set the current function to the given symbol. 72833332Sdonn * We must adjust "curframe" so that subsequent operations are 72933332Sdonn * not confused; for simplicity we simply clear it. 73033332Sdonn */ 73133332Sdonn 73233332Sdonn public setcurfunc (f) 73333332Sdonn Symbol f; 73433332Sdonn { 73533332Sdonn curfunc = f; 73633332Sdonn curframe = nil; 73733332Sdonn } 73833332Sdonn 73933332Sdonn /* 74033332Sdonn * Return the frame for the current function. 74133332Sdonn * The space for the frame is allocated statically. 74233332Sdonn */ 74333332Sdonn 74433332Sdonn public Frame curfuncframe () 74533332Sdonn { 74633332Sdonn static struct Frame frame; 74733332Sdonn Frame frp; 74833332Sdonn 74933332Sdonn if (curframe == nil) { 75033332Sdonn frp = findframe(curfunc); 75133332Sdonn curframe = &curframerec; 75233332Sdonn *curframe = *frp; 75333332Sdonn } else { 75433332Sdonn frp = &frame; 75533332Sdonn *frp = *curframe; 75633332Sdonn } 75733332Sdonn return frp; 75833332Sdonn } 75933332Sdonn 76033332Sdonn /* 76133332Sdonn * Set curfunc to be N up/down the stack from its current value. 76233332Sdonn */ 76333332Sdonn 76433332Sdonn public up (n) 76533332Sdonn integer n; 76633332Sdonn { 76733332Sdonn integer i; 76833332Sdonn Symbol f; 76933332Sdonn Frame frp; 77033332Sdonn boolean done; 77133332Sdonn 77233332Sdonn if (not isactive(program)) { 77333332Sdonn error("program is not active"); 77433332Sdonn } else if (curfunc == nil) { 77533332Sdonn error("no current function"); 77633332Sdonn } else { 77733332Sdonn i = 0; 77833332Sdonn f = curfunc; 77933332Sdonn frp = curfuncframe(); 78033332Sdonn done = false; 78133332Sdonn do { 78233332Sdonn if (frp == nil) { 78333332Sdonn done = true; 78433332Sdonn error("not that many levels"); 78533332Sdonn } else if (i >= n) { 78633332Sdonn done = true; 78733332Sdonn curfunc = f; 78833332Sdonn curframe = &curframerec; 78933332Sdonn *curframe = *frp; 79033332Sdonn showaggrs = false; 79133332Sdonn printcallinfo(curfunc, curframe); 79233332Sdonn } else if (f == program) { 79333332Sdonn done = true; 79433332Sdonn error("not that many levels"); 79533332Sdonn } else { 79633332Sdonn frp = nextfunc(frp, &f); 79733332Sdonn } 79833332Sdonn ++i; 79933332Sdonn } while (not done); 80033332Sdonn } 80133332Sdonn } 80233332Sdonn 80333332Sdonn public down (n) 80433332Sdonn integer n; 80533332Sdonn { 80633332Sdonn integer i, depth; 80733332Sdonn Frame frp, curfrp; 80833332Sdonn Symbol f; 80933332Sdonn struct Frame frame; 81033332Sdonn 81133332Sdonn if (not isactive(program)) { 81233332Sdonn error("program is not active"); 81333332Sdonn } else if (curfunc == nil) { 81433332Sdonn error("no current function"); 81533332Sdonn } else { 81633332Sdonn depth = 0; 81733332Sdonn frp = &frame; 81833332Sdonn getcurfunc(frp, &f); 81933332Sdonn if (curframe == nil) { 82033332Sdonn curfrp = findframe(curfunc); 82133332Sdonn curframe = &curframerec; 82233332Sdonn *curframe = *curfrp; 82333332Sdonn } 82433332Sdonn while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 82533332Sdonn frp = nextfunc(frp, &f); 82633332Sdonn ++depth; 82733332Sdonn } 82833332Sdonn if (f == nil or n > depth) { 82933332Sdonn error("not that many levels"); 83033332Sdonn } else { 83133332Sdonn depth -= n; 83233332Sdonn frp = &frame; 83333332Sdonn getcurfunc(frp, &f); 83433332Sdonn for (i = 0; i < depth; i++) { 83533332Sdonn frp = nextfunc(frp, &f); 83633332Sdonn assert(frp != nil); 83733332Sdonn } 83833332Sdonn curfunc = f; 83933332Sdonn *curframe = *frp; 84033332Sdonn showaggrs = false; 84133332Sdonn printcallinfo(curfunc, curframe); 84233332Sdonn } 84333332Sdonn } 84433332Sdonn } 84533332Sdonn 84633332Sdonn /* 84733332Sdonn * Find the entry point of a procedure or function. 84833332Sdonn */ 84933332Sdonn 85033332Sdonn public findbeginning (f) 85133332Sdonn Symbol f; 85233332Sdonn { 85333332Sdonn if (isinternal(f)) { 85433332Sdonn f->symvalue.funcv.beginaddr += 18; /* VAX only */ 85533332Sdonn } else { 85633332Sdonn /* on 68000's don't add for beginning of program */ 85733332Sdonn if (f->symvalue.funcv.beginaddr != CODESTART) { 85833332Sdonn f->symvalue.funcv.beginaddr += FUNCOFFSET; 85933332Sdonn } 86033332Sdonn } 86133332Sdonn } 86233332Sdonn 86333332Sdonn /* 86433332Sdonn * Return the address corresponding to the first line in a function. 86533332Sdonn */ 86633332Sdonn 86733332Sdonn public Address firstline(f) 86833332Sdonn Symbol f; 86933332Sdonn { 87033332Sdonn Address addr; 87133332Sdonn 87233332Sdonn addr = codeloc(f); 87333332Sdonn while (linelookup(addr) == 0 and addr < objsize) { 87433332Sdonn ++addr; 87533332Sdonn } 87633332Sdonn if (addr == objsize) { 87733332Sdonn addr = -1; 87833332Sdonn } 87933332Sdonn return addr; 88033332Sdonn } 88133332Sdonn 88233332Sdonn /* 88333332Sdonn * Catcher drops strike three ... 88433332Sdonn */ 88533332Sdonn 88633332Sdonn public runtofirst() 88733332Sdonn { 88833332Sdonn Address addr, endaddr; 88933332Sdonn 89033332Sdonn addr = pc; 89133332Sdonn endaddr = objsize + CODESTART; 89233332Sdonn while (linelookup(addr) == 0 and addr < endaddr) { 89333332Sdonn ++addr; 89433332Sdonn } 89533332Sdonn if (addr < endaddr) { 89633332Sdonn stepto(addr); 89733332Sdonn } 89833332Sdonn } 89933332Sdonn 90033332Sdonn /* 90133332Sdonn * Return the address corresponding to the end of the program. 90233332Sdonn * 90333332Sdonn * We look for the entry to "exit". 90433332Sdonn */ 90533332Sdonn 90633332Sdonn public Address lastaddr() 90733332Sdonn { 90833332Sdonn Symbol s; 90933332Sdonn 91033332Sdonn s = lookup(identname("exit", true)); 91133332Sdonn if (s == nil) { 91233332Sdonn panic("can't find exit"); 91333332Sdonn } 91433332Sdonn return codeloc(s); 91533332Sdonn } 91633332Sdonn 91733332Sdonn /* 91833332Sdonn * Decide if the given function is currently active. 91933332Sdonn * 92033332Sdonn * We avoid calls to "findframe" during a stack trace for efficiency. 92133332Sdonn * Presumably information evaluated while walking the stack is active. 92233332Sdonn */ 92333332Sdonn 92433332Sdonn public Boolean isactive (f) 92533332Sdonn Symbol f; 92633332Sdonn { 92733332Sdonn Boolean b; 92833332Sdonn 92933332Sdonn if (isfinished(process)) { 93033332Sdonn b = false; 93133332Sdonn } else { 93233332Sdonn if (walkingstack or f == program or f == nil or 93333332Sdonn (ismodule(f) and isactive(container(f)))) { 93433332Sdonn b = true; 93533332Sdonn } else { 93633332Sdonn b = (Boolean) (findframe(f) != nil); 93733332Sdonn } 93833332Sdonn } 93933332Sdonn return b; 94033332Sdonn } 94133332Sdonn 94233332Sdonn /* 94333332Sdonn * Evaluate a call to a procedure. 94433332Sdonn */ 94533332Sdonn 94633332Sdonn public callproc(exprnode, isfunc) 94733332Sdonn Node exprnode; 94833332Sdonn boolean isfunc; 94933332Sdonn { 95033332Sdonn Node procnode, arglist; 95133332Sdonn Symbol proc; 95233332Sdonn integer argc; 95333332Sdonn 95433332Sdonn procnode = exprnode->value.arg[0]; 95533332Sdonn arglist = exprnode->value.arg[1]; 95633332Sdonn if (procnode->op != O_SYM) { 95733332Sdonn beginerrmsg(); 95833332Sdonn fprintf(stderr, "can't call \""); 95933332Sdonn prtree(stderr, procnode); 96033332Sdonn fprintf(stderr, "\""); 96133332Sdonn enderrmsg(); 96233332Sdonn } 96333332Sdonn assert(procnode->op == O_SYM); 96433332Sdonn proc = procnode->value.sym; 96533332Sdonn if (not isblock(proc)) { 96633332Sdonn error("\"%s\" is not a procedure or function", symname(proc)); 96733332Sdonn } 96833332Sdonn endproc.isfunc = isfunc; 96933332Sdonn endproc.callnode = exprnode; 97033332Sdonn endproc.cmdnode = topnode; 97133332Sdonn pushenv(); 97233332Sdonn pc = codeloc(proc); 97333332Sdonn argc = pushargs(proc, arglist); 97433332Sdonn setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ 97533332Sdonn beginproc(proc, argc); 97633332Sdonn event_once( 97733332Sdonn build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 97833332Sdonn buildcmdlist(build(O_PROCRTN, proc)) 97933332Sdonn ); 98033332Sdonn isstopped = false; 98133332Sdonn if (not bpact()) { 98233332Sdonn isstopped = true; 98333332Sdonn cont(0); 98433332Sdonn } 98533332Sdonn /* 98633332Sdonn * bpact() won't return true, it will call printstatus() and go back 98733332Sdonn * to command input if a breakpoint is found. 98833332Sdonn */ 98933332Sdonn /* NOTREACHED */ 99033332Sdonn } 99133332Sdonn 99233332Sdonn /* 99333332Sdonn * Push the arguments on the process' stack. We do this by first 99433332Sdonn * evaluating them on the "eval" stack, then copying into the process' 99533332Sdonn * space. 99633332Sdonn */ 99733332Sdonn 99833332Sdonn private integer pushargs(proc, arglist) 99933332Sdonn Symbol proc; 100033332Sdonn Node arglist; 100133332Sdonn { 100233332Sdonn Stack *savesp; 100333332Sdonn int argc, args_size; 100433332Sdonn 100533332Sdonn savesp = sp; 100633332Sdonn if (varIsSet("$unsafecall")) { 100733332Sdonn argc = unsafe_evalargs(proc, arglist); 100833332Sdonn } else { 100933332Sdonn argc = evalargs(proc, arglist); 101033332Sdonn } 101133332Sdonn args_size = sp - savesp; 101233332Sdonn setreg(STKP, reg(STKP) - args_size); 101333332Sdonn dwrite(savesp, reg(STKP), args_size); 101433332Sdonn sp = savesp; 101533332Sdonn return argc; 101633332Sdonn } 101733332Sdonn 101833332Sdonn /* 101933332Sdonn * Check to see if an expression is correct for a given parameter. 102033332Sdonn * If the given parameter is false, don't worry about type inconsistencies. 102133332Sdonn * 102233332Sdonn * Return whether or not it is ok. 102333332Sdonn */ 102433332Sdonn 102533332Sdonn private boolean chkparam (actual, formal, chk) 102633332Sdonn Node actual; 102733332Sdonn Symbol formal; 102833332Sdonn boolean chk; 102933332Sdonn { 103033332Sdonn boolean b; 103133332Sdonn 103233332Sdonn b = true; 103333332Sdonn if (chk) { 103433332Sdonn if (formal == nil) { 103533332Sdonn beginerrmsg(); 103633332Sdonn fprintf(stderr, "too many parameters"); 103733332Sdonn b = false; 103833332Sdonn } else if (not compatible(formal->type, actual->nodetype)) { 103933332Sdonn beginerrmsg(); 104033332Sdonn fprintf(stderr, "type mismatch for %s", symname(formal)); 104133332Sdonn b = false; 104233332Sdonn } 104333332Sdonn } 104433332Sdonn if (b and formal != nil and 104533332Sdonn isvarparam(formal) and not isopenarray(formal->type) and 104633332Sdonn not ( 104733332Sdonn actual->op == O_RVAL or actual->nodetype == t_addr or 104833332Sdonn ( 104933332Sdonn actual->op == O_TYPERENAME and 105033332Sdonn ( 105133332Sdonn actual->value.arg[0]->op == O_RVAL or 105233332Sdonn actual->value.arg[0]->nodetype == t_addr 105333332Sdonn ) 105433332Sdonn ) 105533332Sdonn ) 105633332Sdonn ) { 105733332Sdonn beginerrmsg(); 105833332Sdonn fprintf(stderr, "expected variable, found \""); 105933332Sdonn prtree(stderr, actual); 106033332Sdonn fprintf(stderr, "\""); 106133332Sdonn b = false; 106233332Sdonn } 106333332Sdonn return b; 106433332Sdonn } 106533332Sdonn 106633332Sdonn /* 106733332Sdonn * Pass an expression to a particular parameter. 106833332Sdonn * 106933332Sdonn * Normally we pass either the address or value, but in some cases 107033332Sdonn * (such as C strings) we want to copy the value onto the stack and 107133332Sdonn * pass its address. 107233332Sdonn * 107333332Sdonn * Another special case raised by strings is the possibility that 107433332Sdonn * the actual parameter will be larger than the formal, even with 107533332Sdonn * appropriate type-checking. This occurs because we assume during 107633332Sdonn * evaluation that strings are null-terminated, whereas some languages, 107733332Sdonn * notably Pascal, do not work under that assumption. 107833332Sdonn */ 107933332Sdonn 108033332Sdonn private passparam (actual, formal) 108133332Sdonn Node actual; 108233332Sdonn Symbol formal; 108333332Sdonn { 108433332Sdonn boolean b; 108533332Sdonn Address addr; 108633332Sdonn Stack *savesp; 108733332Sdonn integer actsize, formsize; 108833332Sdonn 108933332Sdonn if (formal != nil and isvarparam(formal) and 109033332Sdonn (not isopenarray(formal->type)) 109133332Sdonn ) { 109233332Sdonn addr = lval(actual->value.arg[0]); 109333332Sdonn push(Address, addr); 109433332Sdonn } else if (passaddr(formal, actual->nodetype)) { 109533332Sdonn savesp = sp; 109633332Sdonn eval(actual); 109733332Sdonn actsize = sp - savesp; 109833332Sdonn setreg(STKP, 109933332Sdonn reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) 110033332Sdonn ); 110133332Sdonn dwrite(savesp, reg(STKP), actsize); 110233332Sdonn sp = savesp; 110333332Sdonn push(Address, reg(STKP)); 110433332Sdonn if (formal != nil and isopenarray(formal->type)) { 110533332Sdonn push(integer, actsize div size(formal->type->type)); 110633332Sdonn } 110733332Sdonn } else if (formal != nil) { 110833332Sdonn formsize = size(formal); 110933332Sdonn savesp = sp; 111033332Sdonn eval(actual); 111133332Sdonn actsize = sp - savesp; 111233332Sdonn if (actsize > formsize) { 111333332Sdonn sp -= (actsize - formsize); 111433332Sdonn } 111533332Sdonn } else { 111633332Sdonn eval(actual); 111733332Sdonn } 111833332Sdonn } 111933332Sdonn 112033332Sdonn /* 112133332Sdonn * Evaluate an argument list left-to-right. 112233332Sdonn */ 112333332Sdonn 112433332Sdonn private integer evalargs(proc, arglist) 112533332Sdonn Symbol proc; 112633332Sdonn Node arglist; 112733332Sdonn { 112833332Sdonn Node p, actual; 112933332Sdonn Symbol formal; 113033332Sdonn Stack *savesp; 113133332Sdonn integer count; 113233332Sdonn boolean chk; 113333332Sdonn 113433332Sdonn savesp = sp; 113533332Sdonn count = 0; 113633332Sdonn formal = proc->chain; 113733332Sdonn chk = (boolean) (not nosource(proc)); 113833332Sdonn for (p = arglist; p != nil; p = p->value.arg[1]) { 113933332Sdonn assert(p->op == O_COMMA); 114033332Sdonn actual = p->value.arg[0]; 114133332Sdonn if (not chkparam(actual, formal, chk)) { 114233332Sdonn fprintf(stderr, " in call to %s", symname(proc)); 114333332Sdonn sp = savesp; 114433332Sdonn enderrmsg(); 114533332Sdonn } 114633332Sdonn passparam(actual, formal); 114733332Sdonn if (formal != nil) { 114833332Sdonn formal = formal->chain; 114933332Sdonn } 115033332Sdonn ++count; 115133332Sdonn } 115233332Sdonn if (chk) { 115333332Sdonn if (formal != nil) { 115433332Sdonn sp = savesp; 115533332Sdonn error("not enough parameters to %s", symname(proc)); 115633332Sdonn } 115733332Sdonn } 115833332Sdonn return count; 115933332Sdonn } 116033332Sdonn 116133332Sdonn /* 116233332Sdonn * Evaluate an argument list without any type checking. 116333332Sdonn * This is only useful for procedures with a varying number of 116433332Sdonn * arguments that are compiled -g. 116533332Sdonn */ 116633332Sdonn 116733332Sdonn private integer unsafe_evalargs (proc, arglist) 116833332Sdonn Symbol proc; 116933332Sdonn Node arglist; 117033332Sdonn { 117133332Sdonn Node p; 117233332Sdonn integer count; 117333332Sdonn 117433332Sdonn count = 0; 117533332Sdonn for (p = arglist; p != nil; p = p->value.arg[1]) { 117633332Sdonn assert(p->op == O_COMMA); 117733332Sdonn eval(p->value.arg[0]); 117833332Sdonn ++count; 117933332Sdonn } 118033332Sdonn return count; 118133332Sdonn } 118233332Sdonn 118333332Sdonn public procreturn(f) 118433332Sdonn Symbol f; 118533332Sdonn { 118633332Sdonn integer retvalsize; 118733332Sdonn Node tmp; 118833332Sdonn char *copy; 118933332Sdonn 119033332Sdonn flushoutput(); 119133332Sdonn popenv(); 119233332Sdonn if (endproc.isfunc) { 119333332Sdonn retvalsize = size(f->type); 119433332Sdonn if (retvalsize > sizeof(long)) { 119533332Sdonn pushretval(retvalsize, true); 119633332Sdonn copy = newarr(char, retvalsize); 119733332Sdonn popn(retvalsize, copy); 119833332Sdonn tmp = build(O_SCON, copy); 119933332Sdonn } else { 120033332Sdonn tmp = build(O_LCON, (long) (reg(0))); 120133332Sdonn } 120233332Sdonn tmp->nodetype = f->type; 120333332Sdonn tfree(endproc.callnode); 120433332Sdonn *(endproc.callnode) = *(tmp); 120533332Sdonn dispose(tmp); 120633332Sdonn eval(endproc.cmdnode); 120733332Sdonn } else { 120833332Sdonn putchar('\n'); 120933332Sdonn printname(stdout, f); 121033332Sdonn printf(" returns successfully\n"); 121133332Sdonn } 121233332Sdonn erecover(); 121333332Sdonn } 121433332Sdonn 121533332Sdonn /* 121633332Sdonn * Push the current environment. 121733332Sdonn */ 121833332Sdonn 121933332Sdonn private pushenv() 122033332Sdonn { 122133332Sdonn push(Address, pc); 122233332Sdonn push(Lineno, curline); 122333332Sdonn push(String, cursource); 122433332Sdonn push(Boolean, isstopped); 122533332Sdonn push(Symbol, curfunc); 122633332Sdonn push(Frame, curframe); 122733332Sdonn push(struct Frame, curframerec); 122833332Sdonn push(CallEnv, endproc); 122933332Sdonn push(Word, reg(PROGCTR)); 123033332Sdonn push(Word, reg(STKP)); 123133332Sdonn push(Word, reg(FRP)); 123233332Sdonn } 123333332Sdonn 123433332Sdonn /* 123533332Sdonn * Pop back to the real world. 123633332Sdonn */ 123733332Sdonn 123833332Sdonn public popenv() 123933332Sdonn { 124033332Sdonn String filename; 124133332Sdonn 124233332Sdonn setreg(FRP, pop(Word)); 124333332Sdonn setreg(STKP, pop(Word)); 124433332Sdonn setreg(PROGCTR, pop(Word)); 124533332Sdonn endproc = pop(CallEnv); 124633332Sdonn curframerec = pop(struct Frame); 124733332Sdonn curframe = pop(Frame); 124833332Sdonn curfunc = pop(Symbol); 124933332Sdonn isstopped = pop(Boolean); 125033332Sdonn filename = pop(String); 125133332Sdonn curline = pop(Lineno); 125233332Sdonn pc = pop(Address); 125333332Sdonn setsource(filename); 125433332Sdonn } 125533332Sdonn 125633332Sdonn /* 125733332Sdonn * Flush the debuggee's standard output. 125833332Sdonn * 125933332Sdonn * This is VERY dependent on the use of stdio. 126033332Sdonn */ 126133332Sdonn 126233332Sdonn public flushoutput() 126333332Sdonn { 126433332Sdonn Symbol p, iob; 126533332Sdonn Stack *savesp; 126633332Sdonn 126733332Sdonn p = lookup(identname("fflush", true)); 126833332Sdonn while (p != nil and not isblock(p)) { 126933332Sdonn p = p->next_sym; 127033332Sdonn } 127133332Sdonn if (p != nil) { 127233332Sdonn iob = lookup(identname("_iob", true)); 127333332Sdonn if (iob != nil) { 127433332Sdonn pushenv(); 127533332Sdonn pc = codeloc(p) - FUNCOFFSET; 127633332Sdonn savesp = sp; 127733332Sdonn push(long, address(iob, nil) + sizeof(*stdout)); 127833332Sdonn setreg(STKP, reg(STKP) - sizeof(long)); 127933332Sdonn dwrite(savesp, reg(STKP), sizeof(long)); 128033332Sdonn sp = savesp; 128133332Sdonn beginproc(p, 1); 128233332Sdonn stepto(return_addr()); 128333332Sdonn popenv(); 128433332Sdonn } 128533332Sdonn } 128633332Sdonn } 1287