19678Slinton /* Copyright (c) 1982 Regents of the University of California */ 29678Slinton 3*18231Slinton static char sccsid[] = "@(#)runtime.c 1.13 (Berkeley) 03/01/85"; 49678Slinton 5*18231Slinton static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $"; 6*18231Slinton 79678Slinton /* 89678Slinton * Runtime organization dependent routines, mostly dealing with 99678Slinton * activation records. 109678Slinton */ 119678Slinton 129678Slinton #include "defs.h" 139678Slinton #include "runtime.h" 149678Slinton #include "process.h" 159678Slinton #include "machine.h" 169678Slinton #include "events.h" 179678Slinton #include "mappings.h" 189678Slinton #include "symbols.h" 199678Slinton #include "tree.h" 209678Slinton #include "eval.h" 219678Slinton #include "operators.h" 229678Slinton #include "object.h" 2312546Scsvaf #include <sys/param.h> 249678Slinton 259678Slinton #ifndef public 269678Slinton typedef struct Frame *Frame; 279678Slinton 289678Slinton #include "machine.h" 299678Slinton #endif 309678Slinton 319678Slinton #define NSAVEREG 12 329678Slinton 339678Slinton struct Frame { 34*18231Slinton integer condition_handler; 35*18231Slinton integer mask; 369678Slinton Address save_ap; /* argument pointer */ 379678Slinton Address save_fp; /* frame pointer */ 389678Slinton Address save_pc; /* program counter */ 399678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 409678Slinton }; 419678Slinton 4216618Ssam private Frame curframe = nil; 4316618Ssam private struct Frame curframerec; 449678Slinton private Boolean walkingstack = false; 459678Slinton 4616618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 4716618Ssam 48*18231Slinton #define isstackaddr(addr) \ 49*18231Slinton (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * UPAGES)) 50*18231Slinton 51*18231Slinton typedef struct { 52*18231Slinton Node callnode; 53*18231Slinton Node cmdnode; 54*18231Slinton boolean isfunc; 55*18231Slinton } CallEnv; 56*18231Slinton 57*18231Slinton private CallEnv endproc; 58*18231Slinton 599678Slinton /* 609678Slinton * Set a frame to the current activation record. 619678Slinton */ 629678Slinton 639678Slinton private getcurframe(frp) 64*18231Slinton Frame frp; 659678Slinton { 669678Slinton register int i; 679678Slinton 689678Slinton checkref(frp); 699678Slinton frp->mask = reg(NREG); 709678Slinton frp->save_ap = reg(ARGP); 719678Slinton frp->save_fp = reg(FRP); 72*18231Slinton frp->save_pc = reg(PROGCTR); 739678Slinton for (i = 0; i < NSAVEREG; i++) { 749678Slinton frp->save_reg[i] = reg(i); 759678Slinton } 769678Slinton } 779678Slinton 789678Slinton /* 79*18231Slinton * Get the saved registers from one frame to another 80*18231Slinton * given mask specifying which registers were actually saved. 81*18231Slinton */ 82*18231Slinton 83*18231Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 84*18231Slinton 85*18231Slinton private getsaveregs (newfrp, frp, mask) 86*18231Slinton Frame newfrp, frp; 87*18231Slinton integer mask; 88*18231Slinton { 89*18231Slinton integer i, j; 90*18231Slinton 91*18231Slinton j = 0; 92*18231Slinton for (i = 0; i < NSAVEREG; i++) { 93*18231Slinton if (bis(mask, i)) { 94*18231Slinton newfrp->save_reg[i] = frp->save_reg[j]; 95*18231Slinton ++j; 96*18231Slinton } 97*18231Slinton } 98*18231Slinton } 99*18231Slinton 100*18231Slinton /* 1019678Slinton * Return a pointer to the next activation record up the stack. 1029678Slinton * Return nil if there is none. 1039678Slinton * Writes over space pointed to by given argument. 1049678Slinton */ 1059678Slinton 1069678Slinton private Frame nextframe(frp) 1079678Slinton Frame frp; 1089678Slinton { 109*18231Slinton Frame newfrp; 1109678Slinton struct Frame frame; 111*18231Slinton integer mask; 11212546Scsvaf Address prev_frame, callpc; 113*18231Slinton static integer ntramp = 0; 1149678Slinton 1159678Slinton newfrp = frp; 11612546Scsvaf prev_frame = frp->save_fp; 11712546Scsvaf 11813937Slinton /* 11913937Slinton * The check for interrupt generated frames is taken from adb with only 12013937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 12113937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>. 12212546Scsvaf * 12312546Scsvaf * As best I can make out it looks like: 12412546Scsvaf * 12513937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>. 12613937Slinton * 12713937Slinton * When the signal occurs an exception block and a frame for the routine 12813937Slinton * in which it occured are pushed on the user stack. Then another frame 12913937Slinton * is pushed corresponding to a call from the kernel to sigsub. 13013937Slinton * 13112546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 13213937Slinton * but in the machine check exception block. It is at the magic address 13314620Ssam * fp + 84. 13412546Scsvaf * 13512546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 13613937Slinton * and takes the pc for sub from the exception block. This allows the 13713937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable. 13812546Scsvaf */ 13912546Scsvaf 14013937Slinton nextf: 14113937Slinton dread(&frame, prev_frame, sizeof(struct Frame)); 14213937Slinton if (ntramp == 1) { 14314620Ssam dread(&callpc, prev_frame + 84, sizeof(callpc)); 14413937Slinton } else { 14513937Slinton callpc = frame.save_pc; 14613937Slinton } 147*18231Slinton if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 1489678Slinton newfrp = nil; 149*18231Slinton } else if (isstackaddr(callpc)) { 150*18231Slinton ntramp++; 151*18231Slinton prev_frame = frame.save_fp; 152*18231Slinton goto nextf; 15313937Slinton } else { 15412546Scsvaf frame.save_pc = callpc; 15513937Slinton ntramp = 0; 1569678Slinton mask = ((frame.mask >> 16) & 0x0fff); 157*18231Slinton getsaveregs(newfrp, &frame, mask); 1589678Slinton newfrp->condition_handler = frame.condition_handler; 1599678Slinton newfrp->mask = mask; 1609678Slinton newfrp->save_ap = frame.save_ap; 1619678Slinton newfrp->save_fp = frame.save_fp; 1629678Slinton newfrp->save_pc = frame.save_pc; 1639678Slinton } 1649678Slinton return newfrp; 1659678Slinton } 1669678Slinton 1679678Slinton /* 16816618Ssam * Get the current frame information in the given Frame and store the 16916618Ssam * associated function in the given value-result parameter. 17016618Ssam */ 17116618Ssam 17216618Ssam private getcurfunc (frp, fp) 17316618Ssam Frame frp; 17416618Ssam Symbol *fp; 17516618Ssam { 17616618Ssam getcurframe(frp); 17716618Ssam *fp = whatblock(frp->save_pc); 17816618Ssam } 17916618Ssam 18016618Ssam /* 18116618Ssam * Return the frame associated with the next function up the call stack, or 18216618Ssam * nil if there is none. The function is returned in a value-result parameter. 18316618Ssam * For "inline" functions the statically outer function and same frame 18416618Ssam * are returned. 18516618Ssam */ 18616618Ssam 187*18231Slinton public Frame nextfunc (frp, fp) 18816618Ssam Frame frp; 18916618Ssam Symbol *fp; 19016618Ssam { 19116618Ssam Symbol t; 19216618Ssam Frame nfrp; 19316618Ssam 19416618Ssam t = *fp; 19516618Ssam checkref(t); 19616618Ssam if (isinline(t)) { 19716618Ssam t = container(t); 19816618Ssam nfrp = frp; 19916618Ssam } else { 20016618Ssam nfrp = nextframe(frp); 20116618Ssam if (nfrp == nil) { 20216618Ssam t = nil; 20316618Ssam } else { 20416618Ssam t = whatblock(nfrp->save_pc); 20516618Ssam } 20616618Ssam } 20716618Ssam *fp = t; 20816618Ssam return nfrp; 20916618Ssam } 21016618Ssam 21116618Ssam /* 2129678Slinton * Return the frame associated with the given function. 2139678Slinton * If the function is nil, return the most recently activated frame. 2149678Slinton * 2159678Slinton * Static allocation for the frame. 2169678Slinton */ 2179678Slinton 2189678Slinton public Frame findframe(f) 2199678Slinton Symbol f; 2209678Slinton { 221*18231Slinton Frame frp; 2229678Slinton static struct Frame frame; 22311866Slinton Symbol p; 224*18231Slinton Boolean done; 2259678Slinton 2269678Slinton frp = &frame; 2279678Slinton getcurframe(frp); 228*18231Slinton if (f != nil) { 229*18231Slinton if (f == curfunc and curframe != nil) { 230*18231Slinton *frp = *curframe; 231*18231Slinton } else { 232*18231Slinton done = false; 233*18231Slinton p = whatblock(frp->save_pc); 234*18231Slinton do { 235*18231Slinton if (p == f) { 236*18231Slinton done = true; 237*18231Slinton } else if (p == program) { 238*18231Slinton done = true; 239*18231Slinton frp = nil; 240*18231Slinton } else { 241*18231Slinton frp = nextfunc(frp, &p); 242*18231Slinton if (frp == nil) { 243*18231Slinton done = true; 244*18231Slinton } 245*18231Slinton } 246*18231Slinton } while (not done); 24715784Ssam } 248*18231Slinton } 249*18231Slinton return frp; 250*18231Slinton } 251*18231Slinton 252*18231Slinton /* 253*18231Slinton * Set the registers according to the given frame pointer. 254*18231Slinton */ 255*18231Slinton 256*18231Slinton public getnewregs (addr) 257*18231Slinton Address addr; 258*18231Slinton { 259*18231Slinton struct Frame frame; 260*18231Slinton integer i, j, mask; 261*18231Slinton 262*18231Slinton dread(&frame, addr, sizeof(frame)); 263*18231Slinton setreg(ARGP, frame.save_ap); 264*18231Slinton setreg(FRP, frame.save_fp); 265*18231Slinton setreg(PROGCTR, frame.save_pc); 266*18231Slinton mask = ((frame.mask >> 16) & 0x0fff); 267*18231Slinton j = 0; 268*18231Slinton for (i = 0; i < NSAVEREG; i++) { 269*18231Slinton if (bis(mask, i)) { 270*18231Slinton setreg(i, frame.save_reg[j]); 271*18231Slinton ++j; 27216636Ssam } 2739678Slinton } 274*18231Slinton pc = frame.save_pc; 275*18231Slinton setcurfunc(whatblock(pc)); 2769678Slinton } 2779678Slinton 2789678Slinton /* 2799678Slinton * Find the return address of the current procedure/function. 2809678Slinton */ 2819678Slinton 2829678Slinton public Address return_addr() 2839678Slinton { 2849678Slinton Frame frp; 2859678Slinton Address addr; 2869678Slinton struct Frame frame; 2879678Slinton 2889678Slinton frp = &frame; 2899678Slinton getcurframe(frp); 2909678Slinton frp = nextframe(frp); 2919678Slinton if (frp == nil) { 2929678Slinton addr = 0; 2939678Slinton } else { 2949678Slinton addr = frp->save_pc; 2959678Slinton } 2969678Slinton return addr; 2979678Slinton } 2989678Slinton 2999678Slinton /* 3009678Slinton * Push the value associated with the current function. 3019678Slinton */ 3029678Slinton 3039678Slinton public pushretval(len, isindirect) 304*18231Slinton integer len; 305*18231Slinton boolean isindirect; 3069678Slinton { 3079678Slinton Word r0; 3089678Slinton 3099678Slinton r0 = reg(0); 3109678Slinton if (isindirect) { 3119678Slinton rpush((Address) r0, len); 3129678Slinton } else { 3139678Slinton switch (len) { 3149678Slinton case sizeof(char): 3159678Slinton push(char, r0); 3169678Slinton break; 3179678Slinton 3189678Slinton case sizeof(short): 3199678Slinton push(short, r0); 3209678Slinton break; 3219678Slinton 3229678Slinton default: 3239678Slinton if (len == sizeof(Word)) { 3249678Slinton push(Word, r0); 3259678Slinton } else if (len == 2*sizeof(Word)) { 3269678Slinton push(Word, r0); 3279678Slinton push(Word, reg(1)); 3289678Slinton } else { 329*18231Slinton error("[internal error: bad size %d in pushretval]", len); 3309678Slinton } 3319678Slinton break; 3329678Slinton } 3339678Slinton } 3349678Slinton } 3359678Slinton 3369678Slinton /* 3379678Slinton * Return the base address for locals in the given frame. 3389678Slinton */ 3399678Slinton 3409678Slinton public Address locals_base(frp) 341*18231Slinton Frame frp; 3429678Slinton { 3439678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 3449678Slinton } 3459678Slinton 3469678Slinton /* 3479678Slinton * Return the base address for arguments in the given frame. 3489678Slinton */ 3499678Slinton 3509678Slinton public Address args_base(frp) 351*18231Slinton Frame frp; 3529678Slinton { 3539678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 3549678Slinton } 3559678Slinton 3569678Slinton /* 3579678Slinton * Return saved register n from the given frame. 3589678Slinton */ 3599678Slinton 3609678Slinton public Word savereg(n, frp) 361*18231Slinton integer n; 362*18231Slinton Frame frp; 3639678Slinton { 364*18231Slinton Word w; 3659678Slinton 3669678Slinton if (frp == nil) { 3679678Slinton w = reg(n); 3689678Slinton } else { 3699678Slinton switch (n) { 3709678Slinton case ARGP: 3719678Slinton w = frp->save_ap; 3729678Slinton break; 3739678Slinton 3749678Slinton case FRP: 3759678Slinton w = frp->save_fp; 3769678Slinton break; 3779678Slinton 3789678Slinton case STKP: 3799678Slinton w = reg(STKP); 3809678Slinton break; 3819678Slinton 3829678Slinton case PROGCTR: 3839678Slinton w = frp->save_pc; 3849678Slinton break; 3859678Slinton 3869678Slinton default: 3879678Slinton assert(n >= 0 and n < NSAVEREG); 3889678Slinton w = frp->save_reg[n]; 3899678Slinton break; 3909678Slinton } 3919678Slinton } 3929678Slinton return w; 3939678Slinton } 3949678Slinton 3959678Slinton /* 3969678Slinton * Return the nth argument to the current procedure. 3979678Slinton */ 3989678Slinton 3999678Slinton public Word argn(n, frp) 400*18231Slinton integer n; 4019678Slinton Frame frp; 4029678Slinton { 4039678Slinton Word w; 4049678Slinton 4059678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 4069678Slinton return w; 4079678Slinton } 4089678Slinton 4099678Slinton /* 410*18231Slinton * Print a list of currently active blocks starting with most recent. 4119678Slinton */ 4129678Slinton 413*18231Slinton public wherecmd() 4149678Slinton { 415*18231Slinton walkstack(false); 4169678Slinton } 4179678Slinton 4189678Slinton /* 419*18231Slinton * Print the variables in the given frame or the current one if nil. 4209678Slinton */ 4219678Slinton 422*18231Slinton public dump (func) 423*18231Slinton Symbol func; 4249678Slinton { 425*18231Slinton Symbol f; 426*18231Slinton Frame frp; 427*18231Slinton 428*18231Slinton if (func == nil) { 429*18231Slinton f = curfunc; 430*18231Slinton if (curframe != nil) { 431*18231Slinton frp = curframe; 432*18231Slinton } else { 433*18231Slinton frp = findframe(f); 434*18231Slinton } 435*18231Slinton } else { 436*18231Slinton f = func; 437*18231Slinton frp = findframe(f); 438*18231Slinton } 439*18231Slinton showaggrs = true; 440*18231Slinton printcallinfo(f, frp); 441*18231Slinton dumpvars(f, frp); 4429678Slinton } 4439678Slinton 4449678Slinton /* 445*18231Slinton * Dump all values. 4469678Slinton */ 4479678Slinton 448*18231Slinton public dumpall () 4499678Slinton { 4509678Slinton walkstack(true); 4519678Slinton } 4529678Slinton 4539678Slinton /* 4549678Slinton * Walk the stack of active procedures printing information 4559678Slinton * about each active procedure. 4569678Slinton */ 4579678Slinton 4589678Slinton private walkstack(dumpvariables) 4599678Slinton Boolean dumpvariables; 4609678Slinton { 461*18231Slinton Frame frp; 462*18231Slinton boolean save; 46316618Ssam Symbol f; 4649678Slinton struct Frame frame; 4659678Slinton 466*18231Slinton if (notstarted(process) or isfinished(process)) { 4679678Slinton error("program is not active"); 4689678Slinton } else { 4699678Slinton save = walkingstack; 4709678Slinton walkingstack = true; 471*18231Slinton showaggrs = dumpvariables; 4729678Slinton frp = &frame; 47316618Ssam getcurfunc(frp, &f); 474*18231Slinton for (;;) { 475*18231Slinton printcallinfo(f, frp); 4769678Slinton if (dumpvariables) { 4779678Slinton dumpvars(f, frp); 4789678Slinton putchar('\n'); 4799678Slinton } 48016618Ssam frp = nextfunc(frp, &f); 481*18231Slinton if (frp == nil or f == program) { 482*18231Slinton break; 483*18231Slinton } 484*18231Slinton } 4859678Slinton if (dumpvariables) { 4869678Slinton printf("in \"%s\":\n", symname(program)); 4879678Slinton dumpvars(program, nil); 4889678Slinton putchar('\n'); 4899678Slinton } 4909678Slinton walkingstack = save; 4919678Slinton } 4929678Slinton } 4939678Slinton 4949678Slinton /* 495*18231Slinton * Print out the information about a call, i.e., 496*18231Slinton * routine name, parameter values, and source location. 497*18231Slinton */ 498*18231Slinton 499*18231Slinton private printcallinfo (f, frp) 500*18231Slinton Symbol f; 501*18231Slinton Frame frp; 502*18231Slinton { 503*18231Slinton Lineno line; 504*18231Slinton Address savepc; 505*18231Slinton 506*18231Slinton savepc = frp->save_pc; 507*18231Slinton if (frp->save_fp != reg(FRP)) { 508*18231Slinton savepc -= 1; 509*18231Slinton } 510*18231Slinton printname(stdout, f); 511*18231Slinton if (not isinline(f)) { 512*18231Slinton printparams(f, frp); 513*18231Slinton } 514*18231Slinton line = srcline(savepc); 515*18231Slinton if (line != 0) { 516*18231Slinton printf(", line %d", line); 517*18231Slinton printf(" in \"%s\"\n", srcfilename(savepc)); 518*18231Slinton } else { 519*18231Slinton printf(" at 0x%x\n", savepc); 520*18231Slinton } 521*18231Slinton } 522*18231Slinton 523*18231Slinton /* 52416618Ssam * Set the current function to the given symbol. 52516618Ssam * We must adjust "curframe" so that subsequent operations are 52616618Ssam * not confused; for simplicity we simply clear it. 52716618Ssam */ 52816618Ssam 52916618Ssam public setcurfunc (f) 53016618Ssam Symbol f; 53116618Ssam { 53216618Ssam curfunc = f; 53316618Ssam curframe = nil; 53416618Ssam } 53516618Ssam 53616618Ssam /* 537*18231Slinton * Return the frame for the current function. 538*18231Slinton * The space for the frame is allocated statically. 539*18231Slinton */ 540*18231Slinton 541*18231Slinton public Frame curfuncframe () 542*18231Slinton { 543*18231Slinton static struct Frame frame; 544*18231Slinton Frame frp; 545*18231Slinton 546*18231Slinton if (curframe == nil) { 547*18231Slinton frp = findframe(curfunc); 548*18231Slinton curframe = &curframerec; 549*18231Slinton *curframe = *frp; 550*18231Slinton } else { 551*18231Slinton frp = &frame; 552*18231Slinton *frp = *curframe; 553*18231Slinton } 554*18231Slinton return frp; 555*18231Slinton } 556*18231Slinton 557*18231Slinton /* 55816618Ssam * Set curfunc to be N up/down the stack from its current value. 55916618Ssam */ 56016618Ssam 56116618Ssam public up (n) 56216618Ssam integer n; 56316618Ssam { 56416618Ssam integer i; 56516618Ssam Symbol f; 56616618Ssam Frame frp; 56716618Ssam boolean done; 56816618Ssam 56916618Ssam if (not isactive(program)) { 57016618Ssam error("program is not active"); 57116618Ssam } else if (curfunc == nil) { 57216618Ssam error("no current function"); 57316618Ssam } else { 57416618Ssam i = 0; 57516618Ssam f = curfunc; 576*18231Slinton frp = curfuncframe(); 57716618Ssam done = false; 57816618Ssam do { 57916618Ssam if (frp == nil) { 58016618Ssam done = true; 58116618Ssam error("not that many levels"); 58216618Ssam } else if (i >= n) { 58316618Ssam done = true; 58416618Ssam curfunc = f; 58516618Ssam curframe = &curframerec; 58616618Ssam *curframe = *frp; 587*18231Slinton showaggrs = false; 588*18231Slinton printcallinfo(curfunc, curframe); 58916618Ssam } else if (f == program) { 59016618Ssam done = true; 59116618Ssam error("not that many levels"); 59216618Ssam } else { 59316618Ssam frp = nextfunc(frp, &f); 59416618Ssam } 59516618Ssam ++i; 59616618Ssam } while (not done); 59716618Ssam } 59816618Ssam } 59916618Ssam 60016618Ssam public down (n) 60116618Ssam integer n; 60216618Ssam { 60316618Ssam integer i, depth; 604*18231Slinton Frame frp, curfrp; 60516618Ssam Symbol f; 60616618Ssam struct Frame frame; 60716618Ssam 60816618Ssam if (not isactive(program)) { 60916618Ssam error("program is not active"); 61016618Ssam } else if (curfunc == nil) { 61116618Ssam error("no current function"); 61216618Ssam } else { 61316618Ssam depth = 0; 61416618Ssam frp = &frame; 61516618Ssam getcurfunc(frp, &f); 61616618Ssam if (curframe == nil) { 617*18231Slinton curfrp = findframe(curfunc); 61816618Ssam curframe = &curframerec; 619*18231Slinton *curframe = *curfrp; 62016618Ssam } 62116618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 62216618Ssam frp = nextfunc(frp, &f); 62316618Ssam ++depth; 62416618Ssam } 62516618Ssam if (f == nil or n > depth) { 62616618Ssam error("not that many levels"); 62716618Ssam } else { 62816618Ssam depth -= n; 62916618Ssam frp = &frame; 63016618Ssam getcurfunc(frp, &f); 63116618Ssam for (i = 0; i < depth; i++) { 63216618Ssam frp = nextfunc(frp, &f); 63316618Ssam assert(frp != nil); 63416618Ssam } 63516618Ssam curfunc = f; 63616618Ssam *curframe = *frp; 637*18231Slinton showaggrs = false; 638*18231Slinton printcallinfo(curfunc, curframe); 63916618Ssam } 64016618Ssam } 64116618Ssam } 64216618Ssam 64316618Ssam /* 6449678Slinton * Find the entry point of a procedure or function. 6459678Slinton */ 6469678Slinton 647*18231Slinton public findbeginning (f) 6489678Slinton Symbol f; 6499678Slinton { 65016618Ssam if (isinternal(f)) { 65116618Ssam f->symvalue.funcv.beginaddr += 15; 65216618Ssam } else { 65316618Ssam f->symvalue.funcv.beginaddr += 2; 65416618Ssam } 6559678Slinton } 6569678Slinton 6579678Slinton /* 6589678Slinton * Return the address corresponding to the first line in a function. 6599678Slinton */ 6609678Slinton 6619678Slinton public Address firstline(f) 6629678Slinton Symbol f; 6639678Slinton { 6649678Slinton Address addr; 6659678Slinton 6669678Slinton addr = codeloc(f); 6679678Slinton while (linelookup(addr) == 0 and addr < objsize) { 6689678Slinton ++addr; 6699678Slinton } 6709678Slinton if (addr == objsize) { 6719678Slinton addr = -1; 6729678Slinton } 6739678Slinton return addr; 6749678Slinton } 6759678Slinton 6769678Slinton /* 6779678Slinton * Catcher drops strike three ... 6789678Slinton */ 6799678Slinton 6809678Slinton public runtofirst() 6819678Slinton { 6829678Slinton Address addr; 6839678Slinton 6849678Slinton addr = pc; 6859678Slinton while (linelookup(addr) == 0 and addr < objsize) { 6869678Slinton ++addr; 6879678Slinton } 6889678Slinton if (addr < objsize) { 6899678Slinton stepto(addr); 6909678Slinton } 6919678Slinton } 6929678Slinton 6939678Slinton /* 6949678Slinton * Return the address corresponding to the end of the program. 6959678Slinton * 6969678Slinton * We look for the entry to "exit". 6979678Slinton */ 6989678Slinton 6999678Slinton public Address lastaddr() 7009678Slinton { 701*18231Slinton Symbol s; 7029678Slinton 7039678Slinton s = lookup(identname("exit", true)); 7049678Slinton if (s == nil) { 7059678Slinton panic("can't find exit"); 7069678Slinton } 7079678Slinton return codeloc(s); 7089678Slinton } 7099678Slinton 7109678Slinton /* 7119678Slinton * Decide if the given function is currently active. 7129678Slinton * 7139678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 7149678Slinton * Presumably information evaluated while walking the stack is active. 7159678Slinton */ 7169678Slinton 7179678Slinton public Boolean isactive(f) 7189678Slinton Symbol f; 7199678Slinton { 720*18231Slinton Boolean b; 7219678Slinton 7229678Slinton if (isfinished(process)) { 7239678Slinton b = false; 7249678Slinton } else { 7259678Slinton if (walkingstack or f == program or 7269678Slinton (ismodule(f) and isactive(container(f)))) { 7279678Slinton b = true; 7289678Slinton } else { 7299678Slinton b = (Boolean) (findframe(f) != nil); 7309678Slinton } 7319678Slinton } 7329678Slinton return b; 7339678Slinton } 7349678Slinton 7359678Slinton /* 7369678Slinton * Evaluate a call to a procedure. 7379678Slinton */ 7389678Slinton 739*18231Slinton public callproc(exprnode, isfunc) 740*18231Slinton Node exprnode; 741*18231Slinton boolean isfunc; 7429678Slinton { 743*18231Slinton Node procnode, arglist; 7449678Slinton Symbol proc; 745*18231Slinton integer argc; 7469678Slinton 747*18231Slinton procnode = exprnode->value.arg[0]; 748*18231Slinton arglist = exprnode->value.arg[1]; 7499678Slinton if (procnode->op != O_SYM) { 7509678Slinton beginerrmsg(); 7519678Slinton fprintf(stderr, "can't call \""); 7529678Slinton prtree(stderr, procnode); 7539678Slinton fprintf(stderr, "\""); 7549678Slinton enderrmsg(); 7559678Slinton } 7569678Slinton assert(procnode->op == O_SYM); 7579678Slinton proc = procnode->value.sym; 7589678Slinton if (not isblock(proc)) { 7599678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 7609678Slinton } 761*18231Slinton endproc.isfunc = isfunc; 762*18231Slinton endproc.callnode = exprnode; 763*18231Slinton endproc.cmdnode = topnode; 7649678Slinton pushenv(); 7659678Slinton pc = codeloc(proc); 7669678Slinton argc = pushargs(proc, arglist); 7679678Slinton beginproc(proc, argc); 768*18231Slinton event_once( 769*18231Slinton build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 770*18231Slinton buildcmdlist(build(O_PROCRTN, proc)) 771*18231Slinton ); 772*18231Slinton isstopped = false; 773*18231Slinton if (not bpact()) { 774*18231Slinton isstopped = true; 775*18231Slinton cont(0); 776*18231Slinton } 777*18231Slinton /* 778*18231Slinton * bpact() won't return true, it will call printstatus() and go back 779*18231Slinton * to command input if a breakpoint is found. 780*18231Slinton */ 7819678Slinton /* NOTREACHED */ 7829678Slinton } 7839678Slinton 7849678Slinton /* 7859678Slinton * Push the arguments on the process' stack. We do this by first 7869678Slinton * evaluating them on the "eval" stack, then copying into the process' 7879678Slinton * space. 7889678Slinton */ 7899678Slinton 790*18231Slinton private integer pushargs(proc, arglist) 7919678Slinton Symbol proc; 7929678Slinton Node arglist; 7939678Slinton { 7949678Slinton Stack *savesp; 7959678Slinton int argc, args_size; 7969678Slinton 7979678Slinton savesp = sp; 7989678Slinton argc = evalargs(proc, arglist); 7999678Slinton args_size = sp - savesp; 8009678Slinton setreg(STKP, reg(STKP) - args_size); 8019678Slinton dwrite(savesp, reg(STKP), args_size); 8029678Slinton sp = savesp; 8039678Slinton return argc; 8049678Slinton } 8059678Slinton 8069678Slinton /* 80716618Ssam * Check to see if an expression is correct for a given parameter. 80816618Ssam * If the given parameter is false, don't worry about type inconsistencies. 80916618Ssam * 81016618Ssam * Return whether or not it is ok. 8119678Slinton */ 8129678Slinton 81316618Ssam private boolean chkparam (actual, formal, chk) 81416618Ssam Node actual; 81516618Ssam Symbol formal; 81616618Ssam boolean chk; 81716618Ssam { 81816618Ssam boolean b; 81916618Ssam 82016618Ssam b = true; 82116618Ssam if (chk) { 82216618Ssam if (formal == nil) { 82316618Ssam beginerrmsg(); 82416618Ssam fprintf(stderr, "too many parameters"); 82516618Ssam b = false; 82616618Ssam } else if (not compatible(formal->type, actual->nodetype)) { 82716618Ssam beginerrmsg(); 82816618Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 82916618Ssam b = false; 83016618Ssam } 83116618Ssam } 832*18231Slinton if (b and formal != nil and 833*18231Slinton isvarparam(formal) and not isopenarray(formal->type) and 834*18231Slinton not ( 835*18231Slinton actual->op == O_RVAL or actual->nodetype == t_addr or 836*18231Slinton ( 837*18231Slinton actual->op == O_TYPERENAME and 838*18231Slinton ( 839*18231Slinton actual->value.arg[0]->op == O_RVAL or 840*18231Slinton actual->value.arg[0]->nodetype == t_addr 841*18231Slinton ) 842*18231Slinton ) 843*18231Slinton ) 844*18231Slinton ) { 84516618Ssam beginerrmsg(); 84616618Ssam fprintf(stderr, "expected variable, found \""); 84716618Ssam prtree(stderr, actual); 84816618Ssam fprintf(stderr, "\""); 84916618Ssam b = false; 85016618Ssam } 85116618Ssam return b; 85216618Ssam } 85316618Ssam 85416618Ssam /* 85516618Ssam * Pass an expression to a particular parameter. 85616618Ssam * 85716618Ssam * Normally we pass either the address or value, but in some cases 85816618Ssam * (such as C strings) we want to copy the value onto the stack and 85916618Ssam * pass its address. 860*18231Slinton * 861*18231Slinton * Another special case raised by strings is the possibility that 862*18231Slinton * the actual parameter will be larger than the formal, even with 863*18231Slinton * appropriate type-checking. This occurs because we assume during 864*18231Slinton * evaluation that strings are null-terminated, whereas some languages, 865*18231Slinton * notably Pascal, do not work under that assumption. 86616618Ssam */ 86716618Ssam 86816618Ssam private passparam (actual, formal) 86916618Ssam Node actual; 87016618Ssam Symbol formal; 87116618Ssam { 87216618Ssam boolean b; 87316618Ssam Address addr; 87416618Ssam Stack *savesp; 875*18231Slinton integer actsize, formsize; 87616618Ssam 877*18231Slinton if (formal != nil and isvarparam(formal) and 878*18231Slinton (not isopenarray(formal->type)) 879*18231Slinton ) { 88016618Ssam addr = lval(actual->value.arg[0]); 88116618Ssam push(Address, addr); 88216618Ssam } else if (passaddr(formal, actual->nodetype)) { 88316618Ssam savesp = sp; 88416618Ssam eval(actual); 885*18231Slinton actsize = sp - savesp; 886*18231Slinton setreg(STKP, 887*18231Slinton reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) 888*18231Slinton ); 889*18231Slinton dwrite(savesp, reg(STKP), actsize); 89016618Ssam sp = savesp; 89116618Ssam push(Address, reg(STKP)); 89216618Ssam if (formal != nil and isopenarray(formal->type)) { 893*18231Slinton push(integer, actsize div size(formal->type->type)); 89416618Ssam } 895*18231Slinton } else if (formal != nil) { 896*18231Slinton formsize = size(formal); 897*18231Slinton savesp = sp; 898*18231Slinton eval(actual); 899*18231Slinton actsize = sp - savesp; 900*18231Slinton if (actsize > formsize) { 901*18231Slinton sp -= (actsize - formsize); 902*18231Slinton } 90316618Ssam } else { 90416618Ssam eval(actual); 90516618Ssam } 90616618Ssam } 90716618Ssam 90816618Ssam /* 90916618Ssam * Evaluate an argument list left-to-right. 91016618Ssam */ 91116618Ssam 912*18231Slinton private integer evalargs(proc, arglist) 9139678Slinton Symbol proc; 9149678Slinton Node arglist; 9159678Slinton { 91616618Ssam Node p, actual; 91716618Ssam Symbol formal; 9189678Slinton Stack *savesp; 919*18231Slinton integer count; 92016618Ssam boolean chk; 9219678Slinton 9229678Slinton savesp = sp; 9239678Slinton count = 0; 92416618Ssam formal = proc->chain; 92516618Ssam chk = (boolean) (not nosource(proc)); 9269678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 92716618Ssam assert(p->op == O_COMMA); 92816618Ssam actual = p->value.arg[0]; 92916618Ssam if (not chkparam(actual, formal, chk)) { 93016618Ssam fprintf(stderr, " in call to %s", symname(proc)); 9319678Slinton sp = savesp; 93216618Ssam enderrmsg(); 9339678Slinton } 93416618Ssam passparam(actual, formal); 93516618Ssam if (formal != nil) { 93616618Ssam formal = formal->chain; 9379678Slinton } 9389678Slinton ++count; 9399678Slinton } 94016618Ssam if (chk) { 94116618Ssam if (formal != nil) { 94216618Ssam sp = savesp; 94316618Ssam error("not enough parameters to %s", symname(proc)); 94416618Ssam } 9459678Slinton } 9469678Slinton return count; 9479678Slinton } 9489678Slinton 9499678Slinton public procreturn(f) 9509678Slinton Symbol f; 9519678Slinton { 952*18231Slinton integer retvalsize; 953*18231Slinton Node tmp; 954*18231Slinton char *copy; 955*18231Slinton 9569678Slinton flushoutput(); 9579678Slinton popenv(); 958*18231Slinton if (endproc.isfunc) { 959*18231Slinton retvalsize = size(f->type); 960*18231Slinton if (retvalsize > sizeof(long)) { 961*18231Slinton pushretval(retvalsize, true); 962*18231Slinton copy = newarr(char, retvalsize); 963*18231Slinton popn(retvalsize, copy); 964*18231Slinton tmp = build(O_SCON, copy); 965*18231Slinton } else { 966*18231Slinton tmp = build(O_LCON, (long) (reg(0))); 967*18231Slinton } 968*18231Slinton tmp->nodetype = f->type; 969*18231Slinton tfree(endproc.callnode); 970*18231Slinton *(endproc.callnode) = *(tmp); 971*18231Slinton dispose(tmp); 972*18231Slinton eval(endproc.cmdnode); 973*18231Slinton } else { 974*18231Slinton putchar('\n'); 975*18231Slinton printname(stdout, f); 976*18231Slinton printf(" returns successfully\n", symname(f)); 977*18231Slinton } 9789678Slinton erecover(); 9799678Slinton } 9809678Slinton 9819678Slinton /* 9829678Slinton * Push the current environment. 9839678Slinton */ 9849678Slinton 9859678Slinton private pushenv() 9869678Slinton { 9879678Slinton push(Address, pc); 9889678Slinton push(Lineno, curline); 9899678Slinton push(String, cursource); 9909678Slinton push(Boolean, isstopped); 9919678Slinton push(Symbol, curfunc); 99216618Ssam push(Frame, curframe); 99316618Ssam push(struct Frame, curframerec); 994*18231Slinton push(CallEnv, endproc); 9959678Slinton push(Word, reg(PROGCTR)); 9969678Slinton push(Word, reg(STKP)); 9979678Slinton } 9989678Slinton 9999678Slinton /* 10009678Slinton * Pop back to the real world. 10019678Slinton */ 10029678Slinton 10039678Slinton public popenv() 10049678Slinton { 1005*18231Slinton String filename; 10069678Slinton 10079678Slinton setreg(STKP, pop(Word)); 10089678Slinton setreg(PROGCTR, pop(Word)); 1009*18231Slinton endproc = pop(CallEnv); 101016618Ssam curframerec = pop(struct Frame); 101116618Ssam curframe = pop(Frame); 10129678Slinton curfunc = pop(Symbol); 10139678Slinton isstopped = pop(Boolean); 10149678Slinton filename = pop(String); 10159678Slinton curline = pop(Lineno); 10169678Slinton pc = pop(Address); 10179678Slinton setsource(filename); 10189678Slinton } 10199678Slinton 10209678Slinton /* 10219678Slinton * Flush the debuggee's standard output. 10229678Slinton * 10239678Slinton * This is VERY dependent on the use of stdio. 10249678Slinton */ 10259678Slinton 10269678Slinton public flushoutput() 10279678Slinton { 1028*18231Slinton Symbol p, iob; 1029*18231Slinton Stack *savesp; 10309678Slinton 10319678Slinton p = lookup(identname("fflush", true)); 10329678Slinton while (p != nil and not isblock(p)) { 10339678Slinton p = p->next_sym; 10349678Slinton } 10359678Slinton if (p != nil) { 10369678Slinton iob = lookup(identname("_iob", true)); 10379678Slinton if (iob != nil) { 10389678Slinton pushenv(); 10399678Slinton pc = codeloc(p); 10409678Slinton savesp = sp; 10419678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 10429678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 10439678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 10449678Slinton sp = savesp; 10459678Slinton beginproc(p, 1); 10469678Slinton stepto(return_addr()); 10479678Slinton popenv(); 10489678Slinton } 10499678Slinton } 10509678Slinton } 1051