1*9678Slinton /* Copyright (c) 1982 Regents of the University of California */ 2*9678Slinton 3*9678Slinton static char sccsid[] = "@(#)@(#)runtime.vax.c 1.1 12/15/82"; 4*9678Slinton 5*9678Slinton /* 6*9678Slinton * Runtime organization dependent routines, mostly dealing with 7*9678Slinton * activation records. 8*9678Slinton */ 9*9678Slinton 10*9678Slinton #include "defs.h" 11*9678Slinton #include "runtime.h" 12*9678Slinton #include "process.h" 13*9678Slinton #include "machine.h" 14*9678Slinton #include "events.h" 15*9678Slinton #include "mappings.h" 16*9678Slinton #include "symbols.h" 17*9678Slinton #include "tree.h" 18*9678Slinton #include "eval.h" 19*9678Slinton #include "operators.h" 20*9678Slinton #include "object.h" 21*9678Slinton 22*9678Slinton #ifndef public 23*9678Slinton typedef struct Frame *Frame; 24*9678Slinton 25*9678Slinton #include "machine.h" 26*9678Slinton #endif 27*9678Slinton 28*9678Slinton #define NSAVEREG 12 29*9678Slinton 30*9678Slinton struct Frame { 31*9678Slinton Integer condition_handler; 32*9678Slinton Integer mask; 33*9678Slinton Address save_ap; /* argument pointer */ 34*9678Slinton Address save_fp; /* frame pointer */ 35*9678Slinton Address save_pc; /* program counter */ 36*9678Slinton Word save_reg[NSAVEREG]; /* not necessarily there */ 37*9678Slinton }; 38*9678Slinton 39*9678Slinton private Boolean walkingstack = false; 40*9678Slinton 41*9678Slinton /* 42*9678Slinton * Set a frame to the current activation record. 43*9678Slinton */ 44*9678Slinton 45*9678Slinton private getcurframe(frp) 46*9678Slinton register Frame frp; 47*9678Slinton { 48*9678Slinton register int i; 49*9678Slinton 50*9678Slinton checkref(frp); 51*9678Slinton frp->mask = reg(NREG); 52*9678Slinton frp->save_ap = reg(ARGP); 53*9678Slinton frp->save_fp = reg(FRP); 54*9678Slinton frp->save_pc = reg(PROGCTR); 55*9678Slinton for (i = 0; i < NSAVEREG; i++) { 56*9678Slinton frp->save_reg[i] = reg(i); 57*9678Slinton } 58*9678Slinton } 59*9678Slinton 60*9678Slinton /* 61*9678Slinton * Return a pointer to the next activation record up the stack. 62*9678Slinton * Return nil if there is none. 63*9678Slinton * Writes over space pointed to by given argument. 64*9678Slinton */ 65*9678Slinton 66*9678Slinton #define bis(b, n) ((b & (1 << (n))) != 0) 67*9678Slinton 68*9678Slinton private Frame nextframe(frp) 69*9678Slinton Frame frp; 70*9678Slinton { 71*9678Slinton register Frame newfrp; 72*9678Slinton struct Frame frame; 73*9678Slinton register Integer i, j, mask; 74*9678Slinton 75*9678Slinton newfrp = frp; 76*9678Slinton dread(&frame, newfrp->save_fp, sizeof(struct Frame)); 77*9678Slinton if (frame.save_fp == nil) { 78*9678Slinton newfrp = nil; 79*9678Slinton } else { 80*9678Slinton mask = ((frame.mask >> 16) & 0x0fff); 81*9678Slinton j = 0; 82*9678Slinton for (i = 0; i < NSAVEREG; i++) { 83*9678Slinton if (bis(mask, i)) { 84*9678Slinton newfrp->save_reg[i] = frame.save_reg[j]; 85*9678Slinton ++j; 86*9678Slinton } 87*9678Slinton } 88*9678Slinton newfrp->condition_handler = frame.condition_handler; 89*9678Slinton newfrp->mask = mask; 90*9678Slinton newfrp->save_ap = frame.save_ap; 91*9678Slinton newfrp->save_fp = frame.save_fp; 92*9678Slinton newfrp->save_pc = frame.save_pc; 93*9678Slinton } 94*9678Slinton return newfrp; 95*9678Slinton } 96*9678Slinton 97*9678Slinton /* 98*9678Slinton * Return the frame associated with the given function. 99*9678Slinton * If the function is nil, return the most recently activated frame. 100*9678Slinton * 101*9678Slinton * Static allocation for the frame. 102*9678Slinton */ 103*9678Slinton 104*9678Slinton public Frame findframe(f) 105*9678Slinton Symbol f; 106*9678Slinton { 107*9678Slinton register Frame frp; 108*9678Slinton static struct Frame frame; 109*9678Slinton 110*9678Slinton frp = &frame; 111*9678Slinton getcurframe(frp); 112*9678Slinton if (f != nil) { 113*9678Slinton while (frp != nil and whatblock(frp->save_pc) != f) { 114*9678Slinton frp = nextframe(frp); 115*9678Slinton } 116*9678Slinton } 117*9678Slinton return frp; 118*9678Slinton } 119*9678Slinton 120*9678Slinton /* 121*9678Slinton * Find the return address of the current procedure/function. 122*9678Slinton */ 123*9678Slinton 124*9678Slinton public Address return_addr() 125*9678Slinton { 126*9678Slinton Frame frp; 127*9678Slinton Address addr; 128*9678Slinton struct Frame frame; 129*9678Slinton 130*9678Slinton frp = &frame; 131*9678Slinton getcurframe(frp); 132*9678Slinton frp = nextframe(frp); 133*9678Slinton if (frp == nil) { 134*9678Slinton addr = 0; 135*9678Slinton } else { 136*9678Slinton addr = frp->save_pc; 137*9678Slinton } 138*9678Slinton return addr; 139*9678Slinton } 140*9678Slinton 141*9678Slinton /* 142*9678Slinton * Push the value associated with the current function. 143*9678Slinton */ 144*9678Slinton 145*9678Slinton public pushretval(len, isindirect) 146*9678Slinton Integer len; 147*9678Slinton Boolean isindirect; 148*9678Slinton { 149*9678Slinton Word r0; 150*9678Slinton 151*9678Slinton r0 = reg(0); 152*9678Slinton if (isindirect) { 153*9678Slinton rpush((Address) r0, len); 154*9678Slinton } else { 155*9678Slinton switch (len) { 156*9678Slinton case sizeof(char): 157*9678Slinton push(char, r0); 158*9678Slinton break; 159*9678Slinton 160*9678Slinton case sizeof(short): 161*9678Slinton push(short, r0); 162*9678Slinton break; 163*9678Slinton 164*9678Slinton default: 165*9678Slinton if (len == sizeof(Word)) { 166*9678Slinton push(Word, r0); 167*9678Slinton } else if (len == 2*sizeof(Word)) { 168*9678Slinton push(Word, r0); 169*9678Slinton push(Word, reg(1)); 170*9678Slinton } else { 171*9678Slinton panic("not indirect in pushretval?"); 172*9678Slinton } 173*9678Slinton break; 174*9678Slinton } 175*9678Slinton } 176*9678Slinton } 177*9678Slinton 178*9678Slinton /* 179*9678Slinton * Return the base address for locals in the given frame. 180*9678Slinton */ 181*9678Slinton 182*9678Slinton public Address locals_base(frp) 183*9678Slinton register Frame frp; 184*9678Slinton { 185*9678Slinton return (frp == nil) ? reg(FRP) : frp->save_fp; 186*9678Slinton } 187*9678Slinton 188*9678Slinton /* 189*9678Slinton * Return the base address for arguments in the given frame. 190*9678Slinton */ 191*9678Slinton 192*9678Slinton public Address args_base(frp) 193*9678Slinton register Frame frp; 194*9678Slinton { 195*9678Slinton return (frp == nil) ? reg(ARGP) : frp->save_ap; 196*9678Slinton } 197*9678Slinton 198*9678Slinton /* 199*9678Slinton * Return saved register n from the given frame. 200*9678Slinton */ 201*9678Slinton 202*9678Slinton public Word savereg(n, frp) 203*9678Slinton register Integer n; 204*9678Slinton register Frame frp; 205*9678Slinton { 206*9678Slinton register Word w; 207*9678Slinton 208*9678Slinton if (frp == nil) { 209*9678Slinton w = reg(n); 210*9678Slinton } else { 211*9678Slinton switch (n) { 212*9678Slinton case ARGP: 213*9678Slinton w = frp->save_ap; 214*9678Slinton break; 215*9678Slinton 216*9678Slinton case FRP: 217*9678Slinton w = frp->save_fp; 218*9678Slinton break; 219*9678Slinton 220*9678Slinton case STKP: 221*9678Slinton w = reg(STKP); 222*9678Slinton break; 223*9678Slinton 224*9678Slinton case PROGCTR: 225*9678Slinton w = frp->save_pc; 226*9678Slinton break; 227*9678Slinton 228*9678Slinton default: 229*9678Slinton assert(n >= 0 and n < NSAVEREG); 230*9678Slinton w = frp->save_reg[n]; 231*9678Slinton break; 232*9678Slinton } 233*9678Slinton } 234*9678Slinton return w; 235*9678Slinton } 236*9678Slinton 237*9678Slinton /* 238*9678Slinton * Return the nth argument to the current procedure. 239*9678Slinton */ 240*9678Slinton 241*9678Slinton public Word argn(n, frp) 242*9678Slinton Integer n; 243*9678Slinton Frame frp; 244*9678Slinton { 245*9678Slinton Word w; 246*9678Slinton 247*9678Slinton dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 248*9678Slinton return w; 249*9678Slinton } 250*9678Slinton 251*9678Slinton /* 252*9678Slinton * Calculate the entry address for a procedure or function parameter, 253*9678Slinton * given the address of the descriptor. 254*9678Slinton */ 255*9678Slinton 256*9678Slinton public Address fparamaddr(a) 257*9678Slinton Address a; 258*9678Slinton { 259*9678Slinton Address r; 260*9678Slinton 261*9678Slinton dread(&r, a, sizeof(r)); 262*9678Slinton return r; 263*9678Slinton } 264*9678Slinton 265*9678Slinton /* 266*9678Slinton * Print a list of currently active blocks starting with most recent. 267*9678Slinton */ 268*9678Slinton 269*9678Slinton public wherecmd() 270*9678Slinton { 271*9678Slinton walkstack(false); 272*9678Slinton } 273*9678Slinton 274*9678Slinton /* 275*9678Slinton * Dump the world to the given file. 276*9678Slinton * Like "where", but variables are dumped also. 277*9678Slinton */ 278*9678Slinton 279*9678Slinton public dump() 280*9678Slinton { 281*9678Slinton walkstack(true); 282*9678Slinton } 283*9678Slinton 284*9678Slinton /* 285*9678Slinton * Walk the stack of active procedures printing information 286*9678Slinton * about each active procedure. 287*9678Slinton */ 288*9678Slinton 289*9678Slinton #define lastfunc(f) (f == program) 290*9678Slinton 291*9678Slinton private walkstack(dumpvariables) 292*9678Slinton Boolean dumpvariables; 293*9678Slinton { 294*9678Slinton register Frame frp; 295*9678Slinton register Symbol f; 296*9678Slinton register Boolean save; 297*9678Slinton register Lineno line; 298*9678Slinton struct Frame frame; 299*9678Slinton 300*9678Slinton if (notstarted(process)) { 301*9678Slinton error("program is not active"); 302*9678Slinton } else { 303*9678Slinton save = walkingstack; 304*9678Slinton walkingstack = true; 305*9678Slinton frp = &frame; 306*9678Slinton getcurframe(frp); 307*9678Slinton f = whatblock(frp->save_pc); 308*9678Slinton do { 309*9678Slinton printf("%s", symname(f)); 310*9678Slinton printparams(f, frp); 311*9678Slinton line = srcline(frp->save_pc); 312*9678Slinton if (line != 0) { 313*9678Slinton printf(", line %d", line); 314*9678Slinton printf(" in \"%s\"\n", srcfilename(frp->save_pc)); 315*9678Slinton } else { 316*9678Slinton printf(" at 0x%x\n", frp->save_pc); 317*9678Slinton } 318*9678Slinton if (dumpvariables) { 319*9678Slinton dumpvars(f, frp); 320*9678Slinton putchar('\n'); 321*9678Slinton } 322*9678Slinton frp = nextframe(frp); 323*9678Slinton if (frp != nil) { 324*9678Slinton f = whatblock(frp->save_pc); 325*9678Slinton } 326*9678Slinton } while (frp != nil and not lastfunc(f)); 327*9678Slinton if (dumpvariables) { 328*9678Slinton printf("in \"%s\":\n", symname(program)); 329*9678Slinton dumpvars(program, nil); 330*9678Slinton putchar('\n'); 331*9678Slinton } 332*9678Slinton walkingstack = save; 333*9678Slinton } 334*9678Slinton } 335*9678Slinton 336*9678Slinton /* 337*9678Slinton * Find the entry point of a procedure or function. 338*9678Slinton */ 339*9678Slinton 340*9678Slinton public findbeginning(f) 341*9678Slinton Symbol f; 342*9678Slinton { 343*9678Slinton f->symvalue.funcv.beginaddr += 2; 344*9678Slinton } 345*9678Slinton 346*9678Slinton /* 347*9678Slinton * Return the address corresponding to the first line in a function. 348*9678Slinton */ 349*9678Slinton 350*9678Slinton public Address firstline(f) 351*9678Slinton Symbol f; 352*9678Slinton { 353*9678Slinton Address addr; 354*9678Slinton 355*9678Slinton addr = codeloc(f); 356*9678Slinton while (linelookup(addr) == 0 and addr < objsize) { 357*9678Slinton ++addr; 358*9678Slinton } 359*9678Slinton if (addr == objsize) { 360*9678Slinton addr = -1; 361*9678Slinton } 362*9678Slinton return addr; 363*9678Slinton } 364*9678Slinton 365*9678Slinton /* 366*9678Slinton * Catcher drops strike three ... 367*9678Slinton */ 368*9678Slinton 369*9678Slinton public runtofirst() 370*9678Slinton { 371*9678Slinton Address addr; 372*9678Slinton 373*9678Slinton addr = pc; 374*9678Slinton while (linelookup(addr) == 0 and addr < objsize) { 375*9678Slinton ++addr; 376*9678Slinton } 377*9678Slinton if (addr < objsize) { 378*9678Slinton stepto(addr); 379*9678Slinton } 380*9678Slinton } 381*9678Slinton 382*9678Slinton /* 383*9678Slinton * Return the address corresponding to the end of the program. 384*9678Slinton * 385*9678Slinton * We look for the entry to "exit". 386*9678Slinton */ 387*9678Slinton 388*9678Slinton public Address lastaddr() 389*9678Slinton { 390*9678Slinton register Symbol s; 391*9678Slinton 392*9678Slinton s = lookup(identname("exit", true)); 393*9678Slinton if (s == nil) { 394*9678Slinton panic("can't find exit"); 395*9678Slinton } 396*9678Slinton return codeloc(s); 397*9678Slinton } 398*9678Slinton 399*9678Slinton /* 400*9678Slinton * Decide if the given function is currently active. 401*9678Slinton * 402*9678Slinton * We avoid calls to "findframe" during a stack trace for efficiency. 403*9678Slinton * Presumably information evaluated while walking the stack is active. 404*9678Slinton */ 405*9678Slinton 406*9678Slinton public Boolean isactive(f) 407*9678Slinton Symbol f; 408*9678Slinton { 409*9678Slinton register Boolean b; 410*9678Slinton 411*9678Slinton if (isfinished(process)) { 412*9678Slinton b = false; 413*9678Slinton } else { 414*9678Slinton if (walkingstack or f == program or 415*9678Slinton (ismodule(f) and isactive(container(f)))) { 416*9678Slinton b = true; 417*9678Slinton } else { 418*9678Slinton b = (Boolean) (findframe(f) != nil); 419*9678Slinton } 420*9678Slinton } 421*9678Slinton return b; 422*9678Slinton } 423*9678Slinton 424*9678Slinton /* 425*9678Slinton * Evaluate a call to a procedure. 426*9678Slinton */ 427*9678Slinton 428*9678Slinton public callproc(procnode, arglist) 429*9678Slinton Node procnode; 430*9678Slinton Node arglist; 431*9678Slinton { 432*9678Slinton Symbol proc; 433*9678Slinton Integer argc; 434*9678Slinton 435*9678Slinton if (procnode->op != O_SYM) { 436*9678Slinton beginerrmsg(); 437*9678Slinton fprintf(stderr, "can't call \""); 438*9678Slinton prtree(stderr, procnode); 439*9678Slinton fprintf(stderr, "\""); 440*9678Slinton enderrmsg(); 441*9678Slinton } 442*9678Slinton assert(procnode->op == O_SYM); 443*9678Slinton proc = procnode->value.sym; 444*9678Slinton if (not isblock(proc)) { 445*9678Slinton error("\"%s\" is not a procedure or function", symname(proc)); 446*9678Slinton } 447*9678Slinton pushenv(); 448*9678Slinton pc = codeloc(proc); 449*9678Slinton argc = pushargs(proc, arglist); 450*9678Slinton beginproc(proc, argc); 451*9678Slinton isstopped = true; 452*9678Slinton event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 453*9678Slinton buildcmdlist(build(O_PROCRTN, proc))); 454*9678Slinton cont(); 455*9678Slinton /* NOTREACHED */ 456*9678Slinton } 457*9678Slinton 458*9678Slinton /* 459*9678Slinton * Push the arguments on the process' stack. We do this by first 460*9678Slinton * evaluating them on the "eval" stack, then copying into the process' 461*9678Slinton * space. 462*9678Slinton */ 463*9678Slinton 464*9678Slinton private Integer pushargs(proc, arglist) 465*9678Slinton Symbol proc; 466*9678Slinton Node arglist; 467*9678Slinton { 468*9678Slinton Stack *savesp; 469*9678Slinton int argc, args_size; 470*9678Slinton 471*9678Slinton savesp = sp; 472*9678Slinton argc = evalargs(proc, arglist); 473*9678Slinton args_size = sp - savesp; 474*9678Slinton setreg(STKP, reg(STKP) - args_size); 475*9678Slinton dwrite(savesp, reg(STKP), args_size); 476*9678Slinton sp = savesp; 477*9678Slinton return argc; 478*9678Slinton } 479*9678Slinton 480*9678Slinton /* 481*9678Slinton * Evaluate arguments left-to-right. 482*9678Slinton */ 483*9678Slinton 484*9678Slinton private Integer evalargs(proc, arglist) 485*9678Slinton Symbol proc; 486*9678Slinton Node arglist; 487*9678Slinton { 488*9678Slinton Node p, exp; 489*9678Slinton Symbol arg; 490*9678Slinton Stack *savesp; 491*9678Slinton Address addr; 492*9678Slinton Integer count; 493*9678Slinton 494*9678Slinton savesp = sp; 495*9678Slinton count = 0; 496*9678Slinton arg = proc->chain; 497*9678Slinton for (p = arglist; p != nil; p = p->value.arg[1]) { 498*9678Slinton if (p->op != O_COMMA) { 499*9678Slinton panic("evalargs: arglist missing comma"); 500*9678Slinton } 501*9678Slinton if (arg == nil) { 502*9678Slinton sp = savesp; 503*9678Slinton error("too many parameters to %s", symname(proc)); 504*9678Slinton } 505*9678Slinton exp = p->value.arg[0]; 506*9678Slinton if (not compatible(arg->type, exp->nodetype)) { 507*9678Slinton sp = savesp; 508*9678Slinton error("expression for parameter %s is of wrong type", symname(arg)); 509*9678Slinton } 510*9678Slinton if (arg->class == REF) { 511*9678Slinton if (exp->op != O_RVAL) { 512*9678Slinton sp = savesp; 513*9678Slinton error("variable expected for parameter \"%s\"", symname(arg)); 514*9678Slinton } 515*9678Slinton addr = lval(exp->value.arg[0]); 516*9678Slinton push(Address, addr); 517*9678Slinton } else { 518*9678Slinton eval(exp); 519*9678Slinton } 520*9678Slinton arg = arg->chain; 521*9678Slinton ++count; 522*9678Slinton } 523*9678Slinton if (arg != nil) { 524*9678Slinton sp = savesp; 525*9678Slinton error("not enough parameters to %s", symname(proc)); 526*9678Slinton } 527*9678Slinton return count; 528*9678Slinton } 529*9678Slinton 530*9678Slinton public procreturn(f) 531*9678Slinton Symbol f; 532*9678Slinton { 533*9678Slinton flushoutput(); 534*9678Slinton putchar('\n'); 535*9678Slinton printname(stdout, f); 536*9678Slinton printf(" returns successfully\n", symname(f)); 537*9678Slinton popenv(); 538*9678Slinton erecover(); 539*9678Slinton } 540*9678Slinton 541*9678Slinton /* 542*9678Slinton * Push the current environment. 543*9678Slinton */ 544*9678Slinton 545*9678Slinton private pushenv() 546*9678Slinton { 547*9678Slinton push(Address, pc); 548*9678Slinton push(Lineno, curline); 549*9678Slinton push(String, cursource); 550*9678Slinton push(Boolean, isstopped); 551*9678Slinton push(Symbol, curfunc); 552*9678Slinton push(Word, reg(PROGCTR)); 553*9678Slinton push(Word, reg(STKP)); 554*9678Slinton } 555*9678Slinton 556*9678Slinton /* 557*9678Slinton * Pop back to the real world. 558*9678Slinton */ 559*9678Slinton 560*9678Slinton public popenv() 561*9678Slinton { 562*9678Slinton register String filename; 563*9678Slinton 564*9678Slinton setreg(STKP, pop(Word)); 565*9678Slinton setreg(PROGCTR, pop(Word)); 566*9678Slinton curfunc = pop(Symbol); 567*9678Slinton isstopped = pop(Boolean); 568*9678Slinton filename = pop(String); 569*9678Slinton curline = pop(Lineno); 570*9678Slinton pc = pop(Address); 571*9678Slinton setsource(filename); 572*9678Slinton } 573*9678Slinton 574*9678Slinton /* 575*9678Slinton * Flush the debuggee's standard output. 576*9678Slinton * 577*9678Slinton * This is VERY dependent on the use of stdio. 578*9678Slinton */ 579*9678Slinton 580*9678Slinton public flushoutput() 581*9678Slinton { 582*9678Slinton register Symbol p, iob; 583*9678Slinton register Stack *savesp; 584*9678Slinton 585*9678Slinton p = lookup(identname("fflush", true)); 586*9678Slinton while (p != nil and not isblock(p)) { 587*9678Slinton p = p->next_sym; 588*9678Slinton } 589*9678Slinton if (p != nil) { 590*9678Slinton iob = lookup(identname("_iob", true)); 591*9678Slinton if (iob != nil) { 592*9678Slinton pushenv(); 593*9678Slinton pc = codeloc(p); 594*9678Slinton savesp = sp; 595*9678Slinton push(long, address(iob, nil) + sizeof(struct _iobuf)); 596*9678Slinton setreg(STKP, reg(STKP) - sizeof(long)); 597*9678Slinton dwrite(savesp, reg(STKP), sizeof(long)); 598*9678Slinton sp = savesp; 599*9678Slinton beginproc(p, 1); 600*9678Slinton stepto(return_addr()); 601*9678Slinton popenv(); 602*9678Slinton } 603*9678Slinton } 604*9678Slinton } 605