121621Sdist /* 238105Sbostic * Copyright (c) 1983 The Regents of the University of California. 338105Sbostic * All rights reserved. 438105Sbostic * 5*42685Sbostic * %sccs.include.redist.c% 621621Sdist */ 79678Slinton 821621Sdist #ifndef lint 9*42685Sbostic static char sccsid[] = "@(#)runtime.vax.c 5.5 (Berkeley) 06/01/90"; 1038105Sbostic #endif /* not lint */ 119678Slinton 129678Slinton /* 139678Slinton * Runtime organization dependent routines, mostly dealing with 149678Slinton * activation records. 159678Slinton */ 169678Slinton 179678Slinton #include "defs.h" 189678Slinton #include "runtime.h" 199678Slinton #include "process.h" 209678Slinton #include "machine.h" 219678Slinton #include "events.h" 229678Slinton #include "mappings.h" 239678Slinton #include "symbols.h" 249678Slinton #include "tree.h" 259678Slinton #include "eval.h" 269678Slinton #include "operators.h" 279678Slinton #include "object.h" 2812546Scsvaf #include <sys/param.h> 2933334Sdonn #include <signal.h> 309678Slinton 319678Slinton #ifndef public 329678Slinton typedef struct Frame *Frame; 339678Slinton 349678Slinton #include "machine.h" 359678Slinton #endif 369678Slinton 379678Slinton #define NSAVEREG 12 389678Slinton 399678Slinton struct Frame { 4018231Slinton integer condition_handler; 4118231Slinton integer mask; 429678Slinton Address save_ap; /* argument pointer */ 439678Slinton Address save_fp; /* frame pointer */ 449678Slinton Address save_pc; /* program counter */ 459678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 469678Slinton }; 479678Slinton 4816618Ssam private Frame curframe = nil; 4916618Ssam private struct Frame curframerec; 509678Slinton private Boolean walkingstack = false; 519678Slinton 5216618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 5316618Ssam 5433334Sdonn #define inSignalHandler(addr) \ 5533334Sdonn (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES))) 5618231Slinton 5718231Slinton typedef struct { 5818231Slinton Node callnode; 5918231Slinton Node cmdnode; 6018231Slinton boolean isfunc; 6118231Slinton } CallEnv; 6218231Slinton 6318231Slinton private CallEnv endproc; 6418231Slinton 659678Slinton /* 669678Slinton * Set a frame to the current activation record. 679678Slinton */ 689678Slinton 699678Slinton private getcurframe(frp) 7018231Slinton Frame frp; 719678Slinton { 729678Slinton register int i; 739678Slinton 749678Slinton checkref(frp); 759678Slinton frp->mask = reg(NREG); 769678Slinton frp->save_ap = reg(ARGP); 779678Slinton frp->save_fp = reg(FRP); 7818231Slinton frp->save_pc = reg(PROGCTR); 799678Slinton for (i = 0; i < NSAVEREG; i++) { 809678Slinton frp->save_reg[i] = reg(i); 819678Slinton } 829678Slinton } 839678Slinton 849678Slinton /* 8518231Slinton * Get the saved registers from one frame to another 8618231Slinton * given mask specifying which registers were actually saved. 8718231Slinton */ 8818231Slinton 8918231Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 9018231Slinton 9118231Slinton private getsaveregs (newfrp, frp, mask) 9218231Slinton Frame newfrp, frp; 9318231Slinton integer mask; 9418231Slinton { 9518231Slinton integer i, j; 9618231Slinton 9718231Slinton j = 0; 9818231Slinton for (i = 0; i < NSAVEREG; i++) { 9918231Slinton if (bis(mask, i)) { 10018231Slinton newfrp->save_reg[i] = frp->save_reg[j]; 10118231Slinton ++j; 10218231Slinton } 10318231Slinton } 10418231Slinton } 10518231Slinton 10618231Slinton /* 1079678Slinton * Return a pointer to the next activation record up the stack. 1089678Slinton * Return nil if there is none. 1099678Slinton * Writes over space pointed to by given argument. 1109678Slinton */ 1119678Slinton 1129678Slinton private Frame nextframe(frp) 1139678Slinton Frame frp; 1149678Slinton { 11518231Slinton Frame newfrp; 1169678Slinton struct Frame frame; 11718231Slinton integer mask; 11833334Sdonn Address prev_frame, callpc; 11918231Slinton static integer ntramp = 0; 1209678Slinton 1219678Slinton newfrp = frp; 12212546Scsvaf prev_frame = frp->save_fp; 12312546Scsvaf 12413937Slinton /* 12513937Slinton * The check for interrupt generated frames is taken from adb with only 12613937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 12713937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>. 12812546Scsvaf * 12912546Scsvaf * As best I can make out it looks like: 13012546Scsvaf * 13113937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>. 13213937Slinton * 13313937Slinton * When the signal occurs an exception block and a frame for the routine 13413937Slinton * in which it occured are pushed on the user stack. Then another frame 13513937Slinton * is pushed corresponding to a call from the kernel to sigsub. 13613937Slinton * 13712546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 13813937Slinton * but in the machine check exception block. It is at the magic address 13914620Ssam * fp + 84. 14012546Scsvaf * 14112546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 14213937Slinton * and takes the pc for sub from the exception block. This allows the 14313937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable. 14412546Scsvaf */ 14512546Scsvaf 14613937Slinton nextf: 14733334Sdonn if (prev_frame + sizeof(struct Frame) <= USRSTACK) { 14833334Sdonn dread(&frame, prev_frame, sizeof(struct Frame)); 14933334Sdonn } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) { 15033334Sdonn dread(&frame, prev_frame, USRSTACK - prev_frame); 15133334Sdonn } else { 15233334Sdonn frame.save_fp = nil; 15333334Sdonn } 15413937Slinton if (ntramp == 1) { 15533334Sdonn dread(&callpc, prev_frame + 92, sizeof(callpc)); 15613937Slinton } else { 15713937Slinton callpc = frame.save_pc; 15813937Slinton } 15918231Slinton if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 1609678Slinton newfrp = nil; 16113937Slinton } else { 16233334Sdonn if (inSignalHandler(callpc)) { 16333334Sdonn ntramp++; 16433334Sdonn prev_frame = frame.save_fp; 16533334Sdonn goto nextf; 16633334Sdonn } 16712546Scsvaf frame.save_pc = callpc; 16813937Slinton ntramp = 0; 16933334Sdonn newfrp->save_fp = frame.save_fp; 17033334Sdonn newfrp->save_pc = frame.save_pc; 1719678Slinton mask = ((frame.mask >> 16) & 0x0fff); 17218231Slinton getsaveregs(newfrp, &frame, mask); 1739678Slinton newfrp->condition_handler = frame.condition_handler; 1749678Slinton newfrp->mask = mask; 1759678Slinton newfrp->save_ap = frame.save_ap; 1769678Slinton } 1779678Slinton return newfrp; 1789678Slinton } 1799678Slinton 1809678Slinton /* 18116618Ssam * Get the current frame information in the given Frame and store the 18216618Ssam * associated function in the given value-result parameter. 18316618Ssam */ 18416618Ssam 18516618Ssam private getcurfunc (frp, fp) 18616618Ssam Frame frp; 18716618Ssam Symbol *fp; 18816618Ssam { 18916618Ssam getcurframe(frp); 19016618Ssam *fp = whatblock(frp->save_pc); 19116618Ssam } 19216618Ssam 19316618Ssam /* 19416618Ssam * Return the frame associated with the next function up the call stack, or 19516618Ssam * nil if there is none. The function is returned in a value-result parameter. 19616618Ssam * For "inline" functions the statically outer function and same frame 19716618Ssam * are returned. 19816618Ssam */ 19916618Ssam 20018231Slinton public Frame nextfunc (frp, fp) 20116618Ssam Frame frp; 20216618Ssam Symbol *fp; 20316618Ssam { 20416618Ssam Symbol t; 20516618Ssam Frame nfrp; 20616618Ssam 20716618Ssam t = *fp; 20816618Ssam checkref(t); 20916618Ssam if (isinline(t)) { 21016618Ssam t = container(t); 21116618Ssam nfrp = frp; 21216618Ssam } else { 21316618Ssam nfrp = nextframe(frp); 21416618Ssam if (nfrp == nil) { 21516618Ssam t = nil; 21616618Ssam } else { 21716618Ssam t = whatblock(nfrp->save_pc); 21816618Ssam } 21916618Ssam } 22016618Ssam *fp = t; 22116618Ssam return nfrp; 22216618Ssam } 22316618Ssam 22416618Ssam /* 2259678Slinton * Return the frame associated with the given function. 2269678Slinton * If the function is nil, return the most recently activated frame. 2279678Slinton * 2289678Slinton * Static allocation for the frame. 2299678Slinton */ 2309678Slinton 2319678Slinton public Frame findframe(f) 2329678Slinton Symbol f; 2339678Slinton { 23418231Slinton Frame frp; 2359678Slinton static struct Frame frame; 23611866Slinton Symbol p; 23718231Slinton Boolean done; 2389678Slinton 2399678Slinton frp = &frame; 2409678Slinton getcurframe(frp); 24118231Slinton if (f != nil) { 24218231Slinton if (f == curfunc and curframe != nil) { 24318231Slinton *frp = *curframe; 24418231Slinton } else { 24518231Slinton done = false; 24618231Slinton p = whatblock(frp->save_pc); 24718231Slinton do { 24818231Slinton if (p == f) { 24918231Slinton done = true; 25018231Slinton } else if (p == program) { 25118231Slinton done = true; 25218231Slinton frp = nil; 25318231Slinton } else { 25418231Slinton frp = nextfunc(frp, &p); 25518231Slinton if (frp == nil) { 25618231Slinton done = true; 25718231Slinton } 25818231Slinton } 25918231Slinton } while (not done); 26015784Ssam } 26118231Slinton } 26218231Slinton return frp; 26318231Slinton } 26418231Slinton 26518231Slinton /* 26618231Slinton * Set the registers according to the given frame pointer. 26718231Slinton */ 26818231Slinton 26918231Slinton public getnewregs (addr) 27018231Slinton Address addr; 27118231Slinton { 27218231Slinton struct Frame frame; 27318231Slinton integer i, j, mask; 27418231Slinton 27518231Slinton dread(&frame, addr, sizeof(frame)); 27618231Slinton setreg(FRP, frame.save_fp); 27718231Slinton setreg(PROGCTR, frame.save_pc); 27833334Sdonn setreg(ARGP, frame.save_ap); 27918231Slinton mask = ((frame.mask >> 16) & 0x0fff); 28018231Slinton j = 0; 28118231Slinton for (i = 0; i < NSAVEREG; i++) { 28218231Slinton if (bis(mask, i)) { 28333334Sdonn setreg(i, frame.save_reg[j]); 28433334Sdonn ++j; 28516636Ssam } 2869678Slinton } 28718231Slinton pc = frame.save_pc; 28818231Slinton setcurfunc(whatblock(pc)); 2899678Slinton } 2909678Slinton 2919678Slinton /* 2929678Slinton * Find the return address of the current procedure/function. 2939678Slinton */ 2949678Slinton 2959678Slinton public Address return_addr() 2969678Slinton { 2979678Slinton Frame frp; 2989678Slinton Address addr; 2999678Slinton struct Frame frame; 3009678Slinton 3019678Slinton frp = &frame; 3029678Slinton getcurframe(frp); 3039678Slinton frp = nextframe(frp); 3049678Slinton if (frp == nil) { 3059678Slinton addr = 0; 3069678Slinton } else { 3079678Slinton addr = frp->save_pc; 3089678Slinton } 3099678Slinton return addr; 3109678Slinton } 3119678Slinton 3129678Slinton /* 3139678Slinton * Push the value associated with the current function. 3149678Slinton */ 3159678Slinton 3169678Slinton public pushretval(len, isindirect) 31718231Slinton integer len; 31818231Slinton boolean isindirect; 3199678Slinton { 3209678Slinton Word r0; 3219678Slinton 3229678Slinton r0 = reg(0); 3239678Slinton if (isindirect) { 3249678Slinton rpush((Address) r0, len); 3259678Slinton } else { 3269678Slinton switch (len) { 3279678Slinton case sizeof(char): 3289678Slinton push(char, r0); 3299678Slinton break; 3309678Slinton 3319678Slinton case sizeof(short): 3329678Slinton push(short, r0); 3339678Slinton break; 3349678Slinton 3359678Slinton default: 3369678Slinton if (len == sizeof(Word)) { 3379678Slinton push(Word, r0); 3389678Slinton } else if (len == 2*sizeof(Word)) { 3399678Slinton push(Word, r0); 3409678Slinton push(Word, reg(1)); 3419678Slinton } else { 34218231Slinton error("[internal error: bad size %d in pushretval]", len); 3439678Slinton } 3449678Slinton break; 3459678Slinton } 3469678Slinton } 3479678Slinton } 3489678Slinton 3499678Slinton /* 3509678Slinton * Return the base address for locals in the given frame. 3519678Slinton */ 3529678Slinton 3539678Slinton public Address locals_base(frp) 35418231Slinton Frame frp; 3559678Slinton { 3569678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 3579678Slinton } 3589678Slinton 3599678Slinton /* 3609678Slinton * Return the base address for arguments in the given frame. 3619678Slinton */ 3629678Slinton 3639678Slinton public Address args_base(frp) 36418231Slinton Frame frp; 3659678Slinton { 3669678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 3679678Slinton } 3689678Slinton 3699678Slinton /* 3709678Slinton * Return saved register n from the given frame. 3719678Slinton */ 3729678Slinton 3739678Slinton public Word savereg(n, frp) 37418231Slinton integer n; 37518231Slinton Frame frp; 3769678Slinton { 37718231Slinton Word w; 3789678Slinton 3799678Slinton if (frp == nil) { 3809678Slinton w = reg(n); 3819678Slinton } else { 3829678Slinton switch (n) { 3839678Slinton case ARGP: 3849678Slinton w = frp->save_ap; 3859678Slinton break; 3869678Slinton 3879678Slinton case FRP: 3889678Slinton w = frp->save_fp; 3899678Slinton break; 3909678Slinton 3919678Slinton case STKP: 3929678Slinton w = reg(STKP); 3939678Slinton break; 3949678Slinton 3959678Slinton case PROGCTR: 3969678Slinton w = frp->save_pc; 3979678Slinton break; 3989678Slinton 3999678Slinton default: 4009678Slinton assert(n >= 0 and n < NSAVEREG); 4019678Slinton w = frp->save_reg[n]; 4029678Slinton break; 4039678Slinton } 4049678Slinton } 4059678Slinton return w; 4069678Slinton } 4079678Slinton 4089678Slinton /* 4099678Slinton * Return the nth argument to the current procedure. 4109678Slinton */ 4119678Slinton 4129678Slinton public Word argn(n, frp) 41318231Slinton integer n; 4149678Slinton Frame frp; 4159678Slinton { 41633334Sdonn Address argaddr; 4179678Slinton Word w; 4189678Slinton 41933334Sdonn argaddr = args_base(frp) + (n * sizeof(Word)); 42033334Sdonn dread(&w, argaddr, sizeof(w)); 4219678Slinton return w; 4229678Slinton } 4239678Slinton 4249678Slinton /* 42518231Slinton * Print a list of currently active blocks starting with most recent. 4269678Slinton */ 4279678Slinton 42818231Slinton public wherecmd() 4299678Slinton { 43018231Slinton walkstack(false); 4319678Slinton } 4329678Slinton 4339678Slinton /* 43418231Slinton * Print the variables in the given frame or the current one if nil. 4359678Slinton */ 4369678Slinton 43718231Slinton public dump (func) 43818231Slinton Symbol func; 4399678Slinton { 44018231Slinton Symbol f; 44118231Slinton Frame frp; 44218231Slinton 44318231Slinton if (func == nil) { 44418231Slinton f = curfunc; 44518231Slinton if (curframe != nil) { 44618231Slinton frp = curframe; 44718231Slinton } else { 44818231Slinton frp = findframe(f); 44918231Slinton } 45018231Slinton } else { 45118231Slinton f = func; 45218231Slinton frp = findframe(f); 45318231Slinton } 45418231Slinton showaggrs = true; 45518231Slinton printcallinfo(f, frp); 45618231Slinton dumpvars(f, frp); 4579678Slinton } 4589678Slinton 4599678Slinton /* 46018231Slinton * Dump all values. 4619678Slinton */ 4629678Slinton 46318231Slinton public dumpall () 4649678Slinton { 4659678Slinton walkstack(true); 4669678Slinton } 4679678Slinton 4689678Slinton /* 4699678Slinton * Walk the stack of active procedures printing information 4709678Slinton * about each active procedure. 4719678Slinton */ 4729678Slinton 4739678Slinton private walkstack(dumpvariables) 4749678Slinton Boolean dumpvariables; 4759678Slinton { 47618231Slinton Frame frp; 47718231Slinton boolean save; 47816618Ssam Symbol f; 4799678Slinton struct Frame frame; 4809678Slinton 48118231Slinton if (notstarted(process) or isfinished(process)) { 4829678Slinton error("program is not active"); 4839678Slinton } else { 4849678Slinton save = walkingstack; 4859678Slinton walkingstack = true; 48618231Slinton showaggrs = dumpvariables; 4879678Slinton frp = &frame; 48816618Ssam getcurfunc(frp, &f); 48918231Slinton for (;;) { 49018231Slinton printcallinfo(f, frp); 4919678Slinton if (dumpvariables) { 4929678Slinton dumpvars(f, frp); 4939678Slinton putchar('\n'); 4949678Slinton } 49516618Ssam frp = nextfunc(frp, &f); 49618231Slinton if (frp == nil or f == program) { 49718231Slinton break; 49818231Slinton } 49918231Slinton } 5009678Slinton if (dumpvariables) { 5019678Slinton printf("in \"%s\":\n", symname(program)); 5029678Slinton dumpvars(program, nil); 5039678Slinton putchar('\n'); 5049678Slinton } 5059678Slinton walkingstack = save; 5069678Slinton } 5079678Slinton } 5089678Slinton 5099678Slinton /* 51018231Slinton * Print out the information about a call, i.e., 51118231Slinton * routine name, parameter values, and source location. 51218231Slinton */ 51318231Slinton 51418231Slinton private printcallinfo (f, frp) 51518231Slinton Symbol f; 51618231Slinton Frame frp; 51718231Slinton { 51818231Slinton Lineno line; 51918231Slinton Address savepc; 52018231Slinton 52118231Slinton savepc = frp->save_pc; 52218231Slinton if (frp->save_fp != reg(FRP)) { 52318231Slinton savepc -= 1; 52418231Slinton } 52518231Slinton printname(stdout, f); 52618231Slinton if (not isinline(f)) { 52718231Slinton printparams(f, frp); 52818231Slinton } 52918231Slinton line = srcline(savepc); 53018231Slinton if (line != 0) { 53118231Slinton printf(", line %d", line); 53218231Slinton printf(" in \"%s\"\n", srcfilename(savepc)); 53318231Slinton } else { 53418231Slinton printf(" at 0x%x\n", savepc); 53518231Slinton } 53618231Slinton } 53718231Slinton 53818231Slinton /* 53916618Ssam * Set the current function to the given symbol. 54016618Ssam * We must adjust "curframe" so that subsequent operations are 54116618Ssam * not confused; for simplicity we simply clear it. 54216618Ssam */ 54316618Ssam 54416618Ssam public setcurfunc (f) 54516618Ssam Symbol f; 54616618Ssam { 54716618Ssam curfunc = f; 54816618Ssam curframe = nil; 54916618Ssam } 55016618Ssam 55116618Ssam /* 55218231Slinton * Return the frame for the current function. 55318231Slinton * The space for the frame is allocated statically. 55418231Slinton */ 55518231Slinton 55618231Slinton public Frame curfuncframe () 55718231Slinton { 55818231Slinton static struct Frame frame; 55918231Slinton Frame frp; 56018231Slinton 56118231Slinton if (curframe == nil) { 56218231Slinton frp = findframe(curfunc); 56318231Slinton curframe = &curframerec; 56418231Slinton *curframe = *frp; 56518231Slinton } else { 56618231Slinton frp = &frame; 56718231Slinton *frp = *curframe; 56818231Slinton } 56918231Slinton return frp; 57018231Slinton } 57118231Slinton 57218231Slinton /* 57316618Ssam * Set curfunc to be N up/down the stack from its current value. 57416618Ssam */ 57516618Ssam 57616618Ssam public up (n) 57716618Ssam integer n; 57816618Ssam { 57916618Ssam integer i; 58016618Ssam Symbol f; 58116618Ssam Frame frp; 58216618Ssam boolean done; 58316618Ssam 58416618Ssam if (not isactive(program)) { 58516618Ssam error("program is not active"); 58616618Ssam } else if (curfunc == nil) { 58716618Ssam error("no current function"); 58816618Ssam } else { 58916618Ssam i = 0; 59016618Ssam f = curfunc; 59118231Slinton frp = curfuncframe(); 59216618Ssam done = false; 59316618Ssam do { 59416618Ssam if (frp == nil) { 59516618Ssam done = true; 59616618Ssam error("not that many levels"); 59716618Ssam } else if (i >= n) { 59816618Ssam done = true; 59916618Ssam curfunc = f; 60016618Ssam curframe = &curframerec; 60116618Ssam *curframe = *frp; 60218231Slinton showaggrs = false; 60318231Slinton printcallinfo(curfunc, curframe); 60416618Ssam } else if (f == program) { 60516618Ssam done = true; 60616618Ssam error("not that many levels"); 60716618Ssam } else { 60816618Ssam frp = nextfunc(frp, &f); 60916618Ssam } 61016618Ssam ++i; 61116618Ssam } while (not done); 61216618Ssam } 61316618Ssam } 61416618Ssam 61516618Ssam public down (n) 61616618Ssam integer n; 61716618Ssam { 61816618Ssam integer i, depth; 61918231Slinton Frame frp, curfrp; 62016618Ssam Symbol f; 62116618Ssam struct Frame frame; 62216618Ssam 62316618Ssam if (not isactive(program)) { 62416618Ssam error("program is not active"); 62516618Ssam } else if (curfunc == nil) { 62616618Ssam error("no current function"); 62716618Ssam } else { 62816618Ssam depth = 0; 62916618Ssam frp = &frame; 63016618Ssam getcurfunc(frp, &f); 63116618Ssam if (curframe == nil) { 63218231Slinton curfrp = findframe(curfunc); 63316618Ssam curframe = &curframerec; 63418231Slinton *curframe = *curfrp; 63516618Ssam } 63616618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 63716618Ssam frp = nextfunc(frp, &f); 63816618Ssam ++depth; 63916618Ssam } 64016618Ssam if (f == nil or n > depth) { 64116618Ssam error("not that many levels"); 64216618Ssam } else { 64316618Ssam depth -= n; 64416618Ssam frp = &frame; 64516618Ssam getcurfunc(frp, &f); 64616618Ssam for (i = 0; i < depth; i++) { 64716618Ssam frp = nextfunc(frp, &f); 64816618Ssam assert(frp != nil); 64916618Ssam } 65016618Ssam curfunc = f; 65116618Ssam *curframe = *frp; 65218231Slinton showaggrs = false; 65318231Slinton printcallinfo(curfunc, curframe); 65416618Ssam } 65516618Ssam } 65616618Ssam } 65716618Ssam 65816618Ssam /* 6599678Slinton * Find the entry point of a procedure or function. 66033334Sdonn * 66133334Sdonn * On the VAX we add the size of the register mask (FUNCOFFSET) or 66233334Sdonn * the size of the Modula-2 internal entry sequence, on other machines 66333334Sdonn * (68000's) we add the entry sequence size (FUNCOFFSET) unless 66433334Sdonn * we're right at the beginning of the program. 6659678Slinton */ 6669678Slinton 66718231Slinton public findbeginning (f) 6689678Slinton Symbol f; 6699678Slinton { 67016618Ssam if (isinternal(f)) { 67133334Sdonn f->symvalue.funcv.beginaddr += 18; /* VAX only */ 67216618Ssam } else { 67333334Sdonn f->symvalue.funcv.beginaddr += FUNCOFFSET; 67416618Ssam } 6759678Slinton } 6769678Slinton 6779678Slinton /* 6789678Slinton * Return the address corresponding to the first line in a function. 6799678Slinton */ 6809678Slinton 6819678Slinton public Address firstline(f) 6829678Slinton Symbol f; 6839678Slinton { 6849678Slinton Address addr; 6859678Slinton 6869678Slinton addr = codeloc(f); 6879678Slinton while (linelookup(addr) == 0 and addr < objsize) { 6889678Slinton ++addr; 6899678Slinton } 6909678Slinton if (addr == objsize) { 6919678Slinton addr = -1; 6929678Slinton } 6939678Slinton return addr; 6949678Slinton } 6959678Slinton 6969678Slinton /* 6979678Slinton * Catcher drops strike three ... 6989678Slinton */ 6999678Slinton 7009678Slinton public runtofirst() 7019678Slinton { 70233334Sdonn Address addr, endaddr; 7039678Slinton 7049678Slinton addr = pc; 70533334Sdonn endaddr = objsize + CODESTART; 70633334Sdonn while (linelookup(addr) == 0 and addr < endaddr) { 7079678Slinton ++addr; 7089678Slinton } 70933334Sdonn if (addr < endaddr) { 7109678Slinton stepto(addr); 7119678Slinton } 7129678Slinton } 7139678Slinton 7149678Slinton /* 7159678Slinton * Return the address corresponding to the end of the program. 7169678Slinton * 7179678Slinton * We look for the entry to "exit". 7189678Slinton */ 7199678Slinton 7209678Slinton public Address lastaddr() 7219678Slinton { 72218231Slinton Symbol s; 7239678Slinton 7249678Slinton s = lookup(identname("exit", true)); 7259678Slinton if (s == nil) { 7269678Slinton panic("can't find exit"); 7279678Slinton } 7289678Slinton return codeloc(s); 7299678Slinton } 7309678Slinton 7319678Slinton /* 7329678Slinton * Decide if the given function is currently active. 7339678Slinton * 7349678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 7359678Slinton * Presumably information evaluated while walking the stack is active. 7369678Slinton */ 7379678Slinton 73833334Sdonn public Boolean isactive (f) 7399678Slinton Symbol f; 7409678Slinton { 74118231Slinton Boolean b; 7429678Slinton 7439678Slinton if (isfinished(process)) { 7449678Slinton b = false; 7459678Slinton } else { 74633334Sdonn if (walkingstack or f == program or f == nil or 7479678Slinton (ismodule(f) and isactive(container(f)))) { 7489678Slinton b = true; 7499678Slinton } else { 7509678Slinton b = (Boolean) (findframe(f) != nil); 7519678Slinton } 7529678Slinton } 7539678Slinton return b; 7549678Slinton } 7559678Slinton 7569678Slinton /* 7579678Slinton * Evaluate a call to a procedure. 7589678Slinton */ 7599678Slinton 76018231Slinton public callproc(exprnode, isfunc) 76118231Slinton Node exprnode; 76218231Slinton boolean isfunc; 7639678Slinton { 76418231Slinton Node procnode, arglist; 7659678Slinton Symbol proc; 76618231Slinton integer argc; 7679678Slinton 76818231Slinton procnode = exprnode->value.arg[0]; 76918231Slinton arglist = exprnode->value.arg[1]; 7709678Slinton if (procnode->op != O_SYM) { 7719678Slinton beginerrmsg(); 7729678Slinton fprintf(stderr, "can't call \""); 7739678Slinton prtree(stderr, procnode); 7749678Slinton fprintf(stderr, "\""); 7759678Slinton enderrmsg(); 7769678Slinton } 7779678Slinton assert(procnode->op == O_SYM); 7789678Slinton proc = procnode->value.sym; 7799678Slinton if (not isblock(proc)) { 7809678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 7819678Slinton } 78218231Slinton endproc.isfunc = isfunc; 78318231Slinton endproc.callnode = exprnode; 78418231Slinton endproc.cmdnode = topnode; 7859678Slinton pushenv(); 7869678Slinton pc = codeloc(proc); 7879678Slinton argc = pushargs(proc, arglist); 78833334Sdonn setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ 7899678Slinton beginproc(proc, argc); 79018231Slinton event_once( 79118231Slinton build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 79218231Slinton buildcmdlist(build(O_PROCRTN, proc)) 79318231Slinton ); 79418231Slinton isstopped = false; 79518231Slinton if (not bpact()) { 79618231Slinton isstopped = true; 79718231Slinton cont(0); 79818231Slinton } 79918231Slinton /* 80018231Slinton * bpact() won't return true, it will call printstatus() and go back 80118231Slinton * to command input if a breakpoint is found. 80218231Slinton */ 8039678Slinton /* NOTREACHED */ 8049678Slinton } 8059678Slinton 8069678Slinton /* 8079678Slinton * Push the arguments on the process' stack. We do this by first 8089678Slinton * evaluating them on the "eval" stack, then copying into the process' 8099678Slinton * space. 8109678Slinton */ 8119678Slinton 81218231Slinton private integer pushargs(proc, arglist) 8139678Slinton Symbol proc; 8149678Slinton Node arglist; 8159678Slinton { 8169678Slinton Stack *savesp; 8179678Slinton int argc, args_size; 8189678Slinton 8199678Slinton savesp = sp; 82026324Ssam if (varIsSet("$unsafecall")) { 82126324Ssam argc = unsafe_evalargs(proc, arglist); 82226324Ssam } else { 82326324Ssam argc = evalargs(proc, arglist); 82426324Ssam } 8259678Slinton args_size = sp - savesp; 8269678Slinton setreg(STKP, reg(STKP) - args_size); 8279678Slinton dwrite(savesp, reg(STKP), args_size); 8289678Slinton sp = savesp; 8299678Slinton return argc; 8309678Slinton } 8319678Slinton 8329678Slinton /* 83316618Ssam * Check to see if an expression is correct for a given parameter. 83416618Ssam * If the given parameter is false, don't worry about type inconsistencies. 83516618Ssam * 83616618Ssam * Return whether or not it is ok. 8379678Slinton */ 8389678Slinton 83916618Ssam private boolean chkparam (actual, formal, chk) 84016618Ssam Node actual; 84116618Ssam Symbol formal; 84216618Ssam boolean chk; 84316618Ssam { 84416618Ssam boolean b; 84516618Ssam 84616618Ssam b = true; 84716618Ssam if (chk) { 84816618Ssam if (formal == nil) { 84916618Ssam beginerrmsg(); 85016618Ssam fprintf(stderr, "too many parameters"); 85116618Ssam b = false; 85216618Ssam } else if (not compatible(formal->type, actual->nodetype)) { 85316618Ssam beginerrmsg(); 85416618Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 85516618Ssam b = false; 85616618Ssam } 85716618Ssam } 85818231Slinton if (b and formal != nil and 85918231Slinton isvarparam(formal) and not isopenarray(formal->type) and 86018231Slinton not ( 86118231Slinton actual->op == O_RVAL or actual->nodetype == t_addr or 86218231Slinton ( 86318231Slinton actual->op == O_TYPERENAME and 86418231Slinton ( 86518231Slinton actual->value.arg[0]->op == O_RVAL or 86618231Slinton actual->value.arg[0]->nodetype == t_addr 86718231Slinton ) 86818231Slinton ) 86918231Slinton ) 87018231Slinton ) { 87116618Ssam beginerrmsg(); 87216618Ssam fprintf(stderr, "expected variable, found \""); 87316618Ssam prtree(stderr, actual); 87416618Ssam fprintf(stderr, "\""); 87516618Ssam b = false; 87616618Ssam } 87716618Ssam return b; 87816618Ssam } 87916618Ssam 88016618Ssam /* 88116618Ssam * Pass an expression to a particular parameter. 88216618Ssam * 88316618Ssam * Normally we pass either the address or value, but in some cases 88416618Ssam * (such as C strings) we want to copy the value onto the stack and 88516618Ssam * pass its address. 88618231Slinton * 88718231Slinton * Another special case raised by strings is the possibility that 88818231Slinton * the actual parameter will be larger than the formal, even with 88918231Slinton * appropriate type-checking. This occurs because we assume during 89018231Slinton * evaluation that strings are null-terminated, whereas some languages, 89118231Slinton * notably Pascal, do not work under that assumption. 89216618Ssam */ 89316618Ssam 89416618Ssam private passparam (actual, formal) 89516618Ssam Node actual; 89616618Ssam Symbol formal; 89716618Ssam { 89816618Ssam boolean b; 89916618Ssam Address addr; 90016618Ssam Stack *savesp; 90118231Slinton integer actsize, formsize; 90216618Ssam 90318231Slinton if (formal != nil and isvarparam(formal) and 90418231Slinton (not isopenarray(formal->type)) 90518231Slinton ) { 90616618Ssam addr = lval(actual->value.arg[0]); 90716618Ssam push(Address, addr); 90816618Ssam } else if (passaddr(formal, actual->nodetype)) { 90916618Ssam savesp = sp; 91016618Ssam eval(actual); 91118231Slinton actsize = sp - savesp; 91218231Slinton setreg(STKP, 91318231Slinton reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) 91418231Slinton ); 91518231Slinton dwrite(savesp, reg(STKP), actsize); 91616618Ssam sp = savesp; 91716618Ssam push(Address, reg(STKP)); 91816618Ssam if (formal != nil and isopenarray(formal->type)) { 91918231Slinton push(integer, actsize div size(formal->type->type)); 92016618Ssam } 92118231Slinton } else if (formal != nil) { 92218231Slinton formsize = size(formal); 92318231Slinton savesp = sp; 92418231Slinton eval(actual); 92518231Slinton actsize = sp - savesp; 92618231Slinton if (actsize > formsize) { 92718231Slinton sp -= (actsize - formsize); 92818231Slinton } 92916618Ssam } else { 93016618Ssam eval(actual); 93116618Ssam } 93216618Ssam } 93316618Ssam 93416618Ssam /* 93516618Ssam * Evaluate an argument list left-to-right. 93616618Ssam */ 93716618Ssam 93818231Slinton private integer evalargs(proc, arglist) 9399678Slinton Symbol proc; 9409678Slinton Node arglist; 9419678Slinton { 94216618Ssam Node p, actual; 94316618Ssam Symbol formal; 9449678Slinton Stack *savesp; 94518231Slinton integer count; 94616618Ssam boolean chk; 9479678Slinton 9489678Slinton savesp = sp; 9499678Slinton count = 0; 95016618Ssam formal = proc->chain; 95116618Ssam chk = (boolean) (not nosource(proc)); 9529678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 95316618Ssam assert(p->op == O_COMMA); 95416618Ssam actual = p->value.arg[0]; 95516618Ssam if (not chkparam(actual, formal, chk)) { 95616618Ssam fprintf(stderr, " in call to %s", symname(proc)); 9579678Slinton sp = savesp; 95816618Ssam enderrmsg(); 9599678Slinton } 96016618Ssam passparam(actual, formal); 96116618Ssam if (formal != nil) { 96216618Ssam formal = formal->chain; 9639678Slinton } 9649678Slinton ++count; 9659678Slinton } 96616618Ssam if (chk) { 96716618Ssam if (formal != nil) { 96816618Ssam sp = savesp; 96916618Ssam error("not enough parameters to %s", symname(proc)); 97016618Ssam } 9719678Slinton } 9729678Slinton return count; 9739678Slinton } 9749678Slinton 97526324Ssam /* 97633334Sdonn * Evaluate an argument list without any type checking. 97733334Sdonn * This is only useful for procedures with a varying number of 97833334Sdonn * arguments that are compiled -g. 97926324Ssam */ 98026324Ssam 98133334Sdonn private integer unsafe_evalargs (proc, arglist) 98226324Ssam Symbol proc; 98326324Ssam Node arglist; 98426324Ssam { 98526324Ssam Node p; 98633334Sdonn integer count; 98726324Ssam 98826324Ssam count = 0; 98926324Ssam for (p = arglist; p != nil; p = p->value.arg[1]) { 99026324Ssam assert(p->op == O_COMMA); 99126324Ssam eval(p->value.arg[0]); 99226324Ssam ++count; 99326324Ssam } 99426324Ssam return count; 99526324Ssam } 99626324Ssam 9979678Slinton public procreturn(f) 9989678Slinton Symbol f; 9999678Slinton { 100018231Slinton integer retvalsize; 100118231Slinton Node tmp; 100218231Slinton char *copy; 100318231Slinton 10049678Slinton flushoutput(); 10059678Slinton popenv(); 100618231Slinton if (endproc.isfunc) { 100718231Slinton retvalsize = size(f->type); 100818231Slinton if (retvalsize > sizeof(long)) { 100918231Slinton pushretval(retvalsize, true); 101018231Slinton copy = newarr(char, retvalsize); 101118231Slinton popn(retvalsize, copy); 101218231Slinton tmp = build(O_SCON, copy); 101318231Slinton } else { 101418231Slinton tmp = build(O_LCON, (long) (reg(0))); 101518231Slinton } 101618231Slinton tmp->nodetype = f->type; 101718231Slinton tfree(endproc.callnode); 101818231Slinton *(endproc.callnode) = *(tmp); 101918231Slinton dispose(tmp); 102018231Slinton eval(endproc.cmdnode); 102118231Slinton } else { 102218231Slinton putchar('\n'); 102318231Slinton printname(stdout, f); 102433334Sdonn printf(" returns successfully\n"); 102518231Slinton } 10269678Slinton erecover(); 10279678Slinton } 10289678Slinton 10299678Slinton /* 10309678Slinton * Push the current environment. 10319678Slinton */ 10329678Slinton 10339678Slinton private pushenv() 10349678Slinton { 10359678Slinton push(Address, pc); 10369678Slinton push(Lineno, curline); 10379678Slinton push(String, cursource); 10389678Slinton push(Boolean, isstopped); 10399678Slinton push(Symbol, curfunc); 104016618Ssam push(Frame, curframe); 104116618Ssam push(struct Frame, curframerec); 104218231Slinton push(CallEnv, endproc); 10439678Slinton push(Word, reg(PROGCTR)); 10449678Slinton push(Word, reg(STKP)); 104533334Sdonn push(Word, reg(FRP)); 10469678Slinton } 10479678Slinton 10489678Slinton /* 10499678Slinton * Pop back to the real world. 10509678Slinton */ 10519678Slinton 10529678Slinton public popenv() 10539678Slinton { 105418231Slinton String filename; 10559678Slinton 105633334Sdonn setreg(FRP, pop(Word)); 10579678Slinton setreg(STKP, pop(Word)); 10589678Slinton setreg(PROGCTR, pop(Word)); 105918231Slinton endproc = pop(CallEnv); 106016618Ssam curframerec = pop(struct Frame); 106116618Ssam curframe = pop(Frame); 10629678Slinton curfunc = pop(Symbol); 10639678Slinton isstopped = pop(Boolean); 10649678Slinton filename = pop(String); 10659678Slinton curline = pop(Lineno); 10669678Slinton pc = pop(Address); 10679678Slinton setsource(filename); 10689678Slinton } 10699678Slinton 10709678Slinton /* 10719678Slinton * Flush the debuggee's standard output. 10729678Slinton * 10739678Slinton * This is VERY dependent on the use of stdio. 10749678Slinton */ 10759678Slinton 10769678Slinton public flushoutput() 10779678Slinton { 107818231Slinton Symbol p, iob; 107918231Slinton Stack *savesp; 10809678Slinton 10819678Slinton p = lookup(identname("fflush", true)); 10829678Slinton while (p != nil and not isblock(p)) { 10839678Slinton p = p->next_sym; 10849678Slinton } 10859678Slinton if (p != nil) { 10869678Slinton iob = lookup(identname("_iob", true)); 10879678Slinton if (iob != nil) { 10889678Slinton pushenv(); 108933334Sdonn pc = codeloc(p) - FUNCOFFSET; 10909678Slinton savesp = sp; 109133334Sdonn push(long, address(iob, nil) + sizeof(*stdout)); 10929678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 10939678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 10949678Slinton sp = savesp; 10959678Slinton beginproc(p, 1); 10969678Slinton stepto(return_addr()); 10979678Slinton popenv(); 10989678Slinton } 10999678Slinton } 11009678Slinton } 1101