121621Sdist /* 221621Sdist * Copyright (c) 1983 Regents of the University of California. 321621Sdist * All rights reserved. The Berkeley software License Agreement 421621Sdist * specifies the terms and conditions for redistribution. 521621Sdist */ 69678Slinton 721621Sdist #ifndef lint 8*33334Sdonn static char sccsid[] = "@(#)runtime.vax.c 5.3 (Berkeley) 01/12/88"; 921621Sdist #endif not lint 109678Slinton 11*33334Sdonn static char rcsid[] = "$Header: runtime.vax.c,v 1.3 88/01/11 21:27:00 donn Exp $"; 1218231Slinton 139678Slinton /* 149678Slinton * Runtime organization dependent routines, mostly dealing with 159678Slinton * activation records. 169678Slinton */ 179678Slinton 189678Slinton #include "defs.h" 199678Slinton #include "runtime.h" 209678Slinton #include "process.h" 219678Slinton #include "machine.h" 229678Slinton #include "events.h" 239678Slinton #include "mappings.h" 249678Slinton #include "symbols.h" 259678Slinton #include "tree.h" 269678Slinton #include "eval.h" 279678Slinton #include "operators.h" 289678Slinton #include "object.h" 2912546Scsvaf #include <sys/param.h> 30*33334Sdonn #include <signal.h> 319678Slinton 329678Slinton #ifndef public 339678Slinton typedef struct Frame *Frame; 349678Slinton 359678Slinton #include "machine.h" 369678Slinton #endif 379678Slinton 389678Slinton #define NSAVEREG 12 399678Slinton 409678Slinton struct Frame { 4118231Slinton integer condition_handler; 4218231Slinton integer mask; 439678Slinton Address save_ap; /* argument pointer */ 449678Slinton Address save_fp; /* frame pointer */ 459678Slinton Address save_pc; /* program counter */ 469678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 479678Slinton }; 489678Slinton 4916618Ssam private Frame curframe = nil; 5016618Ssam private struct Frame curframerec; 519678Slinton private Boolean walkingstack = false; 529678Slinton 5316618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 5416618Ssam 55*33334Sdonn #define inSignalHandler(addr) \ 56*33334Sdonn (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES))) 5718231Slinton 5818231Slinton typedef struct { 5918231Slinton Node callnode; 6018231Slinton Node cmdnode; 6118231Slinton boolean isfunc; 6218231Slinton } CallEnv; 6318231Slinton 6418231Slinton private CallEnv endproc; 6518231Slinton 669678Slinton /* 679678Slinton * Set a frame to the current activation record. 689678Slinton */ 699678Slinton 709678Slinton private getcurframe(frp) 7118231Slinton Frame frp; 729678Slinton { 739678Slinton register int i; 749678Slinton 759678Slinton checkref(frp); 769678Slinton frp->mask = reg(NREG); 779678Slinton frp->save_ap = reg(ARGP); 789678Slinton frp->save_fp = reg(FRP); 7918231Slinton frp->save_pc = reg(PROGCTR); 809678Slinton for (i = 0; i < NSAVEREG; i++) { 819678Slinton frp->save_reg[i] = reg(i); 829678Slinton } 839678Slinton } 849678Slinton 859678Slinton /* 8618231Slinton * Get the saved registers from one frame to another 8718231Slinton * given mask specifying which registers were actually saved. 8818231Slinton */ 8918231Slinton 9018231Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 9118231Slinton 9218231Slinton private getsaveregs (newfrp, frp, mask) 9318231Slinton Frame newfrp, frp; 9418231Slinton integer mask; 9518231Slinton { 9618231Slinton integer i, j; 9718231Slinton 9818231Slinton j = 0; 9918231Slinton for (i = 0; i < NSAVEREG; i++) { 10018231Slinton if (bis(mask, i)) { 10118231Slinton newfrp->save_reg[i] = frp->save_reg[j]; 10218231Slinton ++j; 10318231Slinton } 10418231Slinton } 10518231Slinton } 10618231Slinton 10718231Slinton /* 1089678Slinton * Return a pointer to the next activation record up the stack. 1099678Slinton * Return nil if there is none. 1109678Slinton * Writes over space pointed to by given argument. 1119678Slinton */ 1129678Slinton 1139678Slinton private Frame nextframe(frp) 1149678Slinton Frame frp; 1159678Slinton { 11618231Slinton Frame newfrp; 1179678Slinton struct Frame frame; 11818231Slinton integer mask; 119*33334Sdonn Address prev_frame, callpc; 12018231Slinton static integer ntramp = 0; 1219678Slinton 1229678Slinton newfrp = frp; 12312546Scsvaf prev_frame = frp->save_fp; 12412546Scsvaf 12513937Slinton /* 12613937Slinton * The check for interrupt generated frames is taken from adb with only 12713937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 12813937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>. 12912546Scsvaf * 13012546Scsvaf * As best I can make out it looks like: 13112546Scsvaf * 13213937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>. 13313937Slinton * 13413937Slinton * When the signal occurs an exception block and a frame for the routine 13513937Slinton * in which it occured are pushed on the user stack. Then another frame 13613937Slinton * is pushed corresponding to a call from the kernel to sigsub. 13713937Slinton * 13812546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 13913937Slinton * but in the machine check exception block. It is at the magic address 14014620Ssam * fp + 84. 14112546Scsvaf * 14212546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 14313937Slinton * and takes the pc for sub from the exception block. This allows the 14413937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable. 14512546Scsvaf */ 14612546Scsvaf 14713937Slinton nextf: 148*33334Sdonn if (prev_frame + sizeof(struct Frame) <= USRSTACK) { 149*33334Sdonn dread(&frame, prev_frame, sizeof(struct Frame)); 150*33334Sdonn } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) { 151*33334Sdonn dread(&frame, prev_frame, USRSTACK - prev_frame); 152*33334Sdonn } else { 153*33334Sdonn frame.save_fp = nil; 154*33334Sdonn } 15513937Slinton if (ntramp == 1) { 156*33334Sdonn dread(&callpc, prev_frame + 92, sizeof(callpc)); 15713937Slinton } else { 15813937Slinton callpc = frame.save_pc; 15913937Slinton } 16018231Slinton if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 1619678Slinton newfrp = nil; 16213937Slinton } else { 163*33334Sdonn if (inSignalHandler(callpc)) { 164*33334Sdonn ntramp++; 165*33334Sdonn prev_frame = frame.save_fp; 166*33334Sdonn goto nextf; 167*33334Sdonn } 16812546Scsvaf frame.save_pc = callpc; 16913937Slinton ntramp = 0; 170*33334Sdonn newfrp->save_fp = frame.save_fp; 171*33334Sdonn newfrp->save_pc = frame.save_pc; 1729678Slinton mask = ((frame.mask >> 16) & 0x0fff); 17318231Slinton getsaveregs(newfrp, &frame, mask); 1749678Slinton newfrp->condition_handler = frame.condition_handler; 1759678Slinton newfrp->mask = mask; 1769678Slinton newfrp->save_ap = frame.save_ap; 1779678Slinton } 1789678Slinton return newfrp; 1799678Slinton } 1809678Slinton 1819678Slinton /* 18216618Ssam * Get the current frame information in the given Frame and store the 18316618Ssam * associated function in the given value-result parameter. 18416618Ssam */ 18516618Ssam 18616618Ssam private getcurfunc (frp, fp) 18716618Ssam Frame frp; 18816618Ssam Symbol *fp; 18916618Ssam { 19016618Ssam getcurframe(frp); 19116618Ssam *fp = whatblock(frp->save_pc); 19216618Ssam } 19316618Ssam 19416618Ssam /* 19516618Ssam * Return the frame associated with the next function up the call stack, or 19616618Ssam * nil if there is none. The function is returned in a value-result parameter. 19716618Ssam * For "inline" functions the statically outer function and same frame 19816618Ssam * are returned. 19916618Ssam */ 20016618Ssam 20118231Slinton public Frame nextfunc (frp, fp) 20216618Ssam Frame frp; 20316618Ssam Symbol *fp; 20416618Ssam { 20516618Ssam Symbol t; 20616618Ssam Frame nfrp; 20716618Ssam 20816618Ssam t = *fp; 20916618Ssam checkref(t); 21016618Ssam if (isinline(t)) { 21116618Ssam t = container(t); 21216618Ssam nfrp = frp; 21316618Ssam } else { 21416618Ssam nfrp = nextframe(frp); 21516618Ssam if (nfrp == nil) { 21616618Ssam t = nil; 21716618Ssam } else { 21816618Ssam t = whatblock(nfrp->save_pc); 21916618Ssam } 22016618Ssam } 22116618Ssam *fp = t; 22216618Ssam return nfrp; 22316618Ssam } 22416618Ssam 22516618Ssam /* 2269678Slinton * Return the frame associated with the given function. 2279678Slinton * If the function is nil, return the most recently activated frame. 2289678Slinton * 2299678Slinton * Static allocation for the frame. 2309678Slinton */ 2319678Slinton 2329678Slinton public Frame findframe(f) 2339678Slinton Symbol f; 2349678Slinton { 23518231Slinton Frame frp; 2369678Slinton static struct Frame frame; 23711866Slinton Symbol p; 23818231Slinton Boolean done; 2399678Slinton 2409678Slinton frp = &frame; 2419678Slinton getcurframe(frp); 24218231Slinton if (f != nil) { 24318231Slinton if (f == curfunc and curframe != nil) { 24418231Slinton *frp = *curframe; 24518231Slinton } else { 24618231Slinton done = false; 24718231Slinton p = whatblock(frp->save_pc); 24818231Slinton do { 24918231Slinton if (p == f) { 25018231Slinton done = true; 25118231Slinton } else if (p == program) { 25218231Slinton done = true; 25318231Slinton frp = nil; 25418231Slinton } else { 25518231Slinton frp = nextfunc(frp, &p); 25618231Slinton if (frp == nil) { 25718231Slinton done = true; 25818231Slinton } 25918231Slinton } 26018231Slinton } while (not done); 26115784Ssam } 26218231Slinton } 26318231Slinton return frp; 26418231Slinton } 26518231Slinton 26618231Slinton /* 26718231Slinton * Set the registers according to the given frame pointer. 26818231Slinton */ 26918231Slinton 27018231Slinton public getnewregs (addr) 27118231Slinton Address addr; 27218231Slinton { 27318231Slinton struct Frame frame; 27418231Slinton integer i, j, mask; 27518231Slinton 27618231Slinton dread(&frame, addr, sizeof(frame)); 27718231Slinton setreg(FRP, frame.save_fp); 27818231Slinton setreg(PROGCTR, frame.save_pc); 279*33334Sdonn setreg(ARGP, frame.save_ap); 28018231Slinton mask = ((frame.mask >> 16) & 0x0fff); 28118231Slinton j = 0; 28218231Slinton for (i = 0; i < NSAVEREG; i++) { 28318231Slinton if (bis(mask, i)) { 284*33334Sdonn setreg(i, frame.save_reg[j]); 285*33334Sdonn ++j; 28616636Ssam } 2879678Slinton } 28818231Slinton pc = frame.save_pc; 28918231Slinton setcurfunc(whatblock(pc)); 2909678Slinton } 2919678Slinton 2929678Slinton /* 2939678Slinton * Find the return address of the current procedure/function. 2949678Slinton */ 2959678Slinton 2969678Slinton public Address return_addr() 2979678Slinton { 2989678Slinton Frame frp; 2999678Slinton Address addr; 3009678Slinton struct Frame frame; 3019678Slinton 3029678Slinton frp = &frame; 3039678Slinton getcurframe(frp); 3049678Slinton frp = nextframe(frp); 3059678Slinton if (frp == nil) { 3069678Slinton addr = 0; 3079678Slinton } else { 3089678Slinton addr = frp->save_pc; 3099678Slinton } 3109678Slinton return addr; 3119678Slinton } 3129678Slinton 3139678Slinton /* 3149678Slinton * Push the value associated with the current function. 3159678Slinton */ 3169678Slinton 3179678Slinton public pushretval(len, isindirect) 31818231Slinton integer len; 31918231Slinton boolean isindirect; 3209678Slinton { 3219678Slinton Word r0; 3229678Slinton 3239678Slinton r0 = reg(0); 3249678Slinton if (isindirect) { 3259678Slinton rpush((Address) r0, len); 3269678Slinton } else { 3279678Slinton switch (len) { 3289678Slinton case sizeof(char): 3299678Slinton push(char, r0); 3309678Slinton break; 3319678Slinton 3329678Slinton case sizeof(short): 3339678Slinton push(short, r0); 3349678Slinton break; 3359678Slinton 3369678Slinton default: 3379678Slinton if (len == sizeof(Word)) { 3389678Slinton push(Word, r0); 3399678Slinton } else if (len == 2*sizeof(Word)) { 3409678Slinton push(Word, r0); 3419678Slinton push(Word, reg(1)); 3429678Slinton } else { 34318231Slinton error("[internal error: bad size %d in pushretval]", len); 3449678Slinton } 3459678Slinton break; 3469678Slinton } 3479678Slinton } 3489678Slinton } 3499678Slinton 3509678Slinton /* 3519678Slinton * Return the base address for locals in the given frame. 3529678Slinton */ 3539678Slinton 3549678Slinton public Address locals_base(frp) 35518231Slinton Frame frp; 3569678Slinton { 3579678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 3589678Slinton } 3599678Slinton 3609678Slinton /* 3619678Slinton * Return the base address for arguments in the given frame. 3629678Slinton */ 3639678Slinton 3649678Slinton public Address args_base(frp) 36518231Slinton Frame frp; 3669678Slinton { 3679678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 3689678Slinton } 3699678Slinton 3709678Slinton /* 3719678Slinton * Return saved register n from the given frame. 3729678Slinton */ 3739678Slinton 3749678Slinton public Word savereg(n, frp) 37518231Slinton integer n; 37618231Slinton Frame frp; 3779678Slinton { 37818231Slinton Word w; 3799678Slinton 3809678Slinton if (frp == nil) { 3819678Slinton w = reg(n); 3829678Slinton } else { 3839678Slinton switch (n) { 3849678Slinton case ARGP: 3859678Slinton w = frp->save_ap; 3869678Slinton break; 3879678Slinton 3889678Slinton case FRP: 3899678Slinton w = frp->save_fp; 3909678Slinton break; 3919678Slinton 3929678Slinton case STKP: 3939678Slinton w = reg(STKP); 3949678Slinton break; 3959678Slinton 3969678Slinton case PROGCTR: 3979678Slinton w = frp->save_pc; 3989678Slinton break; 3999678Slinton 4009678Slinton default: 4019678Slinton assert(n >= 0 and n < NSAVEREG); 4029678Slinton w = frp->save_reg[n]; 4039678Slinton break; 4049678Slinton } 4059678Slinton } 4069678Slinton return w; 4079678Slinton } 4089678Slinton 4099678Slinton /* 4109678Slinton * Return the nth argument to the current procedure. 4119678Slinton */ 4129678Slinton 4139678Slinton public Word argn(n, frp) 41418231Slinton integer n; 4159678Slinton Frame frp; 4169678Slinton { 417*33334Sdonn Address argaddr; 4189678Slinton Word w; 4199678Slinton 420*33334Sdonn argaddr = args_base(frp) + (n * sizeof(Word)); 421*33334Sdonn dread(&w, argaddr, sizeof(w)); 4229678Slinton return w; 4239678Slinton } 4249678Slinton 4259678Slinton /* 42618231Slinton * Print a list of currently active blocks starting with most recent. 4279678Slinton */ 4289678Slinton 42918231Slinton public wherecmd() 4309678Slinton { 43118231Slinton walkstack(false); 4329678Slinton } 4339678Slinton 4349678Slinton /* 43518231Slinton * Print the variables in the given frame or the current one if nil. 4369678Slinton */ 4379678Slinton 43818231Slinton public dump (func) 43918231Slinton Symbol func; 4409678Slinton { 44118231Slinton Symbol f; 44218231Slinton Frame frp; 44318231Slinton 44418231Slinton if (func == nil) { 44518231Slinton f = curfunc; 44618231Slinton if (curframe != nil) { 44718231Slinton frp = curframe; 44818231Slinton } else { 44918231Slinton frp = findframe(f); 45018231Slinton } 45118231Slinton } else { 45218231Slinton f = func; 45318231Slinton frp = findframe(f); 45418231Slinton } 45518231Slinton showaggrs = true; 45618231Slinton printcallinfo(f, frp); 45718231Slinton dumpvars(f, frp); 4589678Slinton } 4599678Slinton 4609678Slinton /* 46118231Slinton * Dump all values. 4629678Slinton */ 4639678Slinton 46418231Slinton public dumpall () 4659678Slinton { 4669678Slinton walkstack(true); 4679678Slinton } 4689678Slinton 4699678Slinton /* 4709678Slinton * Walk the stack of active procedures printing information 4719678Slinton * about each active procedure. 4729678Slinton */ 4739678Slinton 4749678Slinton private walkstack(dumpvariables) 4759678Slinton Boolean dumpvariables; 4769678Slinton { 47718231Slinton Frame frp; 47818231Slinton boolean save; 47916618Ssam Symbol f; 4809678Slinton struct Frame frame; 4819678Slinton 48218231Slinton if (notstarted(process) or isfinished(process)) { 4839678Slinton error("program is not active"); 4849678Slinton } else { 4859678Slinton save = walkingstack; 4869678Slinton walkingstack = true; 48718231Slinton showaggrs = dumpvariables; 4889678Slinton frp = &frame; 48916618Ssam getcurfunc(frp, &f); 49018231Slinton for (;;) { 49118231Slinton printcallinfo(f, frp); 4929678Slinton if (dumpvariables) { 4939678Slinton dumpvars(f, frp); 4949678Slinton putchar('\n'); 4959678Slinton } 49616618Ssam frp = nextfunc(frp, &f); 49718231Slinton if (frp == nil or f == program) { 49818231Slinton break; 49918231Slinton } 50018231Slinton } 5019678Slinton if (dumpvariables) { 5029678Slinton printf("in \"%s\":\n", symname(program)); 5039678Slinton dumpvars(program, nil); 5049678Slinton putchar('\n'); 5059678Slinton } 5069678Slinton walkingstack = save; 5079678Slinton } 5089678Slinton } 5099678Slinton 5109678Slinton /* 51118231Slinton * Print out the information about a call, i.e., 51218231Slinton * routine name, parameter values, and source location. 51318231Slinton */ 51418231Slinton 51518231Slinton private printcallinfo (f, frp) 51618231Slinton Symbol f; 51718231Slinton Frame frp; 51818231Slinton { 51918231Slinton Lineno line; 52018231Slinton Address savepc; 52118231Slinton 52218231Slinton savepc = frp->save_pc; 52318231Slinton if (frp->save_fp != reg(FRP)) { 52418231Slinton savepc -= 1; 52518231Slinton } 52618231Slinton printname(stdout, f); 52718231Slinton if (not isinline(f)) { 52818231Slinton printparams(f, frp); 52918231Slinton } 53018231Slinton line = srcline(savepc); 53118231Slinton if (line != 0) { 53218231Slinton printf(", line %d", line); 53318231Slinton printf(" in \"%s\"\n", srcfilename(savepc)); 53418231Slinton } else { 53518231Slinton printf(" at 0x%x\n", savepc); 53618231Slinton } 53718231Slinton } 53818231Slinton 53918231Slinton /* 54016618Ssam * Set the current function to the given symbol. 54116618Ssam * We must adjust "curframe" so that subsequent operations are 54216618Ssam * not confused; for simplicity we simply clear it. 54316618Ssam */ 54416618Ssam 54516618Ssam public setcurfunc (f) 54616618Ssam Symbol f; 54716618Ssam { 54816618Ssam curfunc = f; 54916618Ssam curframe = nil; 55016618Ssam } 55116618Ssam 55216618Ssam /* 55318231Slinton * Return the frame for the current function. 55418231Slinton * The space for the frame is allocated statically. 55518231Slinton */ 55618231Slinton 55718231Slinton public Frame curfuncframe () 55818231Slinton { 55918231Slinton static struct Frame frame; 56018231Slinton Frame frp; 56118231Slinton 56218231Slinton if (curframe == nil) { 56318231Slinton frp = findframe(curfunc); 56418231Slinton curframe = &curframerec; 56518231Slinton *curframe = *frp; 56618231Slinton } else { 56718231Slinton frp = &frame; 56818231Slinton *frp = *curframe; 56918231Slinton } 57018231Slinton return frp; 57118231Slinton } 57218231Slinton 57318231Slinton /* 57416618Ssam * Set curfunc to be N up/down the stack from its current value. 57516618Ssam */ 57616618Ssam 57716618Ssam public up (n) 57816618Ssam integer n; 57916618Ssam { 58016618Ssam integer i; 58116618Ssam Symbol f; 58216618Ssam Frame frp; 58316618Ssam boolean done; 58416618Ssam 58516618Ssam if (not isactive(program)) { 58616618Ssam error("program is not active"); 58716618Ssam } else if (curfunc == nil) { 58816618Ssam error("no current function"); 58916618Ssam } else { 59016618Ssam i = 0; 59116618Ssam f = curfunc; 59218231Slinton frp = curfuncframe(); 59316618Ssam done = false; 59416618Ssam do { 59516618Ssam if (frp == nil) { 59616618Ssam done = true; 59716618Ssam error("not that many levels"); 59816618Ssam } else if (i >= n) { 59916618Ssam done = true; 60016618Ssam curfunc = f; 60116618Ssam curframe = &curframerec; 60216618Ssam *curframe = *frp; 60318231Slinton showaggrs = false; 60418231Slinton printcallinfo(curfunc, curframe); 60516618Ssam } else if (f == program) { 60616618Ssam done = true; 60716618Ssam error("not that many levels"); 60816618Ssam } else { 60916618Ssam frp = nextfunc(frp, &f); 61016618Ssam } 61116618Ssam ++i; 61216618Ssam } while (not done); 61316618Ssam } 61416618Ssam } 61516618Ssam 61616618Ssam public down (n) 61716618Ssam integer n; 61816618Ssam { 61916618Ssam integer i, depth; 62018231Slinton Frame frp, curfrp; 62116618Ssam Symbol f; 62216618Ssam struct Frame frame; 62316618Ssam 62416618Ssam if (not isactive(program)) { 62516618Ssam error("program is not active"); 62616618Ssam } else if (curfunc == nil) { 62716618Ssam error("no current function"); 62816618Ssam } else { 62916618Ssam depth = 0; 63016618Ssam frp = &frame; 63116618Ssam getcurfunc(frp, &f); 63216618Ssam if (curframe == nil) { 63318231Slinton curfrp = findframe(curfunc); 63416618Ssam curframe = &curframerec; 63518231Slinton *curframe = *curfrp; 63616618Ssam } 63716618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 63816618Ssam frp = nextfunc(frp, &f); 63916618Ssam ++depth; 64016618Ssam } 64116618Ssam if (f == nil or n > depth) { 64216618Ssam error("not that many levels"); 64316618Ssam } else { 64416618Ssam depth -= n; 64516618Ssam frp = &frame; 64616618Ssam getcurfunc(frp, &f); 64716618Ssam for (i = 0; i < depth; i++) { 64816618Ssam frp = nextfunc(frp, &f); 64916618Ssam assert(frp != nil); 65016618Ssam } 65116618Ssam curfunc = f; 65216618Ssam *curframe = *frp; 65318231Slinton showaggrs = false; 65418231Slinton printcallinfo(curfunc, curframe); 65516618Ssam } 65616618Ssam } 65716618Ssam } 65816618Ssam 65916618Ssam /* 6609678Slinton * Find the entry point of a procedure or function. 661*33334Sdonn * 662*33334Sdonn * On the VAX we add the size of the register mask (FUNCOFFSET) or 663*33334Sdonn * the size of the Modula-2 internal entry sequence, on other machines 664*33334Sdonn * (68000's) we add the entry sequence size (FUNCOFFSET) unless 665*33334Sdonn * we're right at the beginning of the program. 6669678Slinton */ 6679678Slinton 66818231Slinton public findbeginning (f) 6699678Slinton Symbol f; 6709678Slinton { 67116618Ssam if (isinternal(f)) { 672*33334Sdonn f->symvalue.funcv.beginaddr += 18; /* VAX only */ 67316618Ssam } else { 674*33334Sdonn f->symvalue.funcv.beginaddr += FUNCOFFSET; 67516618Ssam } 6769678Slinton } 6779678Slinton 6789678Slinton /* 6799678Slinton * Return the address corresponding to the first line in a function. 6809678Slinton */ 6819678Slinton 6829678Slinton public Address firstline(f) 6839678Slinton Symbol f; 6849678Slinton { 6859678Slinton Address addr; 6869678Slinton 6879678Slinton addr = codeloc(f); 6889678Slinton while (linelookup(addr) == 0 and addr < objsize) { 6899678Slinton ++addr; 6909678Slinton } 6919678Slinton if (addr == objsize) { 6929678Slinton addr = -1; 6939678Slinton } 6949678Slinton return addr; 6959678Slinton } 6969678Slinton 6979678Slinton /* 6989678Slinton * Catcher drops strike three ... 6999678Slinton */ 7009678Slinton 7019678Slinton public runtofirst() 7029678Slinton { 703*33334Sdonn Address addr, endaddr; 7049678Slinton 7059678Slinton addr = pc; 706*33334Sdonn endaddr = objsize + CODESTART; 707*33334Sdonn while (linelookup(addr) == 0 and addr < endaddr) { 7089678Slinton ++addr; 7099678Slinton } 710*33334Sdonn if (addr < endaddr) { 7119678Slinton stepto(addr); 7129678Slinton } 7139678Slinton } 7149678Slinton 7159678Slinton /* 7169678Slinton * Return the address corresponding to the end of the program. 7179678Slinton * 7189678Slinton * We look for the entry to "exit". 7199678Slinton */ 7209678Slinton 7219678Slinton public Address lastaddr() 7229678Slinton { 72318231Slinton Symbol s; 7249678Slinton 7259678Slinton s = lookup(identname("exit", true)); 7269678Slinton if (s == nil) { 7279678Slinton panic("can't find exit"); 7289678Slinton } 7299678Slinton return codeloc(s); 7309678Slinton } 7319678Slinton 7329678Slinton /* 7339678Slinton * Decide if the given function is currently active. 7349678Slinton * 7359678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 7369678Slinton * Presumably information evaluated while walking the stack is active. 7379678Slinton */ 7389678Slinton 739*33334Sdonn public Boolean isactive (f) 7409678Slinton Symbol f; 7419678Slinton { 74218231Slinton Boolean b; 7439678Slinton 7449678Slinton if (isfinished(process)) { 7459678Slinton b = false; 7469678Slinton } else { 747*33334Sdonn if (walkingstack or f == program or f == nil or 7489678Slinton (ismodule(f) and isactive(container(f)))) { 7499678Slinton b = true; 7509678Slinton } else { 7519678Slinton b = (Boolean) (findframe(f) != nil); 7529678Slinton } 7539678Slinton } 7549678Slinton return b; 7559678Slinton } 7569678Slinton 7579678Slinton /* 7589678Slinton * Evaluate a call to a procedure. 7599678Slinton */ 7609678Slinton 76118231Slinton public callproc(exprnode, isfunc) 76218231Slinton Node exprnode; 76318231Slinton boolean isfunc; 7649678Slinton { 76518231Slinton Node procnode, arglist; 7669678Slinton Symbol proc; 76718231Slinton integer argc; 7689678Slinton 76918231Slinton procnode = exprnode->value.arg[0]; 77018231Slinton arglist = exprnode->value.arg[1]; 7719678Slinton if (procnode->op != O_SYM) { 7729678Slinton beginerrmsg(); 7739678Slinton fprintf(stderr, "can't call \""); 7749678Slinton prtree(stderr, procnode); 7759678Slinton fprintf(stderr, "\""); 7769678Slinton enderrmsg(); 7779678Slinton } 7789678Slinton assert(procnode->op == O_SYM); 7799678Slinton proc = procnode->value.sym; 7809678Slinton if (not isblock(proc)) { 7819678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 7829678Slinton } 78318231Slinton endproc.isfunc = isfunc; 78418231Slinton endproc.callnode = exprnode; 78518231Slinton endproc.cmdnode = topnode; 7869678Slinton pushenv(); 7879678Slinton pc = codeloc(proc); 7889678Slinton argc = pushargs(proc, arglist); 789*33334Sdonn setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ 7909678Slinton beginproc(proc, argc); 79118231Slinton event_once( 79218231Slinton build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 79318231Slinton buildcmdlist(build(O_PROCRTN, proc)) 79418231Slinton ); 79518231Slinton isstopped = false; 79618231Slinton if (not bpact()) { 79718231Slinton isstopped = true; 79818231Slinton cont(0); 79918231Slinton } 80018231Slinton /* 80118231Slinton * bpact() won't return true, it will call printstatus() and go back 80218231Slinton * to command input if a breakpoint is found. 80318231Slinton */ 8049678Slinton /* NOTREACHED */ 8059678Slinton } 8069678Slinton 8079678Slinton /* 8089678Slinton * Push the arguments on the process' stack. We do this by first 8099678Slinton * evaluating them on the "eval" stack, then copying into the process' 8109678Slinton * space. 8119678Slinton */ 8129678Slinton 81318231Slinton private integer pushargs(proc, arglist) 8149678Slinton Symbol proc; 8159678Slinton Node arglist; 8169678Slinton { 8179678Slinton Stack *savesp; 8189678Slinton int argc, args_size; 8199678Slinton 8209678Slinton savesp = sp; 82126324Ssam if (varIsSet("$unsafecall")) { 82226324Ssam argc = unsafe_evalargs(proc, arglist); 82326324Ssam } else { 82426324Ssam argc = evalargs(proc, arglist); 82526324Ssam } 8269678Slinton args_size = sp - savesp; 8279678Slinton setreg(STKP, reg(STKP) - args_size); 8289678Slinton dwrite(savesp, reg(STKP), args_size); 8299678Slinton sp = savesp; 8309678Slinton return argc; 8319678Slinton } 8329678Slinton 8339678Slinton /* 83416618Ssam * Check to see if an expression is correct for a given parameter. 83516618Ssam * If the given parameter is false, don't worry about type inconsistencies. 83616618Ssam * 83716618Ssam * Return whether or not it is ok. 8389678Slinton */ 8399678Slinton 84016618Ssam private boolean chkparam (actual, formal, chk) 84116618Ssam Node actual; 84216618Ssam Symbol formal; 84316618Ssam boolean chk; 84416618Ssam { 84516618Ssam boolean b; 84616618Ssam 84716618Ssam b = true; 84816618Ssam if (chk) { 84916618Ssam if (formal == nil) { 85016618Ssam beginerrmsg(); 85116618Ssam fprintf(stderr, "too many parameters"); 85216618Ssam b = false; 85316618Ssam } else if (not compatible(formal->type, actual->nodetype)) { 85416618Ssam beginerrmsg(); 85516618Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 85616618Ssam b = false; 85716618Ssam } 85816618Ssam } 85918231Slinton if (b and formal != nil and 86018231Slinton isvarparam(formal) and not isopenarray(formal->type) and 86118231Slinton not ( 86218231Slinton actual->op == O_RVAL or actual->nodetype == t_addr or 86318231Slinton ( 86418231Slinton actual->op == O_TYPERENAME and 86518231Slinton ( 86618231Slinton actual->value.arg[0]->op == O_RVAL or 86718231Slinton actual->value.arg[0]->nodetype == t_addr 86818231Slinton ) 86918231Slinton ) 87018231Slinton ) 87118231Slinton ) { 87216618Ssam beginerrmsg(); 87316618Ssam fprintf(stderr, "expected variable, found \""); 87416618Ssam prtree(stderr, actual); 87516618Ssam fprintf(stderr, "\""); 87616618Ssam b = false; 87716618Ssam } 87816618Ssam return b; 87916618Ssam } 88016618Ssam 88116618Ssam /* 88216618Ssam * Pass an expression to a particular parameter. 88316618Ssam * 88416618Ssam * Normally we pass either the address or value, but in some cases 88516618Ssam * (such as C strings) we want to copy the value onto the stack and 88616618Ssam * pass its address. 88718231Slinton * 88818231Slinton * Another special case raised by strings is the possibility that 88918231Slinton * the actual parameter will be larger than the formal, even with 89018231Slinton * appropriate type-checking. This occurs because we assume during 89118231Slinton * evaluation that strings are null-terminated, whereas some languages, 89218231Slinton * notably Pascal, do not work under that assumption. 89316618Ssam */ 89416618Ssam 89516618Ssam private passparam (actual, formal) 89616618Ssam Node actual; 89716618Ssam Symbol formal; 89816618Ssam { 89916618Ssam boolean b; 90016618Ssam Address addr; 90116618Ssam Stack *savesp; 90218231Slinton integer actsize, formsize; 90316618Ssam 90418231Slinton if (formal != nil and isvarparam(formal) and 90518231Slinton (not isopenarray(formal->type)) 90618231Slinton ) { 90716618Ssam addr = lval(actual->value.arg[0]); 90816618Ssam push(Address, addr); 90916618Ssam } else if (passaddr(formal, actual->nodetype)) { 91016618Ssam savesp = sp; 91116618Ssam eval(actual); 91218231Slinton actsize = sp - savesp; 91318231Slinton setreg(STKP, 91418231Slinton reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) 91518231Slinton ); 91618231Slinton dwrite(savesp, reg(STKP), actsize); 91716618Ssam sp = savesp; 91816618Ssam push(Address, reg(STKP)); 91916618Ssam if (formal != nil and isopenarray(formal->type)) { 92018231Slinton push(integer, actsize div size(formal->type->type)); 92116618Ssam } 92218231Slinton } else if (formal != nil) { 92318231Slinton formsize = size(formal); 92418231Slinton savesp = sp; 92518231Slinton eval(actual); 92618231Slinton actsize = sp - savesp; 92718231Slinton if (actsize > formsize) { 92818231Slinton sp -= (actsize - formsize); 92918231Slinton } 93016618Ssam } else { 93116618Ssam eval(actual); 93216618Ssam } 93316618Ssam } 93416618Ssam 93516618Ssam /* 93616618Ssam * Evaluate an argument list left-to-right. 93716618Ssam */ 93816618Ssam 93918231Slinton private integer evalargs(proc, arglist) 9409678Slinton Symbol proc; 9419678Slinton Node arglist; 9429678Slinton { 94316618Ssam Node p, actual; 94416618Ssam Symbol formal; 9459678Slinton Stack *savesp; 94618231Slinton integer count; 94716618Ssam boolean chk; 9489678Slinton 9499678Slinton savesp = sp; 9509678Slinton count = 0; 95116618Ssam formal = proc->chain; 95216618Ssam chk = (boolean) (not nosource(proc)); 9539678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 95416618Ssam assert(p->op == O_COMMA); 95516618Ssam actual = p->value.arg[0]; 95616618Ssam if (not chkparam(actual, formal, chk)) { 95716618Ssam fprintf(stderr, " in call to %s", symname(proc)); 9589678Slinton sp = savesp; 95916618Ssam enderrmsg(); 9609678Slinton } 96116618Ssam passparam(actual, formal); 96216618Ssam if (formal != nil) { 96316618Ssam formal = formal->chain; 9649678Slinton } 9659678Slinton ++count; 9669678Slinton } 96716618Ssam if (chk) { 96816618Ssam if (formal != nil) { 96916618Ssam sp = savesp; 97016618Ssam error("not enough parameters to %s", symname(proc)); 97116618Ssam } 9729678Slinton } 9739678Slinton return count; 9749678Slinton } 9759678Slinton 97626324Ssam /* 977*33334Sdonn * Evaluate an argument list without any type checking. 978*33334Sdonn * This is only useful for procedures with a varying number of 979*33334Sdonn * arguments that are compiled -g. 98026324Ssam */ 98126324Ssam 982*33334Sdonn private integer unsafe_evalargs (proc, arglist) 98326324Ssam Symbol proc; 98426324Ssam Node arglist; 98526324Ssam { 98626324Ssam Node p; 987*33334Sdonn integer count; 98826324Ssam 98926324Ssam count = 0; 99026324Ssam for (p = arglist; p != nil; p = p->value.arg[1]) { 99126324Ssam assert(p->op == O_COMMA); 99226324Ssam eval(p->value.arg[0]); 99326324Ssam ++count; 99426324Ssam } 99526324Ssam return count; 99626324Ssam } 99726324Ssam 9989678Slinton public procreturn(f) 9999678Slinton Symbol f; 10009678Slinton { 100118231Slinton integer retvalsize; 100218231Slinton Node tmp; 100318231Slinton char *copy; 100418231Slinton 10059678Slinton flushoutput(); 10069678Slinton popenv(); 100718231Slinton if (endproc.isfunc) { 100818231Slinton retvalsize = size(f->type); 100918231Slinton if (retvalsize > sizeof(long)) { 101018231Slinton pushretval(retvalsize, true); 101118231Slinton copy = newarr(char, retvalsize); 101218231Slinton popn(retvalsize, copy); 101318231Slinton tmp = build(O_SCON, copy); 101418231Slinton } else { 101518231Slinton tmp = build(O_LCON, (long) (reg(0))); 101618231Slinton } 101718231Slinton tmp->nodetype = f->type; 101818231Slinton tfree(endproc.callnode); 101918231Slinton *(endproc.callnode) = *(tmp); 102018231Slinton dispose(tmp); 102118231Slinton eval(endproc.cmdnode); 102218231Slinton } else { 102318231Slinton putchar('\n'); 102418231Slinton printname(stdout, f); 1025*33334Sdonn printf(" returns successfully\n"); 102618231Slinton } 10279678Slinton erecover(); 10289678Slinton } 10299678Slinton 10309678Slinton /* 10319678Slinton * Push the current environment. 10329678Slinton */ 10339678Slinton 10349678Slinton private pushenv() 10359678Slinton { 10369678Slinton push(Address, pc); 10379678Slinton push(Lineno, curline); 10389678Slinton push(String, cursource); 10399678Slinton push(Boolean, isstopped); 10409678Slinton push(Symbol, curfunc); 104116618Ssam push(Frame, curframe); 104216618Ssam push(struct Frame, curframerec); 104318231Slinton push(CallEnv, endproc); 10449678Slinton push(Word, reg(PROGCTR)); 10459678Slinton push(Word, reg(STKP)); 1046*33334Sdonn push(Word, reg(FRP)); 10479678Slinton } 10489678Slinton 10499678Slinton /* 10509678Slinton * Pop back to the real world. 10519678Slinton */ 10529678Slinton 10539678Slinton public popenv() 10549678Slinton { 105518231Slinton String filename; 10569678Slinton 1057*33334Sdonn setreg(FRP, pop(Word)); 10589678Slinton setreg(STKP, pop(Word)); 10599678Slinton setreg(PROGCTR, pop(Word)); 106018231Slinton endproc = pop(CallEnv); 106116618Ssam curframerec = pop(struct Frame); 106216618Ssam curframe = pop(Frame); 10639678Slinton curfunc = pop(Symbol); 10649678Slinton isstopped = pop(Boolean); 10659678Slinton filename = pop(String); 10669678Slinton curline = pop(Lineno); 10679678Slinton pc = pop(Address); 10689678Slinton setsource(filename); 10699678Slinton } 10709678Slinton 10719678Slinton /* 10729678Slinton * Flush the debuggee's standard output. 10739678Slinton * 10749678Slinton * This is VERY dependent on the use of stdio. 10759678Slinton */ 10769678Slinton 10779678Slinton public flushoutput() 10789678Slinton { 107918231Slinton Symbol p, iob; 108018231Slinton Stack *savesp; 10819678Slinton 10829678Slinton p = lookup(identname("fflush", true)); 10839678Slinton while (p != nil and not isblock(p)) { 10849678Slinton p = p->next_sym; 10859678Slinton } 10869678Slinton if (p != nil) { 10879678Slinton iob = lookup(identname("_iob", true)); 10889678Slinton if (iob != nil) { 10899678Slinton pushenv(); 1090*33334Sdonn pc = codeloc(p) - FUNCOFFSET; 10919678Slinton savesp = sp; 1092*33334Sdonn push(long, address(iob, nil) + sizeof(*stdout)); 10939678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 10949678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 10959678Slinton sp = savesp; 10969678Slinton beginproc(p, 1); 10979678Slinton stepto(return_addr()); 10989678Slinton popenv(); 10999678Slinton } 11009678Slinton } 11019678Slinton } 1102