1*26329Ssam /* 2*26329Ssam * Copyright (c) 1985 Regents of the University of California. 3*26329Ssam * All rights reserved. The Berkeley software License Agreement 4*26329Ssam * specifies the terms and conditions for redistribution. 5*26329Ssam */ 6*26329Ssam 7*26329Ssam #ifndef lint 8*26329Ssam static char sccsid[] = "@(#)runtime.tahoe.c 5.1 (Berkeley) 02/22/86"; 9*26329Ssam #endif not lint 10*26329Ssam 11*26329Ssam static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $"; 12*26329Ssam 13*26329Ssam /* 14*26329Ssam * Runtime organization dependent routines, mostly dealing with 15*26329Ssam * activation records. 16*26329Ssam */ 17*26329Ssam 18*26329Ssam #include "defs.h" 19*26329Ssam #include "runtime.h" 20*26329Ssam #include "process.h" 21*26329Ssam #include "machine.h" 22*26329Ssam #include "events.h" 23*26329Ssam #include "mappings.h" 24*26329Ssam #include "symbols.h" 25*26329Ssam #include "tree.h" 26*26329Ssam #include "eval.h" 27*26329Ssam #include "operators.h" 28*26329Ssam #include "object.h" 29*26329Ssam #include <sys/param.h> 30*26329Ssam 31*26329Ssam #ifndef public 32*26329Ssam #include "machine.h" 33*26329Ssam 34*26329Ssam typedef struct Frame { 35*26329Ssam Address save_pc; /* program counter */ 36*26329Ssam integer mask:16; /* register save mask */ 37*26329Ssam integer removed:16; /* 4*number of arguments + 4 */ 38*26329Ssam Address save_fp; /* frame pointer */ 39*26329Ssam #define NSAVEREG 13 40*26329Ssam Word save_reg[NSAVEREG]; /* not necessarily there */ 41*26329Ssam } *Frame; 42*26329Ssam #endif 43*26329Ssam 44*26329Ssam private Frame curframe = nil; 45*26329Ssam private struct Frame curframerec; 46*26329Ssam private Boolean walkingstack = false; 47*26329Ssam 48*26329Ssam #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 49*26329Ssam 50*26329Ssam #define isstackaddr(addr) \ 51*26329Ssam (((addr) < 0xc0000000) and ((addr) > 0xc0000000 - 0x400 * UPAGES)) 52*26329Ssam 53*26329Ssam typedef struct { 54*26329Ssam Node callnode; 55*26329Ssam Node cmdnode; 56*26329Ssam boolean isfunc; 57*26329Ssam } CallEnv; 58*26329Ssam 59*26329Ssam private CallEnv endproc; 60*26329Ssam 61*26329Ssam /* 62*26329Ssam * Set a frame to the current activation record. 63*26329Ssam */ 64*26329Ssam 65*26329Ssam private getcurframe(frp) 66*26329Ssam Frame frp; 67*26329Ssam { 68*26329Ssam register int i; 69*26329Ssam long x; 70*26329Ssam 71*26329Ssam checkref(frp); 72*26329Ssam frp->save_fp = reg(FRP); 73*26329Ssam dread(&x, frp->save_fp-4, 4); 74*26329Ssam frp->mask = x >> 16; 75*26329Ssam frp->removed = x & 0xffff; 76*26329Ssam frp->save_pc = reg(PROGCTR); 77*26329Ssam for (i = 0; i < NSAVEREG; i++) { 78*26329Ssam frp->save_reg[i] = reg(i); 79*26329Ssam } 80*26329Ssam } 81*26329Ssam 82*26329Ssam /* 83*26329Ssam * Get the saved registers from one frame to another 84*26329Ssam * given mask specifying which registers were actually saved. 85*26329Ssam */ 86*26329Ssam 87*26329Ssam #define bis(b, n) ((b & (1 << (n))) != 0) 88*26329Ssam 89*26329Ssam private getsaveregs (newfrp, frp, mask) 90*26329Ssam Frame newfrp, frp; 91*26329Ssam integer mask; 92*26329Ssam { 93*26329Ssam integer i, j; 94*26329Ssam 95*26329Ssam j = 0; 96*26329Ssam for (i = 0; i < NSAVEREG; i++) { 97*26329Ssam if (bis(mask, i)) { 98*26329Ssam newfrp->save_reg[i] = frp->save_reg[j]; 99*26329Ssam ++j; 100*26329Ssam } 101*26329Ssam } 102*26329Ssam } 103*26329Ssam 104*26329Ssam /* 105*26329Ssam * Return a pointer to the next activation record up the stack. 106*26329Ssam * Return nil if there is none. 107*26329Ssam * Writes over space pointed to by given argument. 108*26329Ssam */ 109*26329Ssam 110*26329Ssam private Frame nextframe(frp) 111*26329Ssam Frame frp; 112*26329Ssam { 113*26329Ssam Frame newfrp; 114*26329Ssam struct Frame frame; 115*26329Ssam long x; 116*26329Ssam Address prev_frame, callpc; 117*26329Ssam static integer ntramp = 0; 118*26329Ssam 119*26329Ssam newfrp = frp; 120*26329Ssam prev_frame = frp->save_fp; 121*26329Ssam 122*26329Ssam /* 123*26329Ssam * The check for interrupt generated frames is taken from adb with only 124*26329Ssam * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 125*26329Ssam * gets control, then the stack does NOT look like <main, sub, sigsub>. 126*26329Ssam * 127*26329Ssam * As best I can make out it looks like: 128*26329Ssam * 129*26329Ssam * <main, (machine check exception block + sub), sysframe, sigsub>. 130*26329Ssam * 131*26329Ssam * When the signal occurs an exception block and a frame for the routine 132*26329Ssam * in which it occured are pushed on the user stack. Then another frame 133*26329Ssam * is pushed corresponding to a call from the kernel to sigsub. 134*26329Ssam * 135*26329Ssam * The addr in sub at which the exception occured is not in sub.save_pc 136*26329Ssam * but in the machine check exception block. It is at the magic address 137*26329Ssam * fp + 84. 138*26329Ssam * 139*26329Ssam * The current approach ignores the sys_frame (what adb reports as sigtramp) 140*26329Ssam * and takes the pc for sub from the exception block. This allows the 141*26329Ssam * "where" command to report <main, sub, sigsub>, which seems reasonable. 142*26329Ssam */ 143*26329Ssam 144*26329Ssam nextf: 145*26329Ssam dread(&frame, prev_frame-8, sizeof(struct Frame)); 146*26329Ssam if (ntramp == 1) { 147*26329Ssam dread(&callpc, prev_frame+44, sizeof(callpc)); 148*26329Ssam } else { 149*26329Ssam callpc = frame.save_pc; 150*26329Ssam } 151*26329Ssam if (frame.save_fp == nil or frame.save_pc == (Address) -1) { 152*26329Ssam newfrp = nil; 153*26329Ssam } else if (isstackaddr(callpc)) { 154*26329Ssam ntramp++; 155*26329Ssam prev_frame = frame.save_fp; 156*26329Ssam goto nextf; 157*26329Ssam } else { 158*26329Ssam ntramp = 0; 159*26329Ssam getsaveregs(newfrp, &frame, frame.mask); 160*26329Ssam dread(&x, frame.save_fp-4, sizeof (x)); 161*26329Ssam newfrp->mask = x >> 16; 162*26329Ssam newfrp->removed = x & 0xffff; 163*26329Ssam newfrp->save_fp = frame.save_fp; 164*26329Ssam newfrp->save_pc = callpc; 165*26329Ssam } 166*26329Ssam return newfrp; 167*26329Ssam } 168*26329Ssam 169*26329Ssam /* 170*26329Ssam * Get the current frame information in the given Frame and store the 171*26329Ssam * associated function in the given value-result parameter. 172*26329Ssam */ 173*26329Ssam 174*26329Ssam private getcurfunc (frp, fp) 175*26329Ssam Frame frp; 176*26329Ssam Symbol *fp; 177*26329Ssam { 178*26329Ssam getcurframe(frp); 179*26329Ssam *fp = whatblock(frp->save_pc); 180*26329Ssam } 181*26329Ssam 182*26329Ssam /* 183*26329Ssam * Return the frame associated with the next function up the call stack, or 184*26329Ssam * nil if there is none. The function is returned in a value-result parameter. 185*26329Ssam * For "inline" functions the statically outer function and same frame 186*26329Ssam * are returned. 187*26329Ssam */ 188*26329Ssam 189*26329Ssam public Frame nextfunc (frp, fp) 190*26329Ssam Frame frp; 191*26329Ssam Symbol *fp; 192*26329Ssam { 193*26329Ssam Symbol t; 194*26329Ssam Frame nfrp; 195*26329Ssam 196*26329Ssam t = *fp; 197*26329Ssam checkref(t); 198*26329Ssam if (isinline(t)) { 199*26329Ssam t = container(t); 200*26329Ssam nfrp = frp; 201*26329Ssam } else { 202*26329Ssam nfrp = nextframe(frp); 203*26329Ssam if (nfrp == nil) { 204*26329Ssam t = nil; 205*26329Ssam } else { 206*26329Ssam t = whatblock(nfrp->save_pc); 207*26329Ssam } 208*26329Ssam } 209*26329Ssam *fp = t; 210*26329Ssam return nfrp; 211*26329Ssam } 212*26329Ssam 213*26329Ssam /* 214*26329Ssam * Return the frame associated with the given function. 215*26329Ssam * If the function is nil, return the most recently activated frame. 216*26329Ssam * 217*26329Ssam * Static allocation for the frame. 218*26329Ssam */ 219*26329Ssam 220*26329Ssam public Frame findframe(f) 221*26329Ssam Symbol f; 222*26329Ssam { 223*26329Ssam Frame frp; 224*26329Ssam static struct Frame frame; 225*26329Ssam Symbol p; 226*26329Ssam Boolean done; 227*26329Ssam 228*26329Ssam frp = &frame; 229*26329Ssam getcurframe(frp); 230*26329Ssam if (f != nil) { 231*26329Ssam if (f == curfunc and curframe != nil) { 232*26329Ssam *frp = *curframe; 233*26329Ssam } else { 234*26329Ssam done = false; 235*26329Ssam p = whatblock(frp->save_pc); 236*26329Ssam do { 237*26329Ssam if (p == f) { 238*26329Ssam done = true; 239*26329Ssam } else if (p == program) { 240*26329Ssam done = true; 241*26329Ssam frp = nil; 242*26329Ssam } else { 243*26329Ssam frp = nextfunc(frp, &p); 244*26329Ssam if (frp == nil) { 245*26329Ssam done = true; 246*26329Ssam } 247*26329Ssam } 248*26329Ssam } while (not done); 249*26329Ssam } 250*26329Ssam } 251*26329Ssam return frp; 252*26329Ssam } 253*26329Ssam 254*26329Ssam /* 255*26329Ssam * Set the registers according to the given frame pointer. 256*26329Ssam */ 257*26329Ssam 258*26329Ssam public getnewregs (addr) 259*26329Ssam Address addr; 260*26329Ssam { 261*26329Ssam struct Frame frame; 262*26329Ssam integer i, j, mask; 263*26329Ssam 264*26329Ssam dread(&frame, addr-8, sizeof(frame)); 265*26329Ssam setreg(FRP, frame.save_fp); 266*26329Ssam setreg(PROGCTR, frame.save_pc); 267*26329Ssam mask = frame.mask; 268*26329Ssam j = 0; 269*26329Ssam for (i = 0; i < NSAVEREG; i++) { 270*26329Ssam if (bis(mask, i)) { 271*26329Ssam setreg(i, frame.save_reg[j]); 272*26329Ssam ++j; 273*26329Ssam } 274*26329Ssam } 275*26329Ssam pc = frame.save_pc; 276*26329Ssam setcurfunc(whatblock(pc)); 277*26329Ssam } 278*26329Ssam 279*26329Ssam /* 280*26329Ssam * Find the return address of the current procedure/function. 281*26329Ssam */ 282*26329Ssam 283*26329Ssam public Address return_addr() 284*26329Ssam { 285*26329Ssam Frame frp; 286*26329Ssam Address addr; 287*26329Ssam struct Frame frame; 288*26329Ssam 289*26329Ssam frp = &frame; 290*26329Ssam getcurframe(frp); 291*26329Ssam frp = nextframe(frp); 292*26329Ssam if (frp == nil) { 293*26329Ssam addr = 0; 294*26329Ssam } else { 295*26329Ssam addr = frp->save_pc; 296*26329Ssam } 297*26329Ssam return addr; 298*26329Ssam } 299*26329Ssam 300*26329Ssam /* 301*26329Ssam * Push the value associated with the current function. 302*26329Ssam */ 303*26329Ssam 304*26329Ssam public pushretval(len, isindirect) 305*26329Ssam integer len; 306*26329Ssam boolean isindirect; 307*26329Ssam { 308*26329Ssam Word r0; 309*26329Ssam 310*26329Ssam r0 = reg(0); 311*26329Ssam if (isindirect) { 312*26329Ssam rpush((Address) r0, len); 313*26329Ssam } else { 314*26329Ssam switch (len) { 315*26329Ssam case sizeof(char): 316*26329Ssam push(char, r0); 317*26329Ssam break; 318*26329Ssam 319*26329Ssam case sizeof(short): 320*26329Ssam push(short, r0); 321*26329Ssam break; 322*26329Ssam 323*26329Ssam default: 324*26329Ssam if (len == sizeof(Word)) { 325*26329Ssam push(Word, r0); 326*26329Ssam } else if (len == 2*sizeof(Word)) { 327*26329Ssam push(Word, r0); 328*26329Ssam push(Word, reg(1)); 329*26329Ssam } else { 330*26329Ssam error("[internal error: bad size %d in pushretval]", len); 331*26329Ssam } 332*26329Ssam break; 333*26329Ssam } 334*26329Ssam } 335*26329Ssam } 336*26329Ssam 337*26329Ssam /* 338*26329Ssam * Return the base address for locals in the given frame. 339*26329Ssam */ 340*26329Ssam 341*26329Ssam public Address locals_base(frp) 342*26329Ssam Frame frp; 343*26329Ssam { 344*26329Ssam return (frp == nil ? reg(FRP) : frp->save_fp); 345*26329Ssam } 346*26329Ssam 347*26329Ssam /* 348*26329Ssam * Return the base address for arguments in the given frame. 349*26329Ssam */ 350*26329Ssam 351*26329Ssam public Address args_base(frp) 352*26329Ssam Frame frp; 353*26329Ssam { 354*26329Ssam return (frp == nil ? reg(FRP) : frp->save_fp); 355*26329Ssam } 356*26329Ssam 357*26329Ssam /* 358*26329Ssam * Return saved register n from the given frame. 359*26329Ssam */ 360*26329Ssam 361*26329Ssam public Word savereg(n, frp) 362*26329Ssam integer n; 363*26329Ssam Frame frp; 364*26329Ssam { 365*26329Ssam Word w; 366*26329Ssam 367*26329Ssam if (frp == nil) { 368*26329Ssam w = reg(n); 369*26329Ssam } else { 370*26329Ssam switch (n) { 371*26329Ssam 372*26329Ssam case FRP: 373*26329Ssam w = frp->save_fp; 374*26329Ssam break; 375*26329Ssam 376*26329Ssam case STKP: 377*26329Ssam w = reg(STKP); 378*26329Ssam break; 379*26329Ssam 380*26329Ssam case PROGCTR: 381*26329Ssam w = frp->save_pc; 382*26329Ssam break; 383*26329Ssam 384*26329Ssam default: 385*26329Ssam assert(n >= 0 and n < NSAVEREG); 386*26329Ssam w = frp->save_reg[n]; 387*26329Ssam break; 388*26329Ssam } 389*26329Ssam } 390*26329Ssam return w; 391*26329Ssam } 392*26329Ssam 393*26329Ssam /* 394*26329Ssam * Return the nth argument to the current procedure. 395*26329Ssam */ 396*26329Ssam 397*26329Ssam public Word argn(n, frp) 398*26329Ssam integer n; 399*26329Ssam Frame frp; 400*26329Ssam { 401*26329Ssam Word w; 402*26329Ssam 403*26329Ssam dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 404*26329Ssam return w; 405*26329Ssam } 406*26329Ssam 407*26329Ssam /* 408*26329Ssam * Print a list of currently active blocks starting with most recent. 409*26329Ssam */ 410*26329Ssam 411*26329Ssam public wherecmd() 412*26329Ssam { 413*26329Ssam walkstack(false); 414*26329Ssam } 415*26329Ssam 416*26329Ssam /* 417*26329Ssam * Print the variables in the given frame or the current one if nil. 418*26329Ssam */ 419*26329Ssam 420*26329Ssam public dump (func) 421*26329Ssam Symbol func; 422*26329Ssam { 423*26329Ssam Symbol f; 424*26329Ssam Frame frp; 425*26329Ssam 426*26329Ssam if (func == nil) { 427*26329Ssam f = curfunc; 428*26329Ssam if (curframe != nil) { 429*26329Ssam frp = curframe; 430*26329Ssam } else { 431*26329Ssam frp = findframe(f); 432*26329Ssam } 433*26329Ssam } else { 434*26329Ssam f = func; 435*26329Ssam frp = findframe(f); 436*26329Ssam } 437*26329Ssam showaggrs = true; 438*26329Ssam printcallinfo(f, frp); 439*26329Ssam dumpvars(f, frp); 440*26329Ssam } 441*26329Ssam 442*26329Ssam /* 443*26329Ssam * Dump all values. 444*26329Ssam */ 445*26329Ssam 446*26329Ssam public dumpall () 447*26329Ssam { 448*26329Ssam walkstack(true); 449*26329Ssam } 450*26329Ssam 451*26329Ssam /* 452*26329Ssam * Walk the stack of active procedures printing information 453*26329Ssam * about each active procedure. 454*26329Ssam */ 455*26329Ssam 456*26329Ssam private walkstack(dumpvariables) 457*26329Ssam Boolean dumpvariables; 458*26329Ssam { 459*26329Ssam Frame frp; 460*26329Ssam boolean save; 461*26329Ssam Symbol f; 462*26329Ssam struct Frame frame; 463*26329Ssam 464*26329Ssam if (notstarted(process) or isfinished(process)) { 465*26329Ssam error("program is not active"); 466*26329Ssam } else { 467*26329Ssam save = walkingstack; 468*26329Ssam walkingstack = true; 469*26329Ssam showaggrs = dumpvariables; 470*26329Ssam frp = &frame; 471*26329Ssam getcurfunc(frp, &f); 472*26329Ssam for (;;) { 473*26329Ssam printcallinfo(f, frp); 474*26329Ssam if (dumpvariables) { 475*26329Ssam dumpvars(f, frp); 476*26329Ssam putchar('\n'); 477*26329Ssam } 478*26329Ssam frp = nextfunc(frp, &f); 479*26329Ssam if (frp == nil or f == program) { 480*26329Ssam break; 481*26329Ssam } 482*26329Ssam } 483*26329Ssam if (dumpvariables) { 484*26329Ssam printf("in \"%s\":\n", symname(program)); 485*26329Ssam dumpvars(program, nil); 486*26329Ssam putchar('\n'); 487*26329Ssam } 488*26329Ssam walkingstack = save; 489*26329Ssam } 490*26329Ssam } 491*26329Ssam 492*26329Ssam /* 493*26329Ssam * Print out the information about a call, i.e., 494*26329Ssam * routine name, parameter values, and source location. 495*26329Ssam */ 496*26329Ssam 497*26329Ssam private printcallinfo (f, frp) 498*26329Ssam Symbol f; 499*26329Ssam Frame frp; 500*26329Ssam { 501*26329Ssam Lineno line; 502*26329Ssam Address savepc; 503*26329Ssam 504*26329Ssam savepc = frp->save_pc; 505*26329Ssam if (frp->save_fp != reg(FRP)) { 506*26329Ssam savepc -= 1; 507*26329Ssam } 508*26329Ssam printname(stdout, f); 509*26329Ssam if (not isinline(f)) { 510*26329Ssam printparams(f, frp); 511*26329Ssam } 512*26329Ssam line = srcline(savepc); 513*26329Ssam if (line != 0) { 514*26329Ssam printf(", line %d", line); 515*26329Ssam printf(" in \"%s\"\n", srcfilename(savepc)); 516*26329Ssam } else { 517*26329Ssam printf(" at 0x%x\n", savepc); 518*26329Ssam } 519*26329Ssam } 520*26329Ssam 521*26329Ssam /* 522*26329Ssam * Set the current function to the given symbol. 523*26329Ssam * We must adjust "curframe" so that subsequent operations are 524*26329Ssam * not confused; for simplicity we simply clear it. 525*26329Ssam */ 526*26329Ssam 527*26329Ssam public setcurfunc (f) 528*26329Ssam Symbol f; 529*26329Ssam { 530*26329Ssam curfunc = f; 531*26329Ssam curframe = nil; 532*26329Ssam } 533*26329Ssam 534*26329Ssam /* 535*26329Ssam * Return the frame for the current function. 536*26329Ssam * The space for the frame is allocated statically. 537*26329Ssam */ 538*26329Ssam 539*26329Ssam public Frame curfuncframe () 540*26329Ssam { 541*26329Ssam static struct Frame frame; 542*26329Ssam Frame frp; 543*26329Ssam 544*26329Ssam if (curframe == nil) { 545*26329Ssam frp = findframe(curfunc); 546*26329Ssam curframe = &curframerec; 547*26329Ssam *curframe = *frp; 548*26329Ssam } else { 549*26329Ssam frp = &frame; 550*26329Ssam *frp = *curframe; 551*26329Ssam } 552*26329Ssam return frp; 553*26329Ssam } 554*26329Ssam 555*26329Ssam /* 556*26329Ssam * Set curfunc to be N up/down the stack from its current value. 557*26329Ssam */ 558*26329Ssam 559*26329Ssam public up (n) 560*26329Ssam integer n; 561*26329Ssam { 562*26329Ssam integer i; 563*26329Ssam Symbol f; 564*26329Ssam Frame frp; 565*26329Ssam boolean done; 566*26329Ssam 567*26329Ssam if (not isactive(program)) { 568*26329Ssam error("program is not active"); 569*26329Ssam } else if (curfunc == nil) { 570*26329Ssam error("no current function"); 571*26329Ssam } else { 572*26329Ssam i = 0; 573*26329Ssam f = curfunc; 574*26329Ssam frp = curfuncframe(); 575*26329Ssam done = false; 576*26329Ssam do { 577*26329Ssam if (frp == nil) { 578*26329Ssam done = true; 579*26329Ssam error("not that many levels"); 580*26329Ssam } else if (i >= n) { 581*26329Ssam done = true; 582*26329Ssam curfunc = f; 583*26329Ssam curframe = &curframerec; 584*26329Ssam *curframe = *frp; 585*26329Ssam showaggrs = false; 586*26329Ssam printcallinfo(curfunc, curframe); 587*26329Ssam } else if (f == program) { 588*26329Ssam done = true; 589*26329Ssam error("not that many levels"); 590*26329Ssam } else { 591*26329Ssam frp = nextfunc(frp, &f); 592*26329Ssam } 593*26329Ssam ++i; 594*26329Ssam } while (not done); 595*26329Ssam } 596*26329Ssam } 597*26329Ssam 598*26329Ssam public down (n) 599*26329Ssam integer n; 600*26329Ssam { 601*26329Ssam integer i, depth; 602*26329Ssam Frame frp, curfrp; 603*26329Ssam Symbol f; 604*26329Ssam struct Frame frame; 605*26329Ssam 606*26329Ssam if (not isactive(program)) { 607*26329Ssam error("program is not active"); 608*26329Ssam } else if (curfunc == nil) { 609*26329Ssam error("no current function"); 610*26329Ssam } else { 611*26329Ssam depth = 0; 612*26329Ssam frp = &frame; 613*26329Ssam getcurfunc(frp, &f); 614*26329Ssam if (curframe == nil) { 615*26329Ssam curfrp = findframe(curfunc); 616*26329Ssam curframe = &curframerec; 617*26329Ssam *curframe = *curfrp; 618*26329Ssam } 619*26329Ssam while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 620*26329Ssam frp = nextfunc(frp, &f); 621*26329Ssam ++depth; 622*26329Ssam } 623*26329Ssam if (f == nil or n > depth) { 624*26329Ssam error("not that many levels"); 625*26329Ssam } else { 626*26329Ssam depth -= n; 627*26329Ssam frp = &frame; 628*26329Ssam getcurfunc(frp, &f); 629*26329Ssam for (i = 0; i < depth; i++) { 630*26329Ssam frp = nextfunc(frp, &f); 631*26329Ssam assert(frp != nil); 632*26329Ssam } 633*26329Ssam curfunc = f; 634*26329Ssam *curframe = *frp; 635*26329Ssam showaggrs = false; 636*26329Ssam printcallinfo(curfunc, curframe); 637*26329Ssam } 638*26329Ssam } 639*26329Ssam } 640*26329Ssam 641*26329Ssam /* 642*26329Ssam * Find the entry point of a procedure or function. 643*26329Ssam */ 644*26329Ssam 645*26329Ssam public findbeginning (f) 646*26329Ssam Symbol f; 647*26329Ssam { 648*26329Ssam if (isinternal(f)) { 649*26329Ssam f->symvalue.funcv.beginaddr += 15; 650*26329Ssam } else { 651*26329Ssam f->symvalue.funcv.beginaddr += 2; 652*26329Ssam } 653*26329Ssam } 654*26329Ssam 655*26329Ssam /* 656*26329Ssam * Return the address corresponding to the first line in a function. 657*26329Ssam */ 658*26329Ssam 659*26329Ssam public Address firstline(f) 660*26329Ssam Symbol f; 661*26329Ssam { 662*26329Ssam Address addr; 663*26329Ssam 664*26329Ssam addr = codeloc(f); 665*26329Ssam while (linelookup(addr) == 0 and addr < objsize) { 666*26329Ssam ++addr; 667*26329Ssam } 668*26329Ssam if (addr == objsize) { 669*26329Ssam addr = -1; 670*26329Ssam } 671*26329Ssam return addr; 672*26329Ssam } 673*26329Ssam 674*26329Ssam /* 675*26329Ssam * Catcher drops strike three ... 676*26329Ssam */ 677*26329Ssam 678*26329Ssam public runtofirst() 679*26329Ssam { 680*26329Ssam Address addr; 681*26329Ssam 682*26329Ssam addr = pc; 683*26329Ssam while (linelookup(addr) == 0 and addr < objsize) { 684*26329Ssam ++addr; 685*26329Ssam } 686*26329Ssam if (addr < objsize) { 687*26329Ssam stepto(addr); 688*26329Ssam } 689*26329Ssam } 690*26329Ssam 691*26329Ssam /* 692*26329Ssam * Return the address corresponding to the end of the program. 693*26329Ssam * 694*26329Ssam * We look for the entry to "exit". 695*26329Ssam */ 696*26329Ssam 697*26329Ssam public Address lastaddr() 698*26329Ssam { 699*26329Ssam Symbol s; 700*26329Ssam 701*26329Ssam s = lookup(identname("exit", true)); 702*26329Ssam if (s == nil) { 703*26329Ssam panic("can't find exit"); 704*26329Ssam } 705*26329Ssam return codeloc(s); 706*26329Ssam } 707*26329Ssam 708*26329Ssam /* 709*26329Ssam * Decide if the given function is currently active. 710*26329Ssam * 711*26329Ssam * We avoid calls to "findframe" during a stack trace for efficiency. 712*26329Ssam * Presumably information evaluated while walking the stack is active. 713*26329Ssam */ 714*26329Ssam 715*26329Ssam public Boolean isactive(f) 716*26329Ssam Symbol f; 717*26329Ssam { 718*26329Ssam Boolean b; 719*26329Ssam 720*26329Ssam if (isfinished(process)) { 721*26329Ssam b = false; 722*26329Ssam } else { 723*26329Ssam if (walkingstack or f == program or 724*26329Ssam (ismodule(f) and isactive(container(f)))) { 725*26329Ssam b = true; 726*26329Ssam } else { 727*26329Ssam b = (Boolean) (findframe(f) != nil); 728*26329Ssam } 729*26329Ssam } 730*26329Ssam return b; 731*26329Ssam } 732*26329Ssam 733*26329Ssam /* 734*26329Ssam * Evaluate a call to a procedure. 735*26329Ssam */ 736*26329Ssam 737*26329Ssam public callproc(exprnode, isfunc) 738*26329Ssam Node exprnode; 739*26329Ssam boolean isfunc; 740*26329Ssam { 741*26329Ssam Node procnode, arglist; 742*26329Ssam Symbol proc; 743*26329Ssam integer argc; 744*26329Ssam 745*26329Ssam procnode = exprnode->value.arg[0]; 746*26329Ssam arglist = exprnode->value.arg[1]; 747*26329Ssam if (procnode->op != O_SYM) { 748*26329Ssam beginerrmsg(); 749*26329Ssam fprintf(stderr, "can't call \""); 750*26329Ssam prtree(stderr, procnode); 751*26329Ssam fprintf(stderr, "\""); 752*26329Ssam enderrmsg(); 753*26329Ssam } 754*26329Ssam assert(procnode->op == O_SYM); 755*26329Ssam proc = procnode->value.sym; 756*26329Ssam if (not isblock(proc)) { 757*26329Ssam error("\"%s\" is not a procedure or function", symname(proc)); 758*26329Ssam } 759*26329Ssam endproc.isfunc = isfunc; 760*26329Ssam endproc.callnode = exprnode; 761*26329Ssam endproc.cmdnode = topnode; 762*26329Ssam pushenv(); 763*26329Ssam pc = codeloc(proc); 764*26329Ssam argc = pushargs(proc, arglist); 765*26329Ssam beginproc(proc, argc); 766*26329Ssam event_once( 767*26329Ssam build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 768*26329Ssam buildcmdlist(build(O_PROCRTN, proc)) 769*26329Ssam ); 770*26329Ssam isstopped = false; 771*26329Ssam if (not bpact()) { 772*26329Ssam isstopped = true; 773*26329Ssam cont(0); 774*26329Ssam } 775*26329Ssam /* 776*26329Ssam * bpact() won't return true, it will call printstatus() and go back 777*26329Ssam * to command input if a breakpoint is found. 778*26329Ssam */ 779*26329Ssam /* NOTREACHED */ 780*26329Ssam } 781*26329Ssam 782*26329Ssam /* 783*26329Ssam * Push the arguments on the process' stack. We do this by first 784*26329Ssam * evaluating them on the "eval" stack, then copying into the process' 785*26329Ssam * space. 786*26329Ssam */ 787*26329Ssam 788*26329Ssam private integer pushargs(proc, arglist) 789*26329Ssam Symbol proc; 790*26329Ssam Node arglist; 791*26329Ssam { 792*26329Ssam Stack *savesp; 793*26329Ssam int argc, args_size; 794*26329Ssam 795*26329Ssam savesp = sp; 796*26329Ssam argc = evalargs(proc, arglist); 797*26329Ssam args_size = sp - savesp; 798*26329Ssam setreg(STKP, reg(STKP) - args_size); 799*26329Ssam dwrite(savesp, reg(STKP), args_size); 800*26329Ssam sp = savesp; 801*26329Ssam return argc; 802*26329Ssam } 803*26329Ssam 804*26329Ssam /* 805*26329Ssam * Check to see if an expression is correct for a given parameter. 806*26329Ssam * If the given parameter is false, don't worry about type inconsistencies. 807*26329Ssam * 808*26329Ssam * Return whether or not it is ok. 809*26329Ssam */ 810*26329Ssam 811*26329Ssam private boolean chkparam (actual, formal, chk) 812*26329Ssam Node actual; 813*26329Ssam Symbol formal; 814*26329Ssam boolean chk; 815*26329Ssam { 816*26329Ssam boolean b; 817*26329Ssam 818*26329Ssam b = true; 819*26329Ssam if (chk) { 820*26329Ssam if (formal == nil) { 821*26329Ssam beginerrmsg(); 822*26329Ssam fprintf(stderr, "too many parameters"); 823*26329Ssam b = false; 824*26329Ssam } else if (not compatible(formal->type, actual->nodetype)) { 825*26329Ssam beginerrmsg(); 826*26329Ssam fprintf(stderr, "type mismatch for %s", symname(formal)); 827*26329Ssam b = false; 828*26329Ssam } 829*26329Ssam } 830*26329Ssam if (b and formal != nil and 831*26329Ssam isvarparam(formal) and not isopenarray(formal->type) and 832*26329Ssam not ( 833*26329Ssam actual->op == O_RVAL or actual->nodetype == t_addr or 834*26329Ssam ( 835*26329Ssam actual->op == O_TYPERENAME and 836*26329Ssam ( 837*26329Ssam actual->value.arg[0]->op == O_RVAL or 838*26329Ssam actual->value.arg[0]->nodetype == t_addr 839*26329Ssam ) 840*26329Ssam ) 841*26329Ssam ) 842*26329Ssam ) { 843*26329Ssam beginerrmsg(); 844*26329Ssam fprintf(stderr, "expected variable, found \""); 845*26329Ssam prtree(stderr, actual); 846*26329Ssam fprintf(stderr, "\""); 847*26329Ssam b = false; 848*26329Ssam } 849*26329Ssam return b; 850*26329Ssam } 851*26329Ssam 852*26329Ssam /* 853*26329Ssam * Pass an expression to a particular parameter. 854*26329Ssam * 855*26329Ssam * Normally we pass either the address or value, but in some cases 856*26329Ssam * (such as C strings) we want to copy the value onto the stack and 857*26329Ssam * pass its address. 858*26329Ssam * 859*26329Ssam * Another special case raised by strings is the possibility that 860*26329Ssam * the actual parameter will be larger than the formal, even with 861*26329Ssam * appropriate type-checking. This occurs because we assume during 862*26329Ssam * evaluation that strings are null-terminated, whereas some languages, 863*26329Ssam * notably Pascal, do not work under that assumption. 864*26329Ssam */ 865*26329Ssam 866*26329Ssam private passparam (actual, formal) 867*26329Ssam Node actual; 868*26329Ssam Symbol formal; 869*26329Ssam { 870*26329Ssam boolean b; 871*26329Ssam Address addr; 872*26329Ssam Stack *savesp; 873*26329Ssam integer actsize, formsize; 874*26329Ssam 875*26329Ssam if (formal != nil and isvarparam(formal) and 876*26329Ssam (not isopenarray(formal->type)) 877*26329Ssam ) { 878*26329Ssam addr = lval(actual->value.arg[0]); 879*26329Ssam push(Address, addr); 880*26329Ssam } else if (passaddr(formal, actual->nodetype)) { 881*26329Ssam savesp = sp; 882*26329Ssam eval(actual); 883*26329Ssam actsize = sp - savesp; 884*26329Ssam setreg(STKP, reg(STKP) - roundup(actsize, sizeof (Word))); 885*26329Ssam dwrite(savesp, reg(STKP), actsize); 886*26329Ssam sp = savesp; 887*26329Ssam push(Address, reg(STKP)); 888*26329Ssam if (formal != nil and isopenarray(formal->type)) { 889*26329Ssam push(integer, actsize div size(formal->type->type)); 890*26329Ssam } 891*26329Ssam } else if (formal != nil) { 892*26329Ssam formsize = size(formal); 893*26329Ssam savesp = sp; 894*26329Ssam eval(actual); 895*26329Ssam actsize = sp - savesp; 896*26329Ssam if (actsize > formsize) { 897*26329Ssam sp -= (actsize - formsize); 898*26329Ssam } 899*26329Ssam } else { 900*26329Ssam eval(actual); 901*26329Ssam } 902*26329Ssam } 903*26329Ssam 904*26329Ssam /* 905*26329Ssam * Evaluate an argument list left-to-right. 906*26329Ssam */ 907*26329Ssam 908*26329Ssam private integer evalargs(proc, arglist) 909*26329Ssam Symbol proc; 910*26329Ssam Node arglist; 911*26329Ssam { 912*26329Ssam Node p, actual; 913*26329Ssam Symbol formal; 914*26329Ssam Stack *savesp; 915*26329Ssam integer count; 916*26329Ssam boolean chk; 917*26329Ssam 918*26329Ssam savesp = sp; 919*26329Ssam count = 0; 920*26329Ssam formal = proc->chain; 921*26329Ssam chk = (boolean) (not nosource(proc)); 922*26329Ssam for (p = arglist; p != nil; p = p->value.arg[1]) { 923*26329Ssam assert(p->op == O_COMMA); 924*26329Ssam actual = p->value.arg[0]; 925*26329Ssam if (not chkparam(actual, formal, chk)) { 926*26329Ssam fprintf(stderr, " in call to %s", symname(proc)); 927*26329Ssam sp = savesp; 928*26329Ssam enderrmsg(); 929*26329Ssam } 930*26329Ssam passparam(actual, formal); 931*26329Ssam if (formal != nil) { 932*26329Ssam formal = formal->chain; 933*26329Ssam } 934*26329Ssam ++count; 935*26329Ssam } 936*26329Ssam if (chk) { 937*26329Ssam if (formal != nil) { 938*26329Ssam sp = savesp; 939*26329Ssam error("not enough parameters to %s", symname(proc)); 940*26329Ssam } 941*26329Ssam } 942*26329Ssam return count; 943*26329Ssam } 944*26329Ssam 945*26329Ssam public procreturn(f) 946*26329Ssam Symbol f; 947*26329Ssam { 948*26329Ssam integer retvalsize; 949*26329Ssam Node tmp; 950*26329Ssam char *copy; 951*26329Ssam 952*26329Ssam flushoutput(); 953*26329Ssam popenv(); 954*26329Ssam if (endproc.isfunc) { 955*26329Ssam retvalsize = size(f->type); 956*26329Ssam if (retvalsize > sizeof(long)) { 957*26329Ssam pushretval(retvalsize, true); 958*26329Ssam copy = newarr(char, retvalsize); 959*26329Ssam popn(retvalsize, copy); 960*26329Ssam tmp = build(O_SCON, copy); 961*26329Ssam } else { 962*26329Ssam tmp = build(O_LCON, (long) (reg(0))); 963*26329Ssam } 964*26329Ssam tmp->nodetype = f->type; 965*26329Ssam tfree(endproc.callnode); 966*26329Ssam *(endproc.callnode) = *(tmp); 967*26329Ssam dispose(tmp); 968*26329Ssam eval(endproc.cmdnode); 969*26329Ssam } else { 970*26329Ssam putchar('\n'); 971*26329Ssam printname(stdout, f); 972*26329Ssam printf(" returns successfully\n", symname(f)); 973*26329Ssam } 974*26329Ssam erecover(); 975*26329Ssam } 976*26329Ssam 977*26329Ssam /* 978*26329Ssam * Push the current environment. 979*26329Ssam */ 980*26329Ssam 981*26329Ssam private pushenv() 982*26329Ssam { 983*26329Ssam push(Address, pc); 984*26329Ssam push(Lineno, curline); 985*26329Ssam push(String, cursource); 986*26329Ssam push(Boolean, isstopped); 987*26329Ssam push(Symbol, curfunc); 988*26329Ssam push(Frame, curframe); 989*26329Ssam push(struct Frame, curframerec); 990*26329Ssam push(CallEnv, endproc); 991*26329Ssam push(Word, reg(PROGCTR)); 992*26329Ssam push(Word, reg(STKP)); 993*26329Ssam } 994*26329Ssam 995*26329Ssam /* 996*26329Ssam * Pop back to the real world. 997*26329Ssam */ 998*26329Ssam 999*26329Ssam public popenv() 1000*26329Ssam { 1001*26329Ssam String filename; 1002*26329Ssam 1003*26329Ssam setreg(STKP, pop(Word)); 1004*26329Ssam setreg(PROGCTR, pop(Word)); 1005*26329Ssam endproc = pop(CallEnv); 1006*26329Ssam curframerec = pop(struct Frame); 1007*26329Ssam curframe = pop(Frame); 1008*26329Ssam curfunc = pop(Symbol); 1009*26329Ssam isstopped = pop(Boolean); 1010*26329Ssam filename = pop(String); 1011*26329Ssam curline = pop(Lineno); 1012*26329Ssam pc = pop(Address); 1013*26329Ssam setsource(filename); 1014*26329Ssam } 1015*26329Ssam 1016*26329Ssam /* 1017*26329Ssam * Flush the debuggee's standard output. 1018*26329Ssam * 1019*26329Ssam * This is VERY dependent on the use of stdio. 1020*26329Ssam */ 1021*26329Ssam 1022*26329Ssam public flushoutput() 1023*26329Ssam { 1024*26329Ssam Symbol p, iob; 1025*26329Ssam Stack *savesp; 1026*26329Ssam 1027*26329Ssam p = lookup(identname("fflush", true)); 1028*26329Ssam while (p != nil and not isblock(p)) { 1029*26329Ssam p = p->next_sym; 1030*26329Ssam } 1031*26329Ssam if (p != nil) { 1032*26329Ssam iob = lookup(identname("_iob", true)); 1033*26329Ssam if (iob != nil) { 1034*26329Ssam pushenv(); 1035*26329Ssam pc = codeloc(p); 1036*26329Ssam savesp = sp; 1037*26329Ssam push(long, address(iob, nil) + sizeof(struct _iobuf)); 1038*26329Ssam setreg(STKP, reg(STKP) - sizeof(long)); 1039*26329Ssam dwrite(savesp, reg(STKP), sizeof(long)); 1040*26329Ssam sp = savesp; 1041*26329Ssam beginproc(p, 1); 1042*26329Ssam stepto(return_addr()); 1043*26329Ssam popenv(); 1044*26329Ssam } 1045*26329Ssam } 1046*26329Ssam } 1047