121621Sdist /* 2*38105Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*38105Sbostic * All rights reserved. 4*38105Sbostic * 5*38105Sbostic * Redistribution and use in source and binary forms are permitted 6*38105Sbostic * provided that the above copyright notice and this paragraph are 7*38105Sbostic * duplicated in all such forms and that any documentation, 8*38105Sbostic * advertising materials, and other materials related to such 9*38105Sbostic * distribution and use acknowledge that the software was developed 10*38105Sbostic * by the University of California, Berkeley. The name of the 11*38105Sbostic * University may not be used to endorse or promote products derived 12*38105Sbostic * from this software without specific prior written permission. 13*38105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38105Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621621Sdist */ 179678Slinton 1821621Sdist #ifndef lint 19*38105Sbostic static char sccsid[] = "@(#)runtime.vax.c 5.4 (Berkeley) 05/23/89"; 20*38105Sbostic #endif /* not lint */ 219678Slinton 229678Slinton /* 239678Slinton * Runtime organization dependent routines, mostly dealing with 249678Slinton * activation records. 259678Slinton */ 269678Slinton 279678Slinton #include "defs.h" 289678Slinton #include "runtime.h" 299678Slinton #include "process.h" 309678Slinton #include "machine.h" 319678Slinton #include "events.h" 329678Slinton #include "mappings.h" 339678Slinton #include "symbols.h" 349678Slinton #include "tree.h" 359678Slinton #include "eval.h" 369678Slinton #include "operators.h" 379678Slinton #include "object.h" 3812546Scsvaf #include <sys/param.h> 3933334Sdonn #include <signal.h> 409678Slinton 419678Slinton #ifndef public 429678Slinton typedef struct Frame *Frame; 439678Slinton 449678Slinton #include "machine.h" 459678Slinton #endif 469678Slinton 479678Slinton #define NSAVEREG 12 489678Slinton 499678Slinton struct Frame { 5018231Slinton integer condition_handler; 5118231Slinton integer mask; 529678Slinton Address save_ap; /* argument pointer */ 539678Slinton Address save_fp; /* frame pointer */ 549678Slinton Address save_pc; /* program counter */ 559678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 569678Slinton }; 579678Slinton 5816618Ssam private Frame curframe = nil; 5916618Ssam private struct Frame curframerec; 609678Slinton private Boolean walkingstack = false; 619678Slinton 6216618Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 6316618Ssam 6433334Sdonn #define inSignalHandler(addr) \ 6533334Sdonn (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES))) 6618231Slinton 6718231Slinton typedef struct { 6818231Slinton Node callnode; 6918231Slinton Node cmdnode; 7018231Slinton boolean isfunc; 7118231Slinton } CallEnv; 7218231Slinton 7318231Slinton private CallEnv endproc; 7418231Slinton 759678Slinton /* 769678Slinton * Set a frame to the current activation record. 779678Slinton */ 789678Slinton 799678Slinton private getcurframe(frp) 8018231Slinton Frame frp; 819678Slinton { 829678Slinton register int i; 839678Slinton 849678Slinton checkref(frp); 859678Slinton frp->mask = reg(NREG); 869678Slinton frp->save_ap = reg(ARGP); 879678Slinton frp->save_fp = reg(FRP); 8818231Slinton frp->save_pc = reg(PROGCTR); 899678Slinton for (i = 0; i < NSAVEREG; i++) { 909678Slinton frp->save_reg[i] = reg(i); 919678Slinton } 929678Slinton } 939678Slinton 949678Slinton /* 9518231Slinton * Get the saved registers from one frame to another 9618231Slinton * given mask specifying which registers were actually saved. 9718231Slinton */ 9818231Slinton 9918231Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 10018231Slinton 10118231Slinton private getsaveregs (newfrp, frp, mask) 10218231Slinton Frame newfrp, frp; 10318231Slinton integer mask; 10418231Slinton { 10518231Slinton integer i, j; 10618231Slinton 10718231Slinton j = 0; 10818231Slinton for (i = 0; i < NSAVEREG; i++) { 10918231Slinton if (bis(mask, i)) { 11018231Slinton newfrp->save_reg[i] = frp->save_reg[j]; 11118231Slinton ++j; 11218231Slinton } 11318231Slinton } 11418231Slinton } 11518231Slinton 11618231Slinton /* 1179678Slinton * Return a pointer to the next activation record up the stack. 1189678Slinton * Return nil if there is none. 1199678Slinton * Writes over space pointed to by given argument. 1209678Slinton */ 1219678Slinton 1229678Slinton private Frame nextframe(frp) 1239678Slinton Frame frp; 1249678Slinton { 12518231Slinton Frame newfrp; 1269678Slinton struct Frame frame; 12718231Slinton integer mask; 12833334Sdonn Address prev_frame, callpc; 12918231Slinton static integer ntramp = 0; 1309678Slinton 1319678Slinton newfrp = frp; 13212546Scsvaf prev_frame = frp->save_fp; 13312546Scsvaf 13413937Slinton /* 13513937Slinton * The check for interrupt generated frames is taken from adb with only 13613937Slinton * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 13713937Slinton * gets control, then the stack does NOT look like <main, sub, sigsub>. 13812546Scsvaf * 13912546Scsvaf * As best I can make out it looks like: 14012546Scsvaf * 14113937Slinton * <main, (machine check exception block + sub), sysframe, sigsub>. 14213937Slinton * 14313937Slinton * When the signal occurs an exception block and a frame for the routine 14413937Slinton * in which it occured are pushed on the user stack. Then another frame 14513937Slinton * is pushed corresponding to a call from the kernel to sigsub. 14613937Slinton * 14712546Scsvaf * The addr in sub at which the exception occured is not in sub.save_pc 14813937Slinton * but in the machine check exception block. It is at the magic address 14914620Ssam * fp + 84. 15012546Scsvaf * 15112546Scsvaf * The current approach ignores the sys_frame (what adb reports as sigtramp) 15213937Slinton * and takes the pc for sub from the exception block. This allows the 15313937Slinton * "where" command to report <main, sub, sigsub>, which seems reasonable. 15412546Scsvaf */ 15512546Scsvaf 15613937Slinton nextf: 15733334Sdonn if (prev_frame + sizeof(struct Frame) <= USRSTACK) { 15833334Sdonn dread(&frame, prev_frame, sizeof(struct Frame)); 15933334Sdonn } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) { 16033334Sdonn dread(&frame, prev_frame, USRSTACK - prev_frame); 16133334Sdonn } else { 16233334Sdonn frame.save_fp = nil; 16333334Sdonn } 16413937Slinton if (ntramp == 1) { 16533334Sdonn dread(&callpc, prev_frame + 92, sizeof(callpc)); 16613937Slinton } else { 16713937Slinton callpc = frame.save_pc; 16813937Slinton } 16918231Slinton if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 1709678Slinton newfrp = nil; 17113937Slinton } else { 17233334Sdonn if (inSignalHandler(callpc)) { 17333334Sdonn ntramp++; 17433334Sdonn prev_frame = frame.save_fp; 17533334Sdonn goto nextf; 17633334Sdonn } 17712546Scsvaf frame.save_pc = callpc; 17813937Slinton ntramp = 0; 17933334Sdonn newfrp->save_fp = frame.save_fp; 18033334Sdonn newfrp->save_pc = frame.save_pc; 1819678Slinton mask = ((frame.mask >> 16) & 0x0fff); 18218231Slinton getsaveregs(newfrp, &frame, mask); 1839678Slinton newfrp->condition_handler = frame.condition_handler; 1849678Slinton newfrp->mask = mask; 1859678Slinton newfrp->save_ap = frame.save_ap; 1869678Slinton } 1879678Slinton return newfrp; 1889678Slinton } 1899678Slinton 1909678Slinton /* 19116618Ssam * Get the current frame information in the given Frame and store the 19216618Ssam * associated function in the given value-result parameter. 19316618Ssam */ 19416618Ssam 19516618Ssam private getcurfunc (frp, fp) 19616618Ssam Frame frp; 19716618Ssam Symbol *fp; 19816618Ssam { 19916618Ssam getcurframe(frp); 20016618Ssam *fp = whatblock(frp->save_pc); 20116618Ssam } 20216618Ssam 20316618Ssam /* 20416618Ssam * Return the frame associated with the next function up the call stack, or 20516618Ssam * nil if there is none. The function is returned in a value-result parameter. 20616618Ssam * For "inline" functions the statically outer function and same frame 20716618Ssam * are returned. 20816618Ssam */ 20916618Ssam 21018231Slinton public Frame nextfunc (frp, fp) 21116618Ssam Frame frp; 21216618Ssam Symbol *fp; 21316618Ssam { 21416618Ssam Symbol t; 21516618Ssam Frame nfrp; 21616618Ssam 21716618Ssam t = *fp; 21816618Ssam checkref(t); 21916618Ssam if (isinline(t)) { 22016618Ssam t = container(t); 22116618Ssam nfrp = frp; 22216618Ssam } else { 22316618Ssam nfrp = nextframe(frp); 22416618Ssam if (nfrp == nil) { 22516618Ssam t = nil; 22616618Ssam } else { 22716618Ssam t = whatblock(nfrp->save_pc); 22816618Ssam } 22916618Ssam } 23016618Ssam *fp = t; 23116618Ssam return nfrp; 23216618Ssam } 23316618Ssam 23416618Ssam /* 2359678Slinton * Return the frame associated with the given function. 2369678Slinton * If the function is nil, return the most recently activated frame. 2379678Slinton * 2389678Slinton * Static allocation for the frame. 2399678Slinton */ 2409678Slinton 2419678Slinton public Frame findframe(f) 2429678Slinton Symbol f; 2439678Slinton { 24418231Slinton Frame frp; 2459678Slinton static struct Frame frame; 24611866Slinton Symbol p; 24718231Slinton Boolean done; 2489678Slinton 2499678Slinton frp = &frame; 2509678Slinton getcurframe(frp); 25118231Slinton if (f != nil) { 25218231Slinton if (f == curfunc and curframe != nil) { 25318231Slinton *frp = *curframe; 25418231Slinton } else { 25518231Slinton done = false; 25618231Slinton p = whatblock(frp->save_pc); 25718231Slinton do { 25818231Slinton if (p == f) { 25918231Slinton done = true; 26018231Slinton } else if (p == program) { 26118231Slinton done = true; 26218231Slinton frp = nil; 26318231Slinton } else { 26418231Slinton frp = nextfunc(frp, &p); 26518231Slinton if (frp == nil) { 26618231Slinton done = true; 26718231Slinton } 26818231Slinton } 26918231Slinton } while (not done); 27015784Ssam } 27118231Slinton } 27218231Slinton return frp; 27318231Slinton } 27418231Slinton 27518231Slinton /* 27618231Slinton * Set the registers according to the given frame pointer. 27718231Slinton */ 27818231Slinton 27918231Slinton public getnewregs (addr) 28018231Slinton Address addr; 28118231Slinton { 28218231Slinton struct Frame frame; 28318231Slinton integer i, j, mask; 28418231Slinton 28518231Slinton dread(&frame, addr, sizeof(frame)); 28618231Slinton setreg(FRP, frame.save_fp); 28718231Slinton setreg(PROGCTR, frame.save_pc); 28833334Sdonn setreg(ARGP, frame.save_ap); 28918231Slinton mask = ((frame.mask >> 16) & 0x0fff); 29018231Slinton j = 0; 29118231Slinton for (i = 0; i < NSAVEREG; i++) { 29218231Slinton if (bis(mask, i)) { 29333334Sdonn setreg(i, frame.save_reg[j]); 29433334Sdonn ++j; 29516636Ssam } 2969678Slinton } 29718231Slinton pc = frame.save_pc; 29818231Slinton setcurfunc(whatblock(pc)); 2999678Slinton } 3009678Slinton 3019678Slinton /* 3029678Slinton * Find the return address of the current procedure/function. 3039678Slinton */ 3049678Slinton 3059678Slinton public Address return_addr() 3069678Slinton { 3079678Slinton Frame frp; 3089678Slinton Address addr; 3099678Slinton struct Frame frame; 3109678Slinton 3119678Slinton frp = &frame; 3129678Slinton getcurframe(frp); 3139678Slinton frp = nextframe(frp); 3149678Slinton if (frp == nil) { 3159678Slinton addr = 0; 3169678Slinton } else { 3179678Slinton addr = frp->save_pc; 3189678Slinton } 3199678Slinton return addr; 3209678Slinton } 3219678Slinton 3229678Slinton /* 3239678Slinton * Push the value associated with the current function. 3249678Slinton */ 3259678Slinton 3269678Slinton public pushretval(len, isindirect) 32718231Slinton integer len; 32818231Slinton boolean isindirect; 3299678Slinton { 3309678Slinton Word r0; 3319678Slinton 3329678Slinton r0 = reg(0); 3339678Slinton if (isindirect) { 3349678Slinton rpush((Address) r0, len); 3359678Slinton } else { 3369678Slinton switch (len) { 3379678Slinton case sizeof(char): 3389678Slinton push(char, r0); 3399678Slinton break; 3409678Slinton 3419678Slinton case sizeof(short): 3429678Slinton push(short, r0); 3439678Slinton break; 3449678Slinton 3459678Slinton default: 3469678Slinton if (len == sizeof(Word)) { 3479678Slinton push(Word, r0); 3489678Slinton } else if (len == 2*sizeof(Word)) { 3499678Slinton push(Word, r0); 3509678Slinton push(Word, reg(1)); 3519678Slinton } else { 35218231Slinton error("[internal error: bad size %d in pushretval]", len); 3539678Slinton } 3549678Slinton break; 3559678Slinton } 3569678Slinton } 3579678Slinton } 3589678Slinton 3599678Slinton /* 3609678Slinton * Return the base address for locals in the given frame. 3619678Slinton */ 3629678Slinton 3639678Slinton public Address locals_base(frp) 36418231Slinton Frame frp; 3659678Slinton { 3669678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 3679678Slinton } 3689678Slinton 3699678Slinton /* 3709678Slinton * Return the base address for arguments in the given frame. 3719678Slinton */ 3729678Slinton 3739678Slinton public Address args_base(frp) 37418231Slinton Frame frp; 3759678Slinton { 3769678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 3779678Slinton } 3789678Slinton 3799678Slinton /* 3809678Slinton * Return saved register n from the given frame. 3819678Slinton */ 3829678Slinton 3839678Slinton public Word savereg(n, frp) 38418231Slinton integer n; 38518231Slinton Frame frp; 3869678Slinton { 38718231Slinton Word w; 3889678Slinton 3899678Slinton if (frp == nil) { 3909678Slinton w = reg(n); 3919678Slinton } else { 3929678Slinton switch (n) { 3939678Slinton case ARGP: 3949678Slinton w = frp->save_ap; 3959678Slinton break; 3969678Slinton 3979678Slinton case FRP: 3989678Slinton w = frp->save_fp; 3999678Slinton break; 4009678Slinton 4019678Slinton case STKP: 4029678Slinton w = reg(STKP); 4039678Slinton break; 4049678Slinton 4059678Slinton case PROGCTR: 4069678Slinton w = frp->save_pc; 4079678Slinton break; 4089678Slinton 4099678Slinton default: 4109678Slinton assert(n >= 0 and n < NSAVEREG); 4119678Slinton w = frp->save_reg[n]; 4129678Slinton break; 4139678Slinton } 4149678Slinton } 4159678Slinton return w; 4169678Slinton } 4179678Slinton 4189678Slinton /* 4199678Slinton * Return the nth argument to the current procedure. 4209678Slinton */ 4219678Slinton 4229678Slinton public Word argn(n, frp) 42318231Slinton integer n; 4249678Slinton Frame frp; 4259678Slinton { 42633334Sdonn Address argaddr; 4279678Slinton Word w; 4289678Slinton 42933334Sdonn argaddr = args_base(frp) + (n * sizeof(Word)); 43033334Sdonn dread(&w, argaddr, sizeof(w)); 4319678Slinton return w; 4329678Slinton } 4339678Slinton 4349678Slinton /* 43518231Slinton * Print a list of currently active blocks starting with most recent. 4369678Slinton */ 4379678Slinton 43818231Slinton public wherecmd() 4399678Slinton { 44018231Slinton walkstack(false); 4419678Slinton } 4429678Slinton 4439678Slinton /* 44418231Slinton * Print the variables in the given frame or the current one if nil. 4459678Slinton */ 4469678Slinton 44718231Slinton public dump (func) 44818231Slinton Symbol func; 4499678Slinton { 45018231Slinton Symbol f; 45118231Slinton Frame frp; 45218231Slinton 45318231Slinton if (func == nil) { 45418231Slinton f = curfunc; 45518231Slinton if (curframe != nil) { 45618231Slinton frp = curframe; 45718231Slinton } else { 45818231Slinton frp = findframe(f); 45918231Slinton } 46018231Slinton } else { 46118231Slinton f = func; 46218231Slinton frp = findframe(f); 46318231Slinton } 46418231Slinton showaggrs = true; 46518231Slinton printcallinfo(f, frp); 46618231Slinton dumpvars(f, frp); 4679678Slinton } 4689678Slinton 4699678Slinton /* 47018231Slinton * Dump all values. 4719678Slinton */ 4729678Slinton 47318231Slinton public dumpall () 4749678Slinton { 4759678Slinton walkstack(true); 4769678Slinton } 4779678Slinton 4789678Slinton /* 4799678Slinton * Walk the stack of active procedures printing information 4809678Slinton * about each active procedure. 4819678Slinton */ 4829678Slinton 4839678Slinton private walkstack(dumpvariables) 4849678Slinton Boolean dumpvariables; 4859678Slinton { 48618231Slinton Frame frp; 48718231Slinton boolean save; 48816618Ssam Symbol f; 4899678Slinton struct Frame frame; 4909678Slinton 49118231Slinton if (notstarted(process) or isfinished(process)) { 4929678Slinton error("program is not active"); 4939678Slinton } else { 4949678Slinton save = walkingstack; 4959678Slinton walkingstack = true; 49618231Slinton showaggrs = dumpvariables; 4979678Slinton frp = &frame; 49816618Ssam getcurfunc(frp, &f); 49918231Slinton for (;;) { 50018231Slinton printcallinfo(f, frp); 5019678Slinton if (dumpvariables) { 5029678Slinton dumpvars(f, frp); 5039678Slinton putchar('\n'); 5049678Slinton } 50516618Ssam frp = nextfunc(frp, &f); 50618231Slinton if (frp == nil or f == program) { 50718231Slinton break; 50818231Slinton } 50918231Slinton } 5109678Slinton if (dumpvariables) { 5119678Slinton printf("in \"%s\":\n", symname(program)); 5129678Slinton dumpvars(program, nil); 5139678Slinton putchar('\n'); 5149678Slinton } 5159678Slinton walkingstack = save; 5169678Slinton } 5179678Slinton } 5189678Slinton 5199678Slinton /* 52018231Slinton * Print out the information about a call, i.e., 52118231Slinton * routine name, parameter values, and source location. 52218231Slinton */ 52318231Slinton 52418231Slinton private printcallinfo (f, frp) 52518231Slinton Symbol f; 52618231Slinton Frame frp; 52718231Slinton { 52818231Slinton Lineno line; 52918231Slinton Address savepc; 53018231Slinton 53118231Slinton savepc = frp->save_pc; 53218231Slinton if (frp->save_fp != reg(FRP)) { 53318231Slinton savepc -= 1; 53418231Slinton } 53518231Slinton printname(stdout, f); 53618231Slinton if (not isinline(f)) { 53718231Slinton printparams(f, frp); 53818231Slinton } 53918231Slinton line = srcline(savepc); 54018231Slinton if (line != 0) { 54118231Slinton printf(", line %d", line); 54218231Slinton printf(" in \"%s\"\n", srcfilename(savepc)); 54318231Slinton } else { 54418231Slinton printf(" at 0x%x\n", savepc); 54518231Slinton } 54618231Slinton } 54718231Slinton 54818231Slinton /* 54916618Ssam * Set the current function to the given symbol. 55016618Ssam * We must adjust "curframe" so that subsequent operations are 55116618Ssam * not confused; for simplicity we simply clear it. 55216618Ssam */ 55316618Ssam 55416618Ssam public setcurfunc (f) 55516618Ssam Symbol f; 55616618Ssam { 55716618Ssam curfunc = f; 55816618Ssam curframe = nil; 55916618Ssam } 56016618Ssam 56116618Ssam /* 56218231Slinton * Return the frame for the current function. 56318231Slinton * The space for the frame is allocated statically. 56418231Slinton */ 56518231Slinton 56618231Slinton public Frame curfuncframe () 56718231Slinton { 56818231Slinton static struct Frame frame; 56918231Slinton Frame frp; 57018231Slinton 57118231Slinton if (curframe == nil) { 57218231Slinton frp = findframe(curfunc); 57318231Slinton curframe = &curframerec; 57418231Slinton *curframe = *frp; 57518231Slinton } else { 57618231Slinton frp = &frame; 57718231Slinton *frp = *curframe; 57818231Slinton } 57918231Slinton return frp; 58018231Slinton } 58118231Slinton 58218231Slinton /* 58316618Ssam * Set curfunc to be N up/down the stack from its current value. 58416618Ssam */ 58516618Ssam 58616618Ssam public up (n) 58716618Ssam integer n; 58816618Ssam { 58916618Ssam integer i; 59016618Ssam Symbol f; 59116618Ssam Frame frp; 59216618Ssam boolean done; 59316618Ssam 59416618Ssam if (not isactive(program)) { 59516618Ssam error("program is not active"); 59616618Ssam } else if (curfunc == nil) { 59716618Ssam error("no current function"); 59816618Ssam } else { 59916618Ssam i = 0; 60016618Ssam f = curfunc; 60118231Slinton frp = curfuncframe(); 60216618Ssam done = false; 60316618Ssam do { 60416618Ssam if (frp == nil) { 60516618Ssam done = true; 60616618Ssam error("not that many levels"); 60716618Ssam } else if (i >= n) { 60816618Ssam done = true; 60916618Ssam curfunc = f; 61016618Ssam curframe = &curframerec; 61116618Ssam *curframe = *frp; 61218231Slinton showaggrs = false; 61318231Slinton printcallinfo(curfunc, curframe); 61416618Ssam } else if (f == program) { 61516618Ssam done = true; 61616618Ssam error("not that many levels"); 61716618Ssam } else { 61816618Ssam frp = nextfunc(frp, &f); 61916618Ssam } 62016618Ssam ++i; 62116618Ssam } while (not done); 62216618Ssam } 62316618Ssam } 62416618Ssam 62516618Ssam public down (n) 62616618Ssam integer n; 62716618Ssam { 62816618Ssam integer i, depth; 62918231Slinton Frame frp, curfrp; 63016618Ssam Symbol f; 63116618Ssam struct Frame frame; 63216618Ssam 63316618Ssam if (not isactive(program)) { 63416618Ssam error("program is not active"); 63516618Ssam } else if (curfunc == nil) { 63616618Ssam error("no current function"); 63716618Ssam } else { 63816618Ssam depth = 0; 63916618Ssam frp = &frame; 64016618Ssam getcurfunc(frp, &f); 64116618Ssam if (curframe == nil) { 64218231Slinton curfrp = findframe(curfunc); 64316618Ssam curframe = &curframerec; 64418231Slinton *curframe = *curfrp; 64516618Ssam } 64616618Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 64716618Ssam frp = nextfunc(frp, &f); 64816618Ssam ++depth; 64916618Ssam } 65016618Ssam if (f == nil or n > depth) { 65116618Ssam error("not that many levels"); 65216618Ssam } else { 65316618Ssam depth -= n; 65416618Ssam frp = &frame; 65516618Ssam getcurfunc(frp, &f); 65616618Ssam for (i = 0; i < depth; i++) { 65716618Ssam frp = nextfunc(frp, &f); 65816618Ssam assert(frp != nil); 65916618Ssam } 66016618Ssam curfunc = f; 66116618Ssam *curframe = *frp; 66218231Slinton showaggrs = false; 66318231Slinton printcallinfo(curfunc, curframe); 66416618Ssam } 66516618Ssam } 66616618Ssam } 66716618Ssam 66816618Ssam /* 6699678Slinton * Find the entry point of a procedure or function. 67033334Sdonn * 67133334Sdonn * On the VAX we add the size of the register mask (FUNCOFFSET) or 67233334Sdonn * the size of the Modula-2 internal entry sequence, on other machines 67333334Sdonn * (68000's) we add the entry sequence size (FUNCOFFSET) unless 67433334Sdonn * we're right at the beginning of the program. 6759678Slinton */ 6769678Slinton 67718231Slinton public findbeginning (f) 6789678Slinton Symbol f; 6799678Slinton { 68016618Ssam if (isinternal(f)) { 68133334Sdonn f->symvalue.funcv.beginaddr += 18; /* VAX only */ 68216618Ssam } else { 68333334Sdonn f->symvalue.funcv.beginaddr += FUNCOFFSET; 68416618Ssam } 6859678Slinton } 6869678Slinton 6879678Slinton /* 6889678Slinton * Return the address corresponding to the first line in a function. 6899678Slinton */ 6909678Slinton 6919678Slinton public Address firstline(f) 6929678Slinton Symbol f; 6939678Slinton { 6949678Slinton Address addr; 6959678Slinton 6969678Slinton addr = codeloc(f); 6979678Slinton while (linelookup(addr) == 0 and addr < objsize) { 6989678Slinton ++addr; 6999678Slinton } 7009678Slinton if (addr == objsize) { 7019678Slinton addr = -1; 7029678Slinton } 7039678Slinton return addr; 7049678Slinton } 7059678Slinton 7069678Slinton /* 7079678Slinton * Catcher drops strike three ... 7089678Slinton */ 7099678Slinton 7109678Slinton public runtofirst() 7119678Slinton { 71233334Sdonn Address addr, endaddr; 7139678Slinton 7149678Slinton addr = pc; 71533334Sdonn endaddr = objsize + CODESTART; 71633334Sdonn while (linelookup(addr) == 0 and addr < endaddr) { 7179678Slinton ++addr; 7189678Slinton } 71933334Sdonn if (addr < endaddr) { 7209678Slinton stepto(addr); 7219678Slinton } 7229678Slinton } 7239678Slinton 7249678Slinton /* 7259678Slinton * Return the address corresponding to the end of the program. 7269678Slinton * 7279678Slinton * We look for the entry to "exit". 7289678Slinton */ 7299678Slinton 7309678Slinton public Address lastaddr() 7319678Slinton { 73218231Slinton Symbol s; 7339678Slinton 7349678Slinton s = lookup(identname("exit", true)); 7359678Slinton if (s == nil) { 7369678Slinton panic("can't find exit"); 7379678Slinton } 7389678Slinton return codeloc(s); 7399678Slinton } 7409678Slinton 7419678Slinton /* 7429678Slinton * Decide if the given function is currently active. 7439678Slinton * 7449678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 7459678Slinton * Presumably information evaluated while walking the stack is active. 7469678Slinton */ 7479678Slinton 74833334Sdonn public Boolean isactive (f) 7499678Slinton Symbol f; 7509678Slinton { 75118231Slinton Boolean b; 7529678Slinton 7539678Slinton if (isfinished(process)) { 7549678Slinton b = false; 7559678Slinton } else { 75633334Sdonn if (walkingstack or f == program or f == nil or 7579678Slinton (ismodule(f) and isactive(container(f)))) { 7589678Slinton b = true; 7599678Slinton } else { 7609678Slinton b = (Boolean) (findframe(f) != nil); 7619678Slinton } 7629678Slinton } 7639678Slinton return b; 7649678Slinton } 7659678Slinton 7669678Slinton /* 7679678Slinton * Evaluate a call to a procedure. 7689678Slinton */ 7699678Slinton 77018231Slinton public callproc(exprnode, isfunc) 77118231Slinton Node exprnode; 77218231Slinton boolean isfunc; 7739678Slinton { 77418231Slinton Node procnode, arglist; 7759678Slinton Symbol proc; 77618231Slinton integer argc; 7779678Slinton 77818231Slinton procnode = exprnode->value.arg[0]; 77918231Slinton arglist = exprnode->value.arg[1]; 7809678Slinton if (procnode->op != O_SYM) { 7819678Slinton beginerrmsg(); 7829678Slinton fprintf(stderr, "can't call \""); 7839678Slinton prtree(stderr, procnode); 7849678Slinton fprintf(stderr, "\""); 7859678Slinton enderrmsg(); 7869678Slinton } 7879678Slinton assert(procnode->op == O_SYM); 7889678Slinton proc = procnode->value.sym; 7899678Slinton if (not isblock(proc)) { 7909678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 7919678Slinton } 79218231Slinton endproc.isfunc = isfunc; 79318231Slinton endproc.callnode = exprnode; 79418231Slinton endproc.cmdnode = topnode; 7959678Slinton pushenv(); 7969678Slinton pc = codeloc(proc); 7979678Slinton argc = pushargs(proc, arglist); 79833334Sdonn setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */ 7999678Slinton beginproc(proc, argc); 80018231Slinton event_once( 80118231Slinton build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 80218231Slinton buildcmdlist(build(O_PROCRTN, proc)) 80318231Slinton ); 80418231Slinton isstopped = false; 80518231Slinton if (not bpact()) { 80618231Slinton isstopped = true; 80718231Slinton cont(0); 80818231Slinton } 80918231Slinton /* 81018231Slinton * bpact() won't return true, it will call printstatus() and go back 81118231Slinton * to command input if a breakpoint is found. 81218231Slinton */ 8139678Slinton /* NOTREACHED */ 8149678Slinton } 8159678Slinton 8169678Slinton /* 8179678Slinton * Push the arguments on the process' stack. We do this by first 8189678Slinton * evaluating them on the "eval" stack, then copying into the process' 8199678Slinton * space. 8209678Slinton */ 8219678Slinton 82218231Slinton private integer pushargs(proc, arglist) 8239678Slinton Symbol proc; 8249678Slinton Node arglist; 8259678Slinton { 8269678Slinton Stack *savesp; 8279678Slinton int argc, args_size; 8289678Slinton 8299678Slinton savesp = sp; 83026324Ssam if (varIsSet("$unsafecall")) { 83126324Ssam argc = unsafe_evalargs(proc, arglist); 83226324Ssam } else { 83326324Ssam argc = evalargs(proc, arglist); 83426324Ssam } 8359678Slinton args_size = sp - savesp; 8369678Slinton setreg(STKP, reg(STKP) - args_size); 8379678Slinton dwrite(savesp, reg(STKP), args_size); 8389678Slinton sp = savesp; 8399678Slinton return argc; 8409678Slinton } 8419678Slinton 8429678Slinton /* 84316618Ssam * Check to see if an expression is correct for a given parameter. 84416618Ssam * If the given parameter is false, don't worry about type inconsistencies. 84516618Ssam * 84616618Ssam * Return whether or not it is ok. 8479678Slinton */ 8489678Slinton 84916618Ssam private boolean chkparam (actual, formal, chk) 85016618Ssam Node actual; 85116618Ssam Symbol formal; 85216618Ssam boolean chk; 85316618Ssam { 85416618Ssam boolean b; 85516618Ssam 85616618Ssam b = true; 85716618Ssam if (chk) { 85816618Ssam if (formal == nil) { 85916618Ssam beginerrmsg(); 86016618Ssam fprintf(stderr, "too many parameters"); 86116618Ssam b = false; 86216618Ssam } else if (not compatible(formal->type, actual->nodetype)) { 86316618Ssam beginerrmsg(); 86416618Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 86516618Ssam b = false; 86616618Ssam } 86716618Ssam } 86818231Slinton if (b and formal != nil and 86918231Slinton isvarparam(formal) and not isopenarray(formal->type) and 87018231Slinton not ( 87118231Slinton actual->op == O_RVAL or actual->nodetype == t_addr or 87218231Slinton ( 87318231Slinton actual->op == O_TYPERENAME and 87418231Slinton ( 87518231Slinton actual->value.arg[0]->op == O_RVAL or 87618231Slinton actual->value.arg[0]->nodetype == t_addr 87718231Slinton ) 87818231Slinton ) 87918231Slinton ) 88018231Slinton ) { 88116618Ssam beginerrmsg(); 88216618Ssam fprintf(stderr, "expected variable, found \""); 88316618Ssam prtree(stderr, actual); 88416618Ssam fprintf(stderr, "\""); 88516618Ssam b = false; 88616618Ssam } 88716618Ssam return b; 88816618Ssam } 88916618Ssam 89016618Ssam /* 89116618Ssam * Pass an expression to a particular parameter. 89216618Ssam * 89316618Ssam * Normally we pass either the address or value, but in some cases 89416618Ssam * (such as C strings) we want to copy the value onto the stack and 89516618Ssam * pass its address. 89618231Slinton * 89718231Slinton * Another special case raised by strings is the possibility that 89818231Slinton * the actual parameter will be larger than the formal, even with 89918231Slinton * appropriate type-checking. This occurs because we assume during 90018231Slinton * evaluation that strings are null-terminated, whereas some languages, 90118231Slinton * notably Pascal, do not work under that assumption. 90216618Ssam */ 90316618Ssam 90416618Ssam private passparam (actual, formal) 90516618Ssam Node actual; 90616618Ssam Symbol formal; 90716618Ssam { 90816618Ssam boolean b; 90916618Ssam Address addr; 91016618Ssam Stack *savesp; 91118231Slinton integer actsize, formsize; 91216618Ssam 91318231Slinton if (formal != nil and isvarparam(formal) and 91418231Slinton (not isopenarray(formal->type)) 91518231Slinton ) { 91616618Ssam addr = lval(actual->value.arg[0]); 91716618Ssam push(Address, addr); 91816618Ssam } else if (passaddr(formal, actual->nodetype)) { 91916618Ssam savesp = sp; 92016618Ssam eval(actual); 92118231Slinton actsize = sp - savesp; 92218231Slinton setreg(STKP, 92318231Slinton reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) 92418231Slinton ); 92518231Slinton dwrite(savesp, reg(STKP), actsize); 92616618Ssam sp = savesp; 92716618Ssam push(Address, reg(STKP)); 92816618Ssam if (formal != nil and isopenarray(formal->type)) { 92918231Slinton push(integer, actsize div size(formal->type->type)); 93016618Ssam } 93118231Slinton } else if (formal != nil) { 93218231Slinton formsize = size(formal); 93318231Slinton savesp = sp; 93418231Slinton eval(actual); 93518231Slinton actsize = sp - savesp; 93618231Slinton if (actsize > formsize) { 93718231Slinton sp -= (actsize - formsize); 93818231Slinton } 93916618Ssam } else { 94016618Ssam eval(actual); 94116618Ssam } 94216618Ssam } 94316618Ssam 94416618Ssam /* 94516618Ssam * Evaluate an argument list left-to-right. 94616618Ssam */ 94716618Ssam 94818231Slinton private integer evalargs(proc, arglist) 9499678Slinton Symbol proc; 9509678Slinton Node arglist; 9519678Slinton { 95216618Ssam Node p, actual; 95316618Ssam Symbol formal; 9549678Slinton Stack *savesp; 95518231Slinton integer count; 95616618Ssam boolean chk; 9579678Slinton 9589678Slinton savesp = sp; 9599678Slinton count = 0; 96016618Ssam formal = proc->chain; 96116618Ssam chk = (boolean) (not nosource(proc)); 9629678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 96316618Ssam assert(p->op == O_COMMA); 96416618Ssam actual = p->value.arg[0]; 96516618Ssam if (not chkparam(actual, formal, chk)) { 96616618Ssam fprintf(stderr, " in call to %s", symname(proc)); 9679678Slinton sp = savesp; 96816618Ssam enderrmsg(); 9699678Slinton } 97016618Ssam passparam(actual, formal); 97116618Ssam if (formal != nil) { 97216618Ssam formal = formal->chain; 9739678Slinton } 9749678Slinton ++count; 9759678Slinton } 97616618Ssam if (chk) { 97716618Ssam if (formal != nil) { 97816618Ssam sp = savesp; 97916618Ssam error("not enough parameters to %s", symname(proc)); 98016618Ssam } 9819678Slinton } 9829678Slinton return count; 9839678Slinton } 9849678Slinton 98526324Ssam /* 98633334Sdonn * Evaluate an argument list without any type checking. 98733334Sdonn * This is only useful for procedures with a varying number of 98833334Sdonn * arguments that are compiled -g. 98926324Ssam */ 99026324Ssam 99133334Sdonn private integer unsafe_evalargs (proc, arglist) 99226324Ssam Symbol proc; 99326324Ssam Node arglist; 99426324Ssam { 99526324Ssam Node p; 99633334Sdonn integer count; 99726324Ssam 99826324Ssam count = 0; 99926324Ssam for (p = arglist; p != nil; p = p->value.arg[1]) { 100026324Ssam assert(p->op == O_COMMA); 100126324Ssam eval(p->value.arg[0]); 100226324Ssam ++count; 100326324Ssam } 100426324Ssam return count; 100526324Ssam } 100626324Ssam 10079678Slinton public procreturn(f) 10089678Slinton Symbol f; 10099678Slinton { 101018231Slinton integer retvalsize; 101118231Slinton Node tmp; 101218231Slinton char *copy; 101318231Slinton 10149678Slinton flushoutput(); 10159678Slinton popenv(); 101618231Slinton if (endproc.isfunc) { 101718231Slinton retvalsize = size(f->type); 101818231Slinton if (retvalsize > sizeof(long)) { 101918231Slinton pushretval(retvalsize, true); 102018231Slinton copy = newarr(char, retvalsize); 102118231Slinton popn(retvalsize, copy); 102218231Slinton tmp = build(O_SCON, copy); 102318231Slinton } else { 102418231Slinton tmp = build(O_LCON, (long) (reg(0))); 102518231Slinton } 102618231Slinton tmp->nodetype = f->type; 102718231Slinton tfree(endproc.callnode); 102818231Slinton *(endproc.callnode) = *(tmp); 102918231Slinton dispose(tmp); 103018231Slinton eval(endproc.cmdnode); 103118231Slinton } else { 103218231Slinton putchar('\n'); 103318231Slinton printname(stdout, f); 103433334Sdonn printf(" returns successfully\n"); 103518231Slinton } 10369678Slinton erecover(); 10379678Slinton } 10389678Slinton 10399678Slinton /* 10409678Slinton * Push the current environment. 10419678Slinton */ 10429678Slinton 10439678Slinton private pushenv() 10449678Slinton { 10459678Slinton push(Address, pc); 10469678Slinton push(Lineno, curline); 10479678Slinton push(String, cursource); 10489678Slinton push(Boolean, isstopped); 10499678Slinton push(Symbol, curfunc); 105016618Ssam push(Frame, curframe); 105116618Ssam push(struct Frame, curframerec); 105218231Slinton push(CallEnv, endproc); 10539678Slinton push(Word, reg(PROGCTR)); 10549678Slinton push(Word, reg(STKP)); 105533334Sdonn push(Word, reg(FRP)); 10569678Slinton } 10579678Slinton 10589678Slinton /* 10599678Slinton * Pop back to the real world. 10609678Slinton */ 10619678Slinton 10629678Slinton public popenv() 10639678Slinton { 106418231Slinton String filename; 10659678Slinton 106633334Sdonn setreg(FRP, pop(Word)); 10679678Slinton setreg(STKP, pop(Word)); 10689678Slinton setreg(PROGCTR, pop(Word)); 106918231Slinton endproc = pop(CallEnv); 107016618Ssam curframerec = pop(struct Frame); 107116618Ssam curframe = pop(Frame); 10729678Slinton curfunc = pop(Symbol); 10739678Slinton isstopped = pop(Boolean); 10749678Slinton filename = pop(String); 10759678Slinton curline = pop(Lineno); 10769678Slinton pc = pop(Address); 10779678Slinton setsource(filename); 10789678Slinton } 10799678Slinton 10809678Slinton /* 10819678Slinton * Flush the debuggee's standard output. 10829678Slinton * 10839678Slinton * This is VERY dependent on the use of stdio. 10849678Slinton */ 10859678Slinton 10869678Slinton public flushoutput() 10879678Slinton { 108818231Slinton Symbol p, iob; 108918231Slinton Stack *savesp; 10909678Slinton 10919678Slinton p = lookup(identname("fflush", true)); 10929678Slinton while (p != nil and not isblock(p)) { 10939678Slinton p = p->next_sym; 10949678Slinton } 10959678Slinton if (p != nil) { 10969678Slinton iob = lookup(identname("_iob", true)); 10979678Slinton if (iob != nil) { 10989678Slinton pushenv(); 109933334Sdonn pc = codeloc(p) - FUNCOFFSET; 11009678Slinton savesp = sp; 110133334Sdonn push(long, address(iob, nil) + sizeof(*stdout)); 11029678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 11039678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 11049678Slinton sp = savesp; 11059678Slinton beginproc(p, 1); 11069678Slinton stepto(return_addr()); 11079678Slinton popenv(); 11089678Slinton } 11099678Slinton } 11109678Slinton } 1111