1*21621Sdist /* 2*21621Sdist * Copyright (c) 1983 Regents of the University of California. 3*21621Sdist * All rights reserved. The Berkeley software License Agreement 4*21621Sdist * specifies the terms and conditions for redistribution. 5*21621Sdist */ 69678Slinton 7*21621Sdist #ifndef lint 8*21621Sdist static char sccsid[] = "@(#)runtime.c 5.1 (Berkeley) 05/31/85"; 9*21621Sdist #endif not lint 109678Slinton 1118231Slinton static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton 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> 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 5418231Slinton #define isstackaddr(addr) \ 5518231Slinton (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * 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; 11812546Scsvaf 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: 14713937Slinton dread(&frame, prev_frame, sizeof(struct Frame)); 14813937Slinton if (ntramp == 1) { 14914620Ssam dread(&callpc, prev_frame + 84, sizeof(callpc)); 15013937Slinton } else { 15113937Slinton callpc = frame.save_pc; 15213937Slinton } 15318231Slinton if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 1549678Slinton newfrp = nil; 15518231Slinton } else if (isstackaddr(callpc)) { 15618231Slinton ntramp++; 15718231Slinton prev_frame = frame.save_fp; 15818231Slinton goto nextf; 15913937Slinton } else { 16012546Scsvaf frame.save_pc = callpc; 16113937Slinton ntramp = 0; 1629678Slinton mask = ((frame.mask >> 16) & 0x0fff); 16318231Slinton getsaveregs(newfrp, &frame, mask); 1649678Slinton newfrp->condition_handler = frame.condition_handler; 1659678Slinton newfrp->mask = mask; 1669678Slinton newfrp->save_ap = frame.save_ap; 1679678Slinton newfrp->save_fp = frame.save_fp; 1689678Slinton newfrp->save_pc = frame.save_pc; 1699678Slinton } 1709678Slinton return newfrp; 1719678Slinton } 1729678Slinton 1739678Slinton /* 17416618Ssam * Get the current frame information in the given Frame and store the 17516618Ssam * associated function in the given value-result parameter. 17616618Ssam */ 17716618Ssam 17816618Ssam private getcurfunc (frp, fp) 17916618Ssam Frame frp; 18016618Ssam Symbol *fp; 18116618Ssam { 18216618Ssam getcurframe(frp); 18316618Ssam *fp = whatblock(frp->save_pc); 18416618Ssam } 18516618Ssam 18616618Ssam /* 18716618Ssam * Return the frame associated with the next function up the call stack, or 18816618Ssam * nil if there is none. The function is returned in a value-result parameter. 18916618Ssam * For "inline" functions the statically outer function and same frame 19016618Ssam * are returned. 19116618Ssam */ 19216618Ssam 19318231Slinton public Frame nextfunc (frp, fp) 19416618Ssam Frame frp; 19516618Ssam Symbol *fp; 19616618Ssam { 19716618Ssam Symbol t; 19816618Ssam Frame nfrp; 19916618Ssam 20016618Ssam t = *fp; 20116618Ssam checkref(t); 20216618Ssam if (isinline(t)) { 20316618Ssam t = container(t); 20416618Ssam nfrp = frp; 20516618Ssam } else { 20616618Ssam nfrp = nextframe(frp); 20716618Ssam if (nfrp == nil) { 20816618Ssam t = nil; 20916618Ssam } else { 21016618Ssam t = whatblock(nfrp->save_pc); 21116618Ssam } 21216618Ssam } 21316618Ssam *fp = t; 21416618Ssam return nfrp; 21516618Ssam } 21616618Ssam 21716618Ssam /* 2189678Slinton * Return the frame associated with the given function. 2199678Slinton * If the function is nil, return the most recently activated frame. 2209678Slinton * 2219678Slinton * Static allocation for the frame. 2229678Slinton */ 2239678Slinton 2249678Slinton public Frame findframe(f) 2259678Slinton Symbol f; 2269678Slinton { 22718231Slinton Frame frp; 2289678Slinton static struct Frame frame; 22911866Slinton Symbol p; 23018231Slinton Boolean done; 2319678Slinton 2329678Slinton frp = &frame; 2339678Slinton getcurframe(frp); 23418231Slinton if (f != nil) { 23518231Slinton if (f == curfunc and curframe != nil) { 23618231Slinton *frp = *curframe; 23718231Slinton } else { 23818231Slinton done = false; 23918231Slinton p = whatblock(frp->save_pc); 24018231Slinton do { 24118231Slinton if (p == f) { 24218231Slinton done = true; 24318231Slinton } else if (p == program) { 24418231Slinton done = true; 24518231Slinton frp = nil; 24618231Slinton } else { 24718231Slinton frp = nextfunc(frp, &p); 24818231Slinton if (frp == nil) { 24918231Slinton done = true; 25018231Slinton } 25118231Slinton } 25218231Slinton } while (not done); 25315784Ssam } 25418231Slinton } 25518231Slinton return frp; 25618231Slinton } 25718231Slinton 25818231Slinton /* 25918231Slinton * Set the registers according to the given frame pointer. 26018231Slinton */ 26118231Slinton 26218231Slinton public getnewregs (addr) 26318231Slinton Address addr; 26418231Slinton { 26518231Slinton struct Frame frame; 26618231Slinton integer i, j, mask; 26718231Slinton 26818231Slinton dread(&frame, addr, sizeof(frame)); 26918231Slinton setreg(ARGP, frame.save_ap); 27018231Slinton setreg(FRP, frame.save_fp); 27118231Slinton setreg(PROGCTR, frame.save_pc); 27218231Slinton mask = ((frame.mask >> 16) & 0x0fff); 27318231Slinton j = 0; 27418231Slinton for (i = 0; i < NSAVEREG; i++) { 27518231Slinton if (bis(mask, i)) { 27618231Slinton setreg(i, frame.save_reg[j]); 27718231Slinton ++j; 27816636Ssam } 2799678Slinton } 28018231Slinton pc = frame.save_pc; 28118231Slinton setcurfunc(whatblock(pc)); 2829678Slinton } 2839678Slinton 2849678Slinton /* 2859678Slinton * Find the return address of the current procedure/function. 2869678Slinton */ 2879678Slinton 2889678Slinton public Address return_addr() 2899678Slinton { 2909678Slinton Frame frp; 2919678Slinton Address addr; 2929678Slinton struct Frame frame; 2939678Slinton 2949678Slinton frp = &frame; 2959678Slinton getcurframe(frp); 2969678Slinton frp = nextframe(frp); 2979678Slinton if (frp == nil) { 2989678Slinton addr = 0; 2999678Slinton } else { 3009678Slinton addr = frp->save_pc; 3019678Slinton } 3029678Slinton return addr; 3039678Slinton } 3049678Slinton 3059678Slinton /* 3069678Slinton * Push the value associated with the current function. 3079678Slinton */ 3089678Slinton 3099678Slinton public pushretval(len, isindirect) 31018231Slinton integer len; 31118231Slinton boolean isindirect; 3129678Slinton { 3139678Slinton Word r0; 3149678Slinton 3159678Slinton r0 = reg(0); 3169678Slinton if (isindirect) { 3179678Slinton rpush((Address) r0, len); 3189678Slinton } else { 3199678Slinton switch (len) { 3209678Slinton case sizeof(char): 3219678Slinton push(char, r0); 3229678Slinton break; 3239678Slinton 3249678Slinton case sizeof(short): 3259678Slinton push(short, r0); 3269678Slinton break; 3279678Slinton 3289678Slinton default: 3299678Slinton if (len == sizeof(Word)) { 3309678Slinton push(Word, r0); 3319678Slinton } else if (len == 2*sizeof(Word)) { 3329678Slinton push(Word, r0); 3339678Slinton push(Word, reg(1)); 3349678Slinton } else { 33518231Slinton error("[internal error: bad size %d in pushretval]", len); 3369678Slinton } 3379678Slinton break; 3389678Slinton } 3399678Slinton } 3409678Slinton } 3419678Slinton 3429678Slinton /* 3439678Slinton * Return the base address for locals in the given frame. 3449678Slinton */ 3459678Slinton 3469678Slinton public Address locals_base(frp) 34718231Slinton Frame frp; 3489678Slinton { 3499678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 3509678Slinton } 3519678Slinton 3529678Slinton /* 3539678Slinton * Return the base address for arguments in the given frame. 3549678Slinton */ 3559678Slinton 3569678Slinton public Address args_base(frp) 35718231Slinton Frame frp; 3589678Slinton { 3599678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 3609678Slinton } 3619678Slinton 3629678Slinton /* 3639678Slinton * Return saved register n from the given frame. 3649678Slinton */ 3659678Slinton 3669678Slinton public Word savereg(n, frp) 36718231Slinton integer n; 36818231Slinton Frame frp; 3699678Slinton { 37018231Slinton Word w; 3719678Slinton 3729678Slinton if (frp == nil) { 3739678Slinton w = reg(n); 3749678Slinton } else { 3759678Slinton switch (n) { 3769678Slinton case ARGP: 3779678Slinton w = frp->save_ap; 3789678Slinton break; 3799678Slinton 3809678Slinton case FRP: 3819678Slinton w = frp->save_fp; 3829678Slinton break; 3839678Slinton 3849678Slinton case STKP: 3859678Slinton w = reg(STKP); 3869678Slinton break; 3879678Slinton 3889678Slinton case PROGCTR: 3899678Slinton w = frp->save_pc; 3909678Slinton break; 3919678Slinton 3929678Slinton default: 3939678Slinton assert(n >= 0 and n < NSAVEREG); 3949678Slinton w = frp->save_reg[n]; 3959678Slinton break; 3969678Slinton } 3979678Slinton } 3989678Slinton return w; 3999678Slinton } 4009678Slinton 4019678Slinton /* 4029678Slinton * Return the nth argument to the current procedure. 4039678Slinton */ 4049678Slinton 4059678Slinton public Word argn(n, frp) 40618231Slinton integer n; 4079678Slinton Frame frp; 4089678Slinton { 4099678Slinton Word w; 4109678Slinton 4119678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 4129678Slinton return w; 4139678Slinton } 4149678Slinton 4159678Slinton /* 41618231Slinton * Print a list of currently active blocks starting with most recent. 4179678Slinton */ 4189678Slinton 41918231Slinton public wherecmd() 4209678Slinton { 42118231Slinton walkstack(false); 4229678Slinton } 4239678Slinton 4249678Slinton /* 42518231Slinton * Print the variables in the given frame or the current one if nil. 4269678Slinton */ 4279678Slinton 42818231Slinton public dump (func) 42918231Slinton Symbol func; 4309678Slinton { 43118231Slinton Symbol f; 43218231Slinton Frame frp; 43318231Slinton 43418231Slinton if (func == nil) { 43518231Slinton f = curfunc; 43618231Slinton if (curframe != nil) { 43718231Slinton frp = curframe; 43818231Slinton } else { 43918231Slinton frp = findframe(f); 44018231Slinton } 44118231Slinton } else { 44218231Slinton f = func; 44318231Slinton frp = findframe(f); 44418231Slinton } 44518231Slinton showaggrs = true; 44618231Slinton printcallinfo(f, frp); 44718231Slinton dumpvars(f, frp); 4489678Slinton } 4499678Slinton 4509678Slinton /* 45118231Slinton * Dump all values. 4529678Slinton */ 4539678Slinton 45418231Slinton public dumpall () 4559678Slinton { 4569678Slinton walkstack(true); 4579678Slinton } 4589678Slinton 4599678Slinton /* 4609678Slinton * Walk the stack of active procedures printing information 4619678Slinton * about each active procedure. 4629678Slinton */ 4639678Slinton 4649678Slinton private walkstack(dumpvariables) 4659678Slinton Boolean dumpvariables; 4669678Slinton { 46718231Slinton Frame frp; 46818231Slinton boolean save; 46916618Ssam Symbol f; 4709678Slinton struct Frame frame; 4719678Slinton 47218231Slinton if (notstarted(process) or isfinished(process)) { 4739678Slinton error("program is not active"); 4749678Slinton } else { 4759678Slinton save = walkingstack; 4769678Slinton walkingstack = true; 47718231Slinton showaggrs = dumpvariables; 4789678Slinton frp = &frame; 47916618Ssam getcurfunc(frp, &f); 48018231Slinton for (;;) { 48118231Slinton printcallinfo(f, frp); 4829678Slinton if (dumpvariables) { 4839678Slinton dumpvars(f, frp); 4849678Slinton putchar('\n'); 4859678Slinton } 48616618Ssam frp = nextfunc(frp, &f); 48718231Slinton if (frp == nil or f == program) { 48818231Slinton break; 48918231Slinton } 49018231Slinton } 4919678Slinton if (dumpvariables) { 4929678Slinton printf("in \"%s\":\n", symname(program)); 4939678Slinton dumpvars(program, nil); 4949678Slinton putchar('\n'); 4959678Slinton } 4969678Slinton walkingstack = save; 4979678Slinton } 4989678Slinton } 4999678Slinton 5009678Slinton /* 50118231Slinton * Print out the information about a call, i.e., 50218231Slinton * routine name, parameter values, and source location. 50318231Slinton */ 50418231Slinton 50518231Slinton private printcallinfo (f, frp) 50618231Slinton Symbol f; 50718231Slinton Frame frp; 50818231Slinton { 50918231Slinton Lineno line; 51018231Slinton Address savepc; 51118231Slinton 51218231Slinton savepc = frp->save_pc; 51318231Slinton if (frp->save_fp != reg(FRP)) { 51418231Slinton savepc -= 1; 51518231Slinton } 51618231Slinton printname(stdout, f); 51718231Slinton if (not isinline(f)) { 51818231Slinton printparams(f, frp); 51918231Slinton } 52018231Slinton line = srcline(savepc); 52118231Slinton if (line != 0) { 52218231Slinton printf(", line %d", line); 52318231Slinton printf(" in \"%s\"\n", srcfilename(savepc)); 52418231Slinton } else { 52518231Slinton printf(" at 0x%x\n", savepc); 52618231Slinton } 52718231Slinton } 52818231Slinton 52918231Slinton /* 53016618Ssam * Set the current function to the given symbol. 53116618Ssam * We must adjust "curframe" so that subsequent operations are 53216618Ssam * not confused; for simplicity we simply clear it. 53316618Ssam */ 53416618Ssam 53516618Ssam public setcurfunc (f) 53616618Ssam Symbol f; 53716618Ssam { 53816618Ssam curfunc = f; 53916618Ssam curframe = nil; 54016618Ssam } 54116618Ssam 54216618Ssam /* 54318231Slinton * Return the frame for the current function. 54418231Slinton * The space for the frame is allocated statically. 54518231Slinton */ 54618231Slinton 54718231Slinton public Frame curfuncframe () 54818231Slinton { 54918231Slinton static struct Frame frame; 55018231Slinton Frame frp; 55118231Slinton 55218231Slinton if (curframe == nil) { 55318231Slinton frp = findframe(curfunc); 55418231Slinton curframe = &curframerec; 55518231Slinton *curframe = *frp; 55618231Slinton } else { 55718231Slinton frp = &frame; 55818231Slinton *frp = *curframe; 55918231Slinton } 56018231Slinton return frp; 56118231Slinton } 56218231Slinton 56318231Slinton /* 56416618Ssam * Set curfunc to be N up/down the stack from its current value. 56516618Ssam */ 56616618Ssam 56716618Ssam public up (n) 56816618Ssam integer n; 56916618Ssam { 57016618Ssam integer i; 57116618Ssam Symbol f; 57216618Ssam Frame frp; 57316618Ssam boolean done; 57416618Ssam 57516618Ssam if (not isactive(program)) { 57616618Ssam error("program is not active"); 57716618Ssam } else if (curfunc == nil) { 57816618Ssam error("no current function"); 57916618Ssam } else { 58016618Ssam i = 0; 58116618Ssam f = curfunc; 58218231Slinton frp = curfuncframe(); 58316618Ssam done = false; 58416618Ssam do { 58516618Ssam if (frp == nil) { 58616618Ssam done = true; 58716618Ssam error("not that many levels"); 58816618Ssam } else if (i >= n) { 58916618Ssam done = true; 59016618Ssam curfunc = f; 59116618Ssam curframe = &curframerec; 59216618Ssam *curframe = *frp; 59318231Slinton showaggrs = false; 59418231Slinton printcallinfo(curfunc, curframe); 59516618Ssam } else if (f == program) { 59616618Ssam done = true; 59716618Ssam error("not that many levels"); 59816618Ssam } else { 59916618Ssam frp = nextfunc(frp, &f); 60016618Ssam } 60116618Ssam ++i; 60216618Ssam } while (not done); 60316618Ssam } 60416618Ssam } 60516618Ssam 60616618Ssam public down (n) 60716618Ssam integer n; 60816618Ssam { 60916618Ssam integer i, depth; 61018231Slinton Frame frp, curfrp; 61116618Ssam Symbol f; 61216618Ssam struct Frame frame; 61316618Ssam 61416618Ssam if (not isactive(program)) { 61516618Ssam error("program is not active"); 61616618Ssam } else if (curfunc == nil) { 61716618Ssam error("no current function"); 61816618Ssam } else { 61916618Ssam depth = 0; 62016618Ssam frp = &frame; 62116618Ssam getcurfunc(frp, &f); 62216618Ssam if (curframe == nil) { 62318231Slinton curfrp = findframe(curfunc); 62416618Ssam curframe = &curframerec; 62518231Slinton *curframe = *curfrp; 62616618Ssam } 62716618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 62816618Ssam frp = nextfunc(frp, &f); 62916618Ssam ++depth; 63016618Ssam } 63116618Ssam if (f == nil or n > depth) { 63216618Ssam error("not that many levels"); 63316618Ssam } else { 63416618Ssam depth -= n; 63516618Ssam frp = &frame; 63616618Ssam getcurfunc(frp, &f); 63716618Ssam for (i = 0; i < depth; i++) { 63816618Ssam frp = nextfunc(frp, &f); 63916618Ssam assert(frp != nil); 64016618Ssam } 64116618Ssam curfunc = f; 64216618Ssam *curframe = *frp; 64318231Slinton showaggrs = false; 64418231Slinton printcallinfo(curfunc, curframe); 64516618Ssam } 64616618Ssam } 64716618Ssam } 64816618Ssam 64916618Ssam /* 6509678Slinton * Find the entry point of a procedure or function. 6519678Slinton */ 6529678Slinton 65318231Slinton public findbeginning (f) 6549678Slinton Symbol f; 6559678Slinton { 65616618Ssam if (isinternal(f)) { 65716618Ssam f->symvalue.funcv.beginaddr += 15; 65816618Ssam } else { 65916618Ssam f->symvalue.funcv.beginaddr += 2; 66016618Ssam } 6619678Slinton } 6629678Slinton 6639678Slinton /* 6649678Slinton * Return the address corresponding to the first line in a function. 6659678Slinton */ 6669678Slinton 6679678Slinton public Address firstline(f) 6689678Slinton Symbol f; 6699678Slinton { 6709678Slinton Address addr; 6719678Slinton 6729678Slinton addr = codeloc(f); 6739678Slinton while (linelookup(addr) == 0 and addr < objsize) { 6749678Slinton ++addr; 6759678Slinton } 6769678Slinton if (addr == objsize) { 6779678Slinton addr = -1; 6789678Slinton } 6799678Slinton return addr; 6809678Slinton } 6819678Slinton 6829678Slinton /* 6839678Slinton * Catcher drops strike three ... 6849678Slinton */ 6859678Slinton 6869678Slinton public runtofirst() 6879678Slinton { 6889678Slinton Address addr; 6899678Slinton 6909678Slinton addr = pc; 6919678Slinton while (linelookup(addr) == 0 and addr < objsize) { 6929678Slinton ++addr; 6939678Slinton } 6949678Slinton if (addr < objsize) { 6959678Slinton stepto(addr); 6969678Slinton } 6979678Slinton } 6989678Slinton 6999678Slinton /* 7009678Slinton * Return the address corresponding to the end of the program. 7019678Slinton * 7029678Slinton * We look for the entry to "exit". 7039678Slinton */ 7049678Slinton 7059678Slinton public Address lastaddr() 7069678Slinton { 70718231Slinton Symbol s; 7089678Slinton 7099678Slinton s = lookup(identname("exit", true)); 7109678Slinton if (s == nil) { 7119678Slinton panic("can't find exit"); 7129678Slinton } 7139678Slinton return codeloc(s); 7149678Slinton } 7159678Slinton 7169678Slinton /* 7179678Slinton * Decide if the given function is currently active. 7189678Slinton * 7199678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 7209678Slinton * Presumably information evaluated while walking the stack is active. 7219678Slinton */ 7229678Slinton 7239678Slinton public Boolean isactive(f) 7249678Slinton Symbol f; 7259678Slinton { 72618231Slinton Boolean b; 7279678Slinton 7289678Slinton if (isfinished(process)) { 7299678Slinton b = false; 7309678Slinton } else { 7319678Slinton if (walkingstack or f == program or 7329678Slinton (ismodule(f) and isactive(container(f)))) { 7339678Slinton b = true; 7349678Slinton } else { 7359678Slinton b = (Boolean) (findframe(f) != nil); 7369678Slinton } 7379678Slinton } 7389678Slinton return b; 7399678Slinton } 7409678Slinton 7419678Slinton /* 7429678Slinton * Evaluate a call to a procedure. 7439678Slinton */ 7449678Slinton 74518231Slinton public callproc(exprnode, isfunc) 74618231Slinton Node exprnode; 74718231Slinton boolean isfunc; 7489678Slinton { 74918231Slinton Node procnode, arglist; 7509678Slinton Symbol proc; 75118231Slinton integer argc; 7529678Slinton 75318231Slinton procnode = exprnode->value.arg[0]; 75418231Slinton arglist = exprnode->value.arg[1]; 7559678Slinton if (procnode->op != O_SYM) { 7569678Slinton beginerrmsg(); 7579678Slinton fprintf(stderr, "can't call \""); 7589678Slinton prtree(stderr, procnode); 7599678Slinton fprintf(stderr, "\""); 7609678Slinton enderrmsg(); 7619678Slinton } 7629678Slinton assert(procnode->op == O_SYM); 7639678Slinton proc = procnode->value.sym; 7649678Slinton if (not isblock(proc)) { 7659678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 7669678Slinton } 76718231Slinton endproc.isfunc = isfunc; 76818231Slinton endproc.callnode = exprnode; 76918231Slinton endproc.cmdnode = topnode; 7709678Slinton pushenv(); 7719678Slinton pc = codeloc(proc); 7729678Slinton argc = pushargs(proc, arglist); 7739678Slinton beginproc(proc, argc); 77418231Slinton event_once( 77518231Slinton build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 77618231Slinton buildcmdlist(build(O_PROCRTN, proc)) 77718231Slinton ); 77818231Slinton isstopped = false; 77918231Slinton if (not bpact()) { 78018231Slinton isstopped = true; 78118231Slinton cont(0); 78218231Slinton } 78318231Slinton /* 78418231Slinton * bpact() won't return true, it will call printstatus() and go back 78518231Slinton * to command input if a breakpoint is found. 78618231Slinton */ 7879678Slinton /* NOTREACHED */ 7889678Slinton } 7899678Slinton 7909678Slinton /* 7919678Slinton * Push the arguments on the process' stack. We do this by first 7929678Slinton * evaluating them on the "eval" stack, then copying into the process' 7939678Slinton * space. 7949678Slinton */ 7959678Slinton 79618231Slinton private integer pushargs(proc, arglist) 7979678Slinton Symbol proc; 7989678Slinton Node arglist; 7999678Slinton { 8009678Slinton Stack *savesp; 8019678Slinton int argc, args_size; 8029678Slinton 8039678Slinton savesp = sp; 8049678Slinton argc = evalargs(proc, arglist); 8059678Slinton args_size = sp - savesp; 8069678Slinton setreg(STKP, reg(STKP) - args_size); 8079678Slinton dwrite(savesp, reg(STKP), args_size); 8089678Slinton sp = savesp; 8099678Slinton return argc; 8109678Slinton } 8119678Slinton 8129678Slinton /* 81316618Ssam * Check to see if an expression is correct for a given parameter. 81416618Ssam * If the given parameter is false, don't worry about type inconsistencies. 81516618Ssam * 81616618Ssam * Return whether or not it is ok. 8179678Slinton */ 8189678Slinton 81916618Ssam private boolean chkparam (actual, formal, chk) 82016618Ssam Node actual; 82116618Ssam Symbol formal; 82216618Ssam boolean chk; 82316618Ssam { 82416618Ssam boolean b; 82516618Ssam 82616618Ssam b = true; 82716618Ssam if (chk) { 82816618Ssam if (formal == nil) { 82916618Ssam beginerrmsg(); 83016618Ssam fprintf(stderr, "too many parameters"); 83116618Ssam b = false; 83216618Ssam } else if (not compatible(formal->type, actual->nodetype)) { 83316618Ssam beginerrmsg(); 83416618Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 83516618Ssam b = false; 83616618Ssam } 83716618Ssam } 83818231Slinton if (b and formal != nil and 83918231Slinton isvarparam(formal) and not isopenarray(formal->type) and 84018231Slinton not ( 84118231Slinton actual->op == O_RVAL or actual->nodetype == t_addr or 84218231Slinton ( 84318231Slinton actual->op == O_TYPERENAME and 84418231Slinton ( 84518231Slinton actual->value.arg[0]->op == O_RVAL or 84618231Slinton actual->value.arg[0]->nodetype == t_addr 84718231Slinton ) 84818231Slinton ) 84918231Slinton ) 85018231Slinton ) { 85116618Ssam beginerrmsg(); 85216618Ssam fprintf(stderr, "expected variable, found \""); 85316618Ssam prtree(stderr, actual); 85416618Ssam fprintf(stderr, "\""); 85516618Ssam b = false; 85616618Ssam } 85716618Ssam return b; 85816618Ssam } 85916618Ssam 86016618Ssam /* 86116618Ssam * Pass an expression to a particular parameter. 86216618Ssam * 86316618Ssam * Normally we pass either the address or value, but in some cases 86416618Ssam * (such as C strings) we want to copy the value onto the stack and 86516618Ssam * pass its address. 86618231Slinton * 86718231Slinton * Another special case raised by strings is the possibility that 86818231Slinton * the actual parameter will be larger than the formal, even with 86918231Slinton * appropriate type-checking. This occurs because we assume during 87018231Slinton * evaluation that strings are null-terminated, whereas some languages, 87118231Slinton * notably Pascal, do not work under that assumption. 87216618Ssam */ 87316618Ssam 87416618Ssam private passparam (actual, formal) 87516618Ssam Node actual; 87616618Ssam Symbol formal; 87716618Ssam { 87816618Ssam boolean b; 87916618Ssam Address addr; 88016618Ssam Stack *savesp; 88118231Slinton integer actsize, formsize; 88216618Ssam 88318231Slinton if (formal != nil and isvarparam(formal) and 88418231Slinton (not isopenarray(formal->type)) 88518231Slinton ) { 88616618Ssam addr = lval(actual->value.arg[0]); 88716618Ssam push(Address, addr); 88816618Ssam } else if (passaddr(formal, actual->nodetype)) { 88916618Ssam savesp = sp; 89016618Ssam eval(actual); 89118231Slinton actsize = sp - savesp; 89218231Slinton setreg(STKP, 89318231Slinton reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) 89418231Slinton ); 89518231Slinton dwrite(savesp, reg(STKP), actsize); 89616618Ssam sp = savesp; 89716618Ssam push(Address, reg(STKP)); 89816618Ssam if (formal != nil and isopenarray(formal->type)) { 89918231Slinton push(integer, actsize div size(formal->type->type)); 90016618Ssam } 90118231Slinton } else if (formal != nil) { 90218231Slinton formsize = size(formal); 90318231Slinton savesp = sp; 90418231Slinton eval(actual); 90518231Slinton actsize = sp - savesp; 90618231Slinton if (actsize > formsize) { 90718231Slinton sp -= (actsize - formsize); 90818231Slinton } 90916618Ssam } else { 91016618Ssam eval(actual); 91116618Ssam } 91216618Ssam } 91316618Ssam 91416618Ssam /* 91516618Ssam * Evaluate an argument list left-to-right. 91616618Ssam */ 91716618Ssam 91818231Slinton private integer evalargs(proc, arglist) 9199678Slinton Symbol proc; 9209678Slinton Node arglist; 9219678Slinton { 92216618Ssam Node p, actual; 92316618Ssam Symbol formal; 9249678Slinton Stack *savesp; 92518231Slinton integer count; 92616618Ssam boolean chk; 9279678Slinton 9289678Slinton savesp = sp; 9299678Slinton count = 0; 93016618Ssam formal = proc->chain; 93116618Ssam chk = (boolean) (not nosource(proc)); 9329678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 93316618Ssam assert(p->op == O_COMMA); 93416618Ssam actual = p->value.arg[0]; 93516618Ssam if (not chkparam(actual, formal, chk)) { 93616618Ssam fprintf(stderr, " in call to %s", symname(proc)); 9379678Slinton sp = savesp; 93816618Ssam enderrmsg(); 9399678Slinton } 94016618Ssam passparam(actual, formal); 94116618Ssam if (formal != nil) { 94216618Ssam formal = formal->chain; 9439678Slinton } 9449678Slinton ++count; 9459678Slinton } 94616618Ssam if (chk) { 94716618Ssam if (formal != nil) { 94816618Ssam sp = savesp; 94916618Ssam error("not enough parameters to %s", symname(proc)); 95016618Ssam } 9519678Slinton } 9529678Slinton return count; 9539678Slinton } 9549678Slinton 9559678Slinton public procreturn(f) 9569678Slinton Symbol f; 9579678Slinton { 95818231Slinton integer retvalsize; 95918231Slinton Node tmp; 96018231Slinton char *copy; 96118231Slinton 9629678Slinton flushoutput(); 9639678Slinton popenv(); 96418231Slinton if (endproc.isfunc) { 96518231Slinton retvalsize = size(f->type); 96618231Slinton if (retvalsize > sizeof(long)) { 96718231Slinton pushretval(retvalsize, true); 96818231Slinton copy = newarr(char, retvalsize); 96918231Slinton popn(retvalsize, copy); 97018231Slinton tmp = build(O_SCON, copy); 97118231Slinton } else { 97218231Slinton tmp = build(O_LCON, (long) (reg(0))); 97318231Slinton } 97418231Slinton tmp->nodetype = f->type; 97518231Slinton tfree(endproc.callnode); 97618231Slinton *(endproc.callnode) = *(tmp); 97718231Slinton dispose(tmp); 97818231Slinton eval(endproc.cmdnode); 97918231Slinton } else { 98018231Slinton putchar('\n'); 98118231Slinton printname(stdout, f); 98218231Slinton printf(" returns successfully\n", symname(f)); 98318231Slinton } 9849678Slinton erecover(); 9859678Slinton } 9869678Slinton 9879678Slinton /* 9889678Slinton * Push the current environment. 9899678Slinton */ 9909678Slinton 9919678Slinton private pushenv() 9929678Slinton { 9939678Slinton push(Address, pc); 9949678Slinton push(Lineno, curline); 9959678Slinton push(String, cursource); 9969678Slinton push(Boolean, isstopped); 9979678Slinton push(Symbol, curfunc); 99816618Ssam push(Frame, curframe); 99916618Ssam push(struct Frame, curframerec); 100018231Slinton push(CallEnv, endproc); 10019678Slinton push(Word, reg(PROGCTR)); 10029678Slinton push(Word, reg(STKP)); 10039678Slinton } 10049678Slinton 10059678Slinton /* 10069678Slinton * Pop back to the real world. 10079678Slinton */ 10089678Slinton 10099678Slinton public popenv() 10109678Slinton { 101118231Slinton String filename; 10129678Slinton 10139678Slinton setreg(STKP, pop(Word)); 10149678Slinton setreg(PROGCTR, pop(Word)); 101518231Slinton endproc = pop(CallEnv); 101616618Ssam curframerec = pop(struct Frame); 101716618Ssam curframe = pop(Frame); 10189678Slinton curfunc = pop(Symbol); 10199678Slinton isstopped = pop(Boolean); 10209678Slinton filename = pop(String); 10219678Slinton curline = pop(Lineno); 10229678Slinton pc = pop(Address); 10239678Slinton setsource(filename); 10249678Slinton } 10259678Slinton 10269678Slinton /* 10279678Slinton * Flush the debuggee's standard output. 10289678Slinton * 10299678Slinton * This is VERY dependent on the use of stdio. 10309678Slinton */ 10319678Slinton 10329678Slinton public flushoutput() 10339678Slinton { 103418231Slinton Symbol p, iob; 103518231Slinton Stack *savesp; 10369678Slinton 10379678Slinton p = lookup(identname("fflush", true)); 10389678Slinton while (p != nil and not isblock(p)) { 10399678Slinton p = p->next_sym; 10409678Slinton } 10419678Slinton if (p != nil) { 10429678Slinton iob = lookup(identname("_iob", true)); 10439678Slinton if (iob != nil) { 10449678Slinton pushenv(); 10459678Slinton pc = codeloc(p); 10469678Slinton savesp = sp; 10479678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 10489678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 10499678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 10509678Slinton sp = savesp; 10519678Slinton beginproc(p, 1); 10529678Slinton stepto(return_addr()); 10539678Slinton popenv(); 10549678Slinton } 10559678Slinton } 10569678Slinton } 1057