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