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