1*9662Slinton /* Copyright (c) 1982 Regents of the University of California */ 2*9662Slinton 3*9662Slinton static char sccsid[] = "@(#)@(#)eval.c 1.1 12/15/82"; 4*9662Slinton 5*9662Slinton /* 6*9662Slinton * Tree evaluation. 7*9662Slinton */ 8*9662Slinton 9*9662Slinton #include "defs.h" 10*9662Slinton #include "tree.h" 11*9662Slinton #include "operators.h" 12*9662Slinton #include "eval.h" 13*9662Slinton #include "events.h" 14*9662Slinton #include "symbols.h" 15*9662Slinton #include "scanner.h" 16*9662Slinton #include "source.h" 17*9662Slinton #include "object.h" 18*9662Slinton #include "mappings.h" 19*9662Slinton #include "process.h" 20*9662Slinton #include "machine.h" 21*9662Slinton #include <signal.h> 22*9662Slinton 23*9662Slinton #ifndef public 24*9662Slinton 25*9662Slinton #include "machine.h" 26*9662Slinton 27*9662Slinton #define STACKSIZE 2000 28*9662Slinton 29*9662Slinton typedef Char Stack; 30*9662Slinton 31*9662Slinton #define push(type, value) { \ 32*9662Slinton ((type *) (sp += sizeof(type)))[-1] = (value); \ 33*9662Slinton } 34*9662Slinton 35*9662Slinton #define pop(type) ( \ 36*9662Slinton (*((type *) (sp -= sizeof(type)))) \ 37*9662Slinton ) 38*9662Slinton 39*9662Slinton #define alignstack() { \ 40*9662Slinton sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \ 41*9662Slinton } 42*9662Slinton 43*9662Slinton #endif 44*9662Slinton 45*9662Slinton public Stack stack[STACKSIZE]; 46*9662Slinton public Stack *sp = &stack[0]; 47*9662Slinton 48*9662Slinton #define chksp() \ 49*9662Slinton { \ 50*9662Slinton if (sp < &stack[0]) { \ 51*9662Slinton panic("stack underflow"); \ 52*9662Slinton } \ 53*9662Slinton } 54*9662Slinton 55*9662Slinton #define poparg(n, r, fr) { \ 56*9662Slinton eval(p->value.arg[n]); \ 57*9662Slinton if (isreal(p->op)) { \ 58*9662Slinton fr = pop(double); \ 59*9662Slinton } else if (isint(p->op)) { \ 60*9662Slinton r = popsmall(p->value.arg[n]->nodetype); \ 61*9662Slinton } \ 62*9662Slinton } 63*9662Slinton 64*9662Slinton #define Boolrep char /* underlying representation type for booleans */ 65*9662Slinton 66*9662Slinton /* 67*9662Slinton * Evaluate a parse tree leaving the value on the top of the stack. 68*9662Slinton */ 69*9662Slinton 70*9662Slinton public eval(p) 71*9662Slinton register Node p; 72*9662Slinton { 73*9662Slinton long r0, r1; 74*9662Slinton double fr0, fr1; 75*9662Slinton Address addr; 76*9662Slinton long i, n; 77*9662Slinton int len; 78*9662Slinton Symbol s, f; 79*9662Slinton Node n1, n2; 80*9662Slinton Boolean b; 81*9662Slinton File file; 82*9662Slinton 83*9662Slinton checkref(p); 84*9662Slinton switch (degree(p->op)) { 85*9662Slinton case BINARY: 86*9662Slinton poparg(1, r1, fr1); 87*9662Slinton poparg(0, r0, fr0); 88*9662Slinton break; 89*9662Slinton 90*9662Slinton case UNARY: 91*9662Slinton poparg(0, r0, fr0); 92*9662Slinton break; 93*9662Slinton 94*9662Slinton default: 95*9662Slinton /* do nothing */; 96*9662Slinton } 97*9662Slinton switch (p->op) { 98*9662Slinton case O_SYM: 99*9662Slinton s = p->value.sym; 100*9662Slinton if (s == retaddrsym) { 101*9662Slinton push(long, return_addr()); 102*9662Slinton } else { 103*9662Slinton if (isvariable(s)) { 104*9662Slinton if (s != program and not isactive(container(s))) { 105*9662Slinton error("\"%s\" is not active", symname(s)); 106*9662Slinton } 107*9662Slinton push(long, address(s, nil)); 108*9662Slinton } else if (isblock(s)) { 109*9662Slinton push(Symbol, s); 110*9662Slinton } else { 111*9662Slinton error("can't evaluate a %s", classname(s)); 112*9662Slinton } 113*9662Slinton } 114*9662Slinton break; 115*9662Slinton 116*9662Slinton case O_LCON: 117*9662Slinton r0 = p->value.lcon; 118*9662Slinton pushsmall(p->nodetype, r0); 119*9662Slinton break; 120*9662Slinton 121*9662Slinton case O_FCON: 122*9662Slinton push(double, p->value.fcon); 123*9662Slinton break; 124*9662Slinton 125*9662Slinton case O_SCON: 126*9662Slinton len = size(p->nodetype); 127*9662Slinton mov(p->value.scon, sp, len); 128*9662Slinton sp += len; 129*9662Slinton break; 130*9662Slinton 131*9662Slinton case O_INDEX: 132*9662Slinton n = pop(long); 133*9662Slinton i = evalindex(p->value.arg[0]->nodetype, 134*9662Slinton popsmall(p->value.arg[1]->nodetype)); 135*9662Slinton push(long, n + i*size(p->nodetype)); 136*9662Slinton break; 137*9662Slinton 138*9662Slinton case O_DOT: 139*9662Slinton s = p->value.arg[1]->value.sym; 140*9662Slinton n = lval(p->value.arg[0]); 141*9662Slinton push(long, n + (s->symvalue.field.offset div 8)); 142*9662Slinton break; 143*9662Slinton 144*9662Slinton /* 145*9662Slinton * Get the value of the expression addressed by the top of the stack. 146*9662Slinton * Push the result back on the stack. 147*9662Slinton */ 148*9662Slinton 149*9662Slinton case O_INDIR: 150*9662Slinton case O_RVAL: 151*9662Slinton addr = pop(long); 152*9662Slinton if (addr == 0) { 153*9662Slinton error("reference through nil pointer"); 154*9662Slinton } 155*9662Slinton if (p->op == O_INDIR) { 156*9662Slinton len = sizeof(long); 157*9662Slinton } else { 158*9662Slinton len = size(p->nodetype); 159*9662Slinton } 160*9662Slinton rpush(addr, len); 161*9662Slinton break; 162*9662Slinton 163*9662Slinton case O_COMMA: 164*9662Slinton break; 165*9662Slinton 166*9662Slinton case O_ITOF: 167*9662Slinton push(double, (double) r0); 168*9662Slinton break; 169*9662Slinton 170*9662Slinton case O_ADD: 171*9662Slinton push(long, r0+r1); 172*9662Slinton break; 173*9662Slinton 174*9662Slinton case O_ADDF: 175*9662Slinton push(double, fr0+fr1); 176*9662Slinton break; 177*9662Slinton 178*9662Slinton case O_SUB: 179*9662Slinton push(long, r0-r1); 180*9662Slinton break; 181*9662Slinton 182*9662Slinton case O_SUBF: 183*9662Slinton push(double, fr0-fr1); 184*9662Slinton break; 185*9662Slinton 186*9662Slinton case O_NEG: 187*9662Slinton push(long, -r0); 188*9662Slinton break; 189*9662Slinton 190*9662Slinton case O_NEGF: 191*9662Slinton push(double, -fr0); 192*9662Slinton break; 193*9662Slinton 194*9662Slinton case O_MUL: 195*9662Slinton push(long, r0*r1); 196*9662Slinton break; 197*9662Slinton 198*9662Slinton case O_MULF: 199*9662Slinton push(double, fr0*fr1); 200*9662Slinton break; 201*9662Slinton 202*9662Slinton case O_DIVF: 203*9662Slinton if (fr1 == 0) { 204*9662Slinton error("error: division by 0"); 205*9662Slinton } 206*9662Slinton push(double, fr0 / fr1); 207*9662Slinton break; 208*9662Slinton 209*9662Slinton case O_DIV: 210*9662Slinton if (r1 == 0) { 211*9662Slinton error("error: div by 0"); 212*9662Slinton } 213*9662Slinton push(long, r0 div r1); 214*9662Slinton break; 215*9662Slinton 216*9662Slinton case O_MOD: 217*9662Slinton if (r1 == 0) { 218*9662Slinton error("error: mod by 0"); 219*9662Slinton } 220*9662Slinton push(long, r0 mod r1); 221*9662Slinton break; 222*9662Slinton 223*9662Slinton case O_LT: 224*9662Slinton push(Boolrep, r0 < r1); 225*9662Slinton break; 226*9662Slinton 227*9662Slinton case O_LTF: 228*9662Slinton push(Boolrep, fr0 < fr1); 229*9662Slinton break; 230*9662Slinton 231*9662Slinton case O_LE: 232*9662Slinton push(Boolrep, r0 <= r1); 233*9662Slinton break; 234*9662Slinton 235*9662Slinton case O_LEF: 236*9662Slinton push(Boolrep, fr0 <= fr1); 237*9662Slinton break; 238*9662Slinton 239*9662Slinton case O_GT: 240*9662Slinton push(Boolrep, r0 > r1); 241*9662Slinton break; 242*9662Slinton 243*9662Slinton case O_GTF: 244*9662Slinton push(Boolrep, fr0 > fr1); 245*9662Slinton break; 246*9662Slinton 247*9662Slinton case O_EQ: 248*9662Slinton push(Boolrep, r0 == r1); 249*9662Slinton break; 250*9662Slinton 251*9662Slinton case O_EQF: 252*9662Slinton push(Boolrep, fr0 == fr1); 253*9662Slinton break; 254*9662Slinton 255*9662Slinton case O_NE: 256*9662Slinton push(Boolrep, r0 != r1); 257*9662Slinton break; 258*9662Slinton 259*9662Slinton case O_NEF: 260*9662Slinton push(Boolrep, fr0 != fr1); 261*9662Slinton break; 262*9662Slinton 263*9662Slinton case O_AND: 264*9662Slinton push(Boolrep, r0 and r1); 265*9662Slinton break; 266*9662Slinton 267*9662Slinton case O_OR: 268*9662Slinton push(Boolrep, r0 or r1); 269*9662Slinton break; 270*9662Slinton 271*9662Slinton case O_ASSIGN: 272*9662Slinton assign(p->value.arg[0], p->value.arg[1]); 273*9662Slinton break; 274*9662Slinton 275*9662Slinton case O_CHFILE: 276*9662Slinton if (p->value.scon == nil) { 277*9662Slinton printf("%s\n", cursource); 278*9662Slinton } else { 279*9662Slinton file = opensource(p->value.scon); 280*9662Slinton if (file == nil) { 281*9662Slinton error("can't read \"%s\"", p->value.scon); 282*9662Slinton } else { 283*9662Slinton fclose(file); 284*9662Slinton setsource(p->value.scon); 285*9662Slinton } 286*9662Slinton } 287*9662Slinton break; 288*9662Slinton 289*9662Slinton case O_CONT: 290*9662Slinton cont(); 291*9662Slinton printnews(); 292*9662Slinton break; 293*9662Slinton 294*9662Slinton case O_LIST: 295*9662Slinton if (p->value.arg[0]->op == O_SYM) { 296*9662Slinton f = p->value.arg[0]->value.sym; 297*9662Slinton addr = firstline(f); 298*9662Slinton if (addr == NOADDR) { 299*9662Slinton error("no source lines for \"%s\"", symname(f)); 300*9662Slinton } 301*9662Slinton setsource(srcfilename(addr)); 302*9662Slinton r0 = srcline(addr) - 5; 303*9662Slinton r1 = r0 + 10; 304*9662Slinton if (r0 < 1) { 305*9662Slinton r0 = 1; 306*9662Slinton } 307*9662Slinton } else { 308*9662Slinton eval(p->value.arg[0]); 309*9662Slinton r0 = pop(long); 310*9662Slinton eval(p->value.arg[1]); 311*9662Slinton r1 = pop(long); 312*9662Slinton } 313*9662Slinton printlines((Lineno) r0, (Lineno) r1); 314*9662Slinton break; 315*9662Slinton 316*9662Slinton case O_FUNC: 317*9662Slinton if (p->value.arg[0] == nil) { 318*9662Slinton printname(stdout, curfunc); 319*9662Slinton putchar('\n'); 320*9662Slinton } else { 321*9662Slinton curfunc = p->value.arg[0]->value.sym; 322*9662Slinton addr = codeloc(curfunc); 323*9662Slinton if (addr != NOADDR) { 324*9662Slinton setsource(srcfilename(addr)); 325*9662Slinton cursrcline = srcline(addr) - 5; 326*9662Slinton if (cursrcline < 1) { 327*9662Slinton cursrcline = 1; 328*9662Slinton } 329*9662Slinton } 330*9662Slinton } 331*9662Slinton break; 332*9662Slinton 333*9662Slinton case O_EXAMINE: 334*9662Slinton eval(p->value.examine.beginaddr); 335*9662Slinton r0 = pop(long); 336*9662Slinton if (p->value.examine.endaddr == nil) { 337*9662Slinton n = p->value.examine.count; 338*9662Slinton if (streq(p->value.examine.mode, "i")) { 339*9662Slinton printninst(n, (Address) r0); 340*9662Slinton } else { 341*9662Slinton printndata(n, (Address) r0, p->value.examine.mode); 342*9662Slinton } 343*9662Slinton } else { 344*9662Slinton eval(p->value.examine.endaddr); 345*9662Slinton r1 = pop(long); 346*9662Slinton if (streq(p->value.examine.mode, "i")) { 347*9662Slinton printinst((Address)r0, (Address)r1); 348*9662Slinton } else { 349*9662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 350*9662Slinton } 351*9662Slinton } 352*9662Slinton break; 353*9662Slinton 354*9662Slinton case O_PRINT: 355*9662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 356*9662Slinton eval(n1->value.arg[0]); 357*9662Slinton printval(n1->value.arg[0]->nodetype); 358*9662Slinton putchar(' '); 359*9662Slinton } 360*9662Slinton putchar('\n'); 361*9662Slinton break; 362*9662Slinton 363*9662Slinton case O_PSYM: 364*9662Slinton if (p->value.arg[0]->op == O_SYM) { 365*9662Slinton psym(p->value.arg[0]->value.sym); 366*9662Slinton } else { 367*9662Slinton psym(p->value.arg[0]->nodetype); 368*9662Slinton } 369*9662Slinton break; 370*9662Slinton 371*9662Slinton case O_QLINE: 372*9662Slinton eval(p->value.arg[1]); 373*9662Slinton break; 374*9662Slinton 375*9662Slinton case O_STEP: 376*9662Slinton b = inst_tracing; 377*9662Slinton inst_tracing = (Boolean) (not p->value.step.source); 378*9662Slinton if (p->value.step.skipcalls) { 379*9662Slinton next(); 380*9662Slinton } else { 381*9662Slinton stepc(); 382*9662Slinton } 383*9662Slinton inst_tracing = b; 384*9662Slinton printnews(); 385*9662Slinton break; 386*9662Slinton 387*9662Slinton case O_WHATIS: 388*9662Slinton if (p->value.arg[0]->op == O_SYM) { 389*9662Slinton printdecl(p->value.arg[0]->value.sym); 390*9662Slinton } else { 391*9662Slinton printdecl(p->value.arg[0]->nodetype); 392*9662Slinton } 393*9662Slinton break; 394*9662Slinton 395*9662Slinton case O_WHERE: 396*9662Slinton wherecmd(); 397*9662Slinton break; 398*9662Slinton 399*9662Slinton case O_WHEREIS: 400*9662Slinton printwhereis(stdout, p->value.arg[0]->value.sym); 401*9662Slinton break; 402*9662Slinton 403*9662Slinton case O_WHICH: 404*9662Slinton printwhich(stdout, p->value.arg[0]->value.sym); 405*9662Slinton putchar('\n'); 406*9662Slinton break; 407*9662Slinton 408*9662Slinton case O_ALIAS: 409*9662Slinton n1 = p->value.arg[0]; 410*9662Slinton n2 = p->value.arg[1]; 411*9662Slinton if (n1 == nil) { 412*9662Slinton print_alias(nil); 413*9662Slinton } else if (n2 == nil) { 414*9662Slinton print_alias(n1->value.name); 415*9662Slinton } else { 416*9662Slinton enter_alias(n1->value.name, n2->value.name); 417*9662Slinton } 418*9662Slinton break; 419*9662Slinton 420*9662Slinton case O_CALL: 421*9662Slinton callproc(p->value.arg[0], p->value.arg[1]); 422*9662Slinton break; 423*9662Slinton 424*9662Slinton case O_CATCH: 425*9662Slinton psigtrace(process, p->value.lcon, true); 426*9662Slinton break; 427*9662Slinton 428*9662Slinton case O_EDIT: 429*9662Slinton edit(p->value.scon); 430*9662Slinton break; 431*9662Slinton 432*9662Slinton case O_DUMP: 433*9662Slinton dump(); 434*9662Slinton break; 435*9662Slinton 436*9662Slinton case O_GRIPE: 437*9662Slinton gripe(); 438*9662Slinton break; 439*9662Slinton 440*9662Slinton case O_HELP: 441*9662Slinton help(); 442*9662Slinton break; 443*9662Slinton 444*9662Slinton case O_IGNORE: 445*9662Slinton psigtrace(process, p->value.lcon, false); 446*9662Slinton break; 447*9662Slinton 448*9662Slinton case O_RUN: 449*9662Slinton run(); 450*9662Slinton break; 451*9662Slinton 452*9662Slinton case O_SOURCE: 453*9662Slinton setinput(p->value.scon); 454*9662Slinton break; 455*9662Slinton 456*9662Slinton case O_STATUS: 457*9662Slinton status(); 458*9662Slinton break; 459*9662Slinton 460*9662Slinton case O_TRACE: 461*9662Slinton case O_TRACEI: 462*9662Slinton trace(p); 463*9662Slinton if (isstdin()) { 464*9662Slinton status(); 465*9662Slinton } 466*9662Slinton break; 467*9662Slinton 468*9662Slinton case O_STOP: 469*9662Slinton case O_STOPI: 470*9662Slinton stop(p); 471*9662Slinton if (isstdin()) { 472*9662Slinton status(); 473*9662Slinton } 474*9662Slinton break; 475*9662Slinton 476*9662Slinton case O_ADDEVENT: 477*9662Slinton addevent(p->value.event.cond, p->value.event.actions); 478*9662Slinton break; 479*9662Slinton 480*9662Slinton case O_DELETE: 481*9662Slinton delevent((unsigned int) p->value.lcon); 482*9662Slinton break; 483*9662Slinton 484*9662Slinton case O_ENDX: 485*9662Slinton endprogram(); 486*9662Slinton break; 487*9662Slinton 488*9662Slinton case O_IF: 489*9662Slinton if (cond(p->value.event.cond)) { 490*9662Slinton evalcmdlist(p->value.event.actions); 491*9662Slinton } 492*9662Slinton break; 493*9662Slinton 494*9662Slinton case O_ONCE: 495*9662Slinton event_once(p->value.event.cond, p->value.event.actions); 496*9662Slinton break; 497*9662Slinton 498*9662Slinton case O_PRINTCALL: 499*9662Slinton printcall(p->value.sym, whatblock(return_addr())); 500*9662Slinton break; 501*9662Slinton 502*9662Slinton case O_PRINTIFCHANGED: 503*9662Slinton printifchanged(p->value.arg[0]); 504*9662Slinton break; 505*9662Slinton 506*9662Slinton case O_PRINTRTN: 507*9662Slinton printrtn(p->value.sym); 508*9662Slinton break; 509*9662Slinton 510*9662Slinton case O_PRINTSRCPOS: 511*9662Slinton getsrcpos(); 512*9662Slinton if (p->value.arg[0] == nil) { 513*9662Slinton printsrcpos(); 514*9662Slinton putchar('\n'); 515*9662Slinton printlines(curline, curline); 516*9662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 517*9662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 518*9662Slinton printf("tracei: "); 519*9662Slinton printinst(pc, pc); 520*9662Slinton } else { 521*9662Slinton printf("trace: "); 522*9662Slinton printlines(curline, curline); 523*9662Slinton } 524*9662Slinton } else { 525*9662Slinton printsrcpos(); 526*9662Slinton printf(": "); 527*9662Slinton eval(p->value.arg[0]); 528*9662Slinton prtree(stdout, p->value.arg[0]); 529*9662Slinton printf(" = "); 530*9662Slinton printval(p->value.arg[0]->nodetype); 531*9662Slinton putchar('\n'); 532*9662Slinton } 533*9662Slinton break; 534*9662Slinton 535*9662Slinton case O_PROCRTN: 536*9662Slinton procreturn(p->value.sym); 537*9662Slinton break; 538*9662Slinton 539*9662Slinton case O_STOPIFCHANGED: 540*9662Slinton stopifchanged(p->value.arg[0]); 541*9662Slinton break; 542*9662Slinton 543*9662Slinton case O_STOPX: 544*9662Slinton isstopped = true; 545*9662Slinton break; 546*9662Slinton 547*9662Slinton case O_TRACEON: 548*9662Slinton traceon(p->value.trace.inst, p->value.trace.event, 549*9662Slinton p->value.trace.actions); 550*9662Slinton break; 551*9662Slinton 552*9662Slinton case O_TRACEOFF: 553*9662Slinton traceoff(p->value.lcon); 554*9662Slinton break; 555*9662Slinton 556*9662Slinton default: 557*9662Slinton panic("eval: bad op %d", p->op); 558*9662Slinton } 559*9662Slinton } 560*9662Slinton 561*9662Slinton /* 562*9662Slinton * Evaluate a list of commands. 563*9662Slinton */ 564*9662Slinton 565*9662Slinton public evalcmdlist(cl) 566*9662Slinton Cmdlist cl; 567*9662Slinton { 568*9662Slinton Command c; 569*9662Slinton 570*9662Slinton foreach (Command, c, cl) 571*9662Slinton evalcmd(c); 572*9662Slinton endfor 573*9662Slinton } 574*9662Slinton 575*9662Slinton /* 576*9662Slinton * Push "len" bytes onto the expression stack from address "addr" 577*9662Slinton * in the process. If there isn't room on the stack, print an error message. 578*9662Slinton */ 579*9662Slinton 580*9662Slinton public rpush(addr, len) 581*9662Slinton Address addr; 582*9662Slinton int len; 583*9662Slinton { 584*9662Slinton if (not canpush(len)) { 585*9662Slinton error("expression too large to evaluate"); 586*9662Slinton } else { 587*9662Slinton chksp(); 588*9662Slinton dread(sp, addr, len); 589*9662Slinton sp += len; 590*9662Slinton } 591*9662Slinton } 592*9662Slinton 593*9662Slinton /* 594*9662Slinton * Check if the stack has n bytes available. 595*9662Slinton */ 596*9662Slinton 597*9662Slinton public Boolean canpush(n) 598*9662Slinton Integer n; 599*9662Slinton { 600*9662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 601*9662Slinton } 602*9662Slinton 603*9662Slinton /* 604*9662Slinton * Push a small scalar of the given type onto the stack. 605*9662Slinton */ 606*9662Slinton 607*9662Slinton public pushsmall(t, v) 608*9662Slinton Symbol t; 609*9662Slinton long v; 610*9662Slinton { 611*9662Slinton register Integer s; 612*9662Slinton 613*9662Slinton s = size(t); 614*9662Slinton switch (s) { 615*9662Slinton case sizeof(char): 616*9662Slinton push(char, v); 617*9662Slinton break; 618*9662Slinton 619*9662Slinton case sizeof(short): 620*9662Slinton push(short, v); 621*9662Slinton break; 622*9662Slinton 623*9662Slinton case sizeof(long): 624*9662Slinton push(long, v); 625*9662Slinton break; 626*9662Slinton 627*9662Slinton default: 628*9662Slinton panic("bad size %d in popsmall", s); 629*9662Slinton } 630*9662Slinton } 631*9662Slinton 632*9662Slinton /* 633*9662Slinton * Pop an item of the given type which is assumed to be no larger 634*9662Slinton * than a long and return it expanded into a long. 635*9662Slinton */ 636*9662Slinton 637*9662Slinton public long popsmall(t) 638*9662Slinton Symbol t; 639*9662Slinton { 640*9662Slinton long r; 641*9662Slinton 642*9662Slinton switch (size(t)) { 643*9662Slinton case sizeof(char): 644*9662Slinton r = (long) pop(char); 645*9662Slinton break; 646*9662Slinton 647*9662Slinton case sizeof(short): 648*9662Slinton r = (long) pop(short); 649*9662Slinton break; 650*9662Slinton 651*9662Slinton case sizeof(long): 652*9662Slinton r = pop(long); 653*9662Slinton break; 654*9662Slinton 655*9662Slinton default: 656*9662Slinton panic("popsmall: size is %d", size(t)); 657*9662Slinton } 658*9662Slinton return r; 659*9662Slinton } 660*9662Slinton 661*9662Slinton /* 662*9662Slinton * Evaluate a conditional expression. 663*9662Slinton */ 664*9662Slinton 665*9662Slinton public Boolean cond(p) 666*9662Slinton Node p; 667*9662Slinton { 668*9662Slinton register Boolean b; 669*9662Slinton 670*9662Slinton if (p == nil) { 671*9662Slinton b = true; 672*9662Slinton } else { 673*9662Slinton eval(p); 674*9662Slinton b = pop(Boolean); 675*9662Slinton } 676*9662Slinton return b; 677*9662Slinton } 678*9662Slinton 679*9662Slinton /* 680*9662Slinton * Return the address corresponding to a given tree. 681*9662Slinton */ 682*9662Slinton 683*9662Slinton public Address lval(p) 684*9662Slinton Node p; 685*9662Slinton { 686*9662Slinton if (p->op == O_RVAL) { 687*9662Slinton eval(p->value.arg[0]); 688*9662Slinton } else { 689*9662Slinton eval(p); 690*9662Slinton } 691*9662Slinton return (Address) (pop(long)); 692*9662Slinton } 693*9662Slinton 694*9662Slinton /* 695*9662Slinton * Process a trace command, translating into the appropriate events 696*9662Slinton * and associated actions. 697*9662Slinton */ 698*9662Slinton 699*9662Slinton public trace(p) 700*9662Slinton Node p; 701*9662Slinton { 702*9662Slinton Node exp, place, cond; 703*9662Slinton Node left; 704*9662Slinton 705*9662Slinton exp = p->value.arg[0]; 706*9662Slinton place = p->value.arg[1]; 707*9662Slinton cond = p->value.arg[2]; 708*9662Slinton if (exp == nil) { 709*9662Slinton traceall(p->op, place, cond); 710*9662Slinton } else if (exp->op == O_QLINE) { 711*9662Slinton traceinst(p->op, exp, cond); 712*9662Slinton } else if (place != nil and place->op == O_QLINE) { 713*9662Slinton traceat(p->op, exp, place, cond); 714*9662Slinton } else { 715*9662Slinton left = (exp->op == O_RVAL) ? exp->value.arg[0] : exp; 716*9662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 717*9662Slinton traceproc(p->op, left->value.sym, place, cond); 718*9662Slinton } else { 719*9662Slinton tracedata(p->op, exp, place, cond); 720*9662Slinton } 721*9662Slinton } 722*9662Slinton } 723*9662Slinton 724*9662Slinton /* 725*9662Slinton * Set a breakpoint that will turn on tracing. 726*9662Slinton */ 727*9662Slinton 728*9662Slinton private traceall(op, place, cond) 729*9662Slinton Operator op; 730*9662Slinton Node place; 731*9662Slinton Node cond; 732*9662Slinton { 733*9662Slinton Symbol s; 734*9662Slinton Node event; 735*9662Slinton Command action; 736*9662Slinton 737*9662Slinton if (place == nil) { 738*9662Slinton s = program; 739*9662Slinton } else { 740*9662Slinton s = place->value.sym; 741*9662Slinton } 742*9662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 743*9662Slinton action = build(O_PRINTSRCPOS, 744*9662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 745*9662Slinton if (cond != nil) { 746*9662Slinton action = build(O_IF, cond, buildcmdlist(action)); 747*9662Slinton } 748*9662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 749*9662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 750*9662Slinton } 751*9662Slinton 752*9662Slinton /* 753*9662Slinton * Set up the appropriate breakpoint for tracing an instruction. 754*9662Slinton */ 755*9662Slinton 756*9662Slinton private traceinst(op, exp, cond) 757*9662Slinton Operator op; 758*9662Slinton Node exp; 759*9662Slinton Node cond; 760*9662Slinton { 761*9662Slinton Node event; 762*9662Slinton Command action; 763*9662Slinton 764*9662Slinton if (op == O_TRACEI) { 765*9662Slinton event = build(O_EQ, build(O_SYM, pcsym), exp); 766*9662Slinton } else { 767*9662Slinton event = build(O_EQ, build(O_SYM, linesym), exp); 768*9662Slinton } 769*9662Slinton action = build(O_PRINTSRCPOS, exp); 770*9662Slinton if (cond) { 771*9662Slinton action = build(O_IF, cond, buildcmdlist(action)); 772*9662Slinton } 773*9662Slinton addevent(event, buildcmdlist(action)); 774*9662Slinton } 775*9662Slinton 776*9662Slinton /* 777*9662Slinton * Set a breakpoint to print an expression at a given line or address. 778*9662Slinton */ 779*9662Slinton 780*9662Slinton private traceat(op, exp, place, cond) 781*9662Slinton Operator op; 782*9662Slinton Node exp; 783*9662Slinton Node place; 784*9662Slinton Node cond; 785*9662Slinton { 786*9662Slinton Node event; 787*9662Slinton Command action; 788*9662Slinton 789*9662Slinton if (op == O_TRACEI) { 790*9662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 791*9662Slinton } else { 792*9662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 793*9662Slinton } 794*9662Slinton action = build(O_PRINTSRCPOS, exp); 795*9662Slinton if (cond != nil) { 796*9662Slinton action = build(O_IF, cond, buildcmdlist(action)); 797*9662Slinton } 798*9662Slinton addevent(event, buildcmdlist(action)); 799*9662Slinton } 800*9662Slinton 801*9662Slinton /* 802*9662Slinton * Construct event for tracing a procedure. 803*9662Slinton * 804*9662Slinton * What we want here is 805*9662Slinton * 806*9662Slinton * when $proc = p do 807*9662Slinton * if <condition> then 808*9662Slinton * printcall; 809*9662Slinton * once $pc = $retaddr do 810*9662Slinton * printrtn; 811*9662Slinton * end; 812*9662Slinton * end if; 813*9662Slinton * end; 814*9662Slinton * 815*9662Slinton * Note that "once" is like "when" except that the event 816*9662Slinton * deletes itself as part of its associated action. 817*9662Slinton */ 818*9662Slinton 819*9662Slinton private traceproc(op, p, place, cond) 820*9662Slinton Operator op; 821*9662Slinton Symbol p; 822*9662Slinton Node place; 823*9662Slinton Node cond; 824*9662Slinton { 825*9662Slinton Node event; 826*9662Slinton Command action; 827*9662Slinton Cmdlist actionlist; 828*9662Slinton 829*9662Slinton action = build(O_PRINTCALL, p); 830*9662Slinton actionlist = list_alloc(); 831*9662Slinton cmdlist_append(action, actionlist); 832*9662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 833*9662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 834*9662Slinton cmdlist_append(action, actionlist); 835*9662Slinton if (cond != nil) { 836*9662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 837*9662Slinton } 838*9662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 839*9662Slinton addevent(event, actionlist); 840*9662Slinton } 841*9662Slinton 842*9662Slinton /* 843*9662Slinton * Set up breakpoint for tracing data. 844*9662Slinton */ 845*9662Slinton 846*9662Slinton private tracedata(op, exp, place, cond) 847*9662Slinton Operator op; 848*9662Slinton Node exp; 849*9662Slinton Node place; 850*9662Slinton Node cond; 851*9662Slinton { 852*9662Slinton Symbol p; 853*9662Slinton Node event; 854*9662Slinton Command action; 855*9662Slinton 856*9662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 857*9662Slinton if (p == nil) { 858*9662Slinton p = program; 859*9662Slinton } 860*9662Slinton action = build(O_PRINTIFCHANGED, exp); 861*9662Slinton if (cond != nil) { 862*9662Slinton action = build(O_IF, cond, buildcmdlist(action)); 863*9662Slinton } 864*9662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 865*9662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 866*9662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 867*9662Slinton } 868*9662Slinton 869*9662Slinton /* 870*9662Slinton * Setting and unsetting of stops. 871*9662Slinton */ 872*9662Slinton 873*9662Slinton public stop(p) 874*9662Slinton Node p; 875*9662Slinton { 876*9662Slinton Node exp, place, cond; 877*9662Slinton Symbol s; 878*9662Slinton Command action; 879*9662Slinton 880*9662Slinton exp = p->value.arg[0]; 881*9662Slinton place = p->value.arg[1]; 882*9662Slinton cond = p->value.arg[2]; 883*9662Slinton if (exp != nil) { 884*9662Slinton stopvar(p->op, exp, place, cond); 885*9662Slinton } else if (cond != nil) { 886*9662Slinton s = (place == nil) ? program : place->value.sym; 887*9662Slinton action = build(O_IF, cond, buildcmdlist(build(O_STOPX))); 888*9662Slinton action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action)); 889*9662Slinton cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 890*9662Slinton action->value.trace.event = addevent(cond, buildcmdlist(action)); 891*9662Slinton } else if (place->op == O_SYM) { 892*9662Slinton s = place->value.sym; 893*9662Slinton cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 894*9662Slinton addevent(cond, buildcmdlist(build(O_STOPX))); 895*9662Slinton } else { 896*9662Slinton stopinst(p->op, place, cond); 897*9662Slinton } 898*9662Slinton } 899*9662Slinton 900*9662Slinton private stopinst(op, place, cond) 901*9662Slinton Operator op; 902*9662Slinton Node place; 903*9662Slinton Node cond; 904*9662Slinton { 905*9662Slinton Node event; 906*9662Slinton 907*9662Slinton if (op == O_STOP) { 908*9662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 909*9662Slinton } else { 910*9662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 911*9662Slinton } 912*9662Slinton addevent(event, buildcmdlist(build(O_STOPX))); 913*9662Slinton } 914*9662Slinton 915*9662Slinton /* 916*9662Slinton * Implement stopping on assignment to a variable by adding it to 917*9662Slinton * the variable list. 918*9662Slinton */ 919*9662Slinton 920*9662Slinton private stopvar(op, exp, place, cond) 921*9662Slinton Operator op; 922*9662Slinton Node exp; 923*9662Slinton Node place; 924*9662Slinton Node cond; 925*9662Slinton { 926*9662Slinton Symbol p; 927*9662Slinton Node event; 928*9662Slinton Command action; 929*9662Slinton 930*9662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 931*9662Slinton if (p == nil) { 932*9662Slinton p = program; 933*9662Slinton } 934*9662Slinton action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp))); 935*9662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 936*9662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 937*9662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 938*9662Slinton } 939*9662Slinton 940*9662Slinton /* 941*9662Slinton * Assign the value of an expression to a variable (or term). 942*9662Slinton */ 943*9662Slinton 944*9662Slinton public assign(var, exp) 945*9662Slinton Node var; 946*9662Slinton Node exp; 947*9662Slinton { 948*9662Slinton Address addr; 949*9662Slinton int varsize; 950*9662Slinton char cvalue; 951*9662Slinton short svalue; 952*9662Slinton long lvalue; 953*9662Slinton 954*9662Slinton if (not compatible(var->nodetype, exp->nodetype)) { 955*9662Slinton error("incompatible types"); 956*9662Slinton } 957*9662Slinton addr = lval(var); 958*9662Slinton eval(exp); 959*9662Slinton varsize = size(var->nodetype); 960*9662Slinton if (varsize < sizeof(long)) { 961*9662Slinton lvalue = pop(long); 962*9662Slinton switch (varsize) { 963*9662Slinton case sizeof(char): 964*9662Slinton cvalue = lvalue; 965*9662Slinton dwrite(&cvalue, addr, varsize); 966*9662Slinton break; 967*9662Slinton 968*9662Slinton case sizeof(short): 969*9662Slinton svalue = lvalue; 970*9662Slinton dwrite(&svalue, addr, varsize); 971*9662Slinton break; 972*9662Slinton 973*9662Slinton default: 974*9662Slinton panic("bad size %d", varsize); 975*9662Slinton } 976*9662Slinton } else { 977*9662Slinton sp -= varsize; 978*9662Slinton dwrite(sp, addr, varsize); 979*9662Slinton } 980*9662Slinton } 981*9662Slinton 982*9662Slinton #define DEF_EDITOR "vi" 983*9662Slinton 984*9662Slinton /* 985*9662Slinton * Invoke an editor on the given file. Which editor to use might change 986*9662Slinton * installation to installation. For now, we use "vi". In any event, 987*9662Slinton * the environment variable "EDITOR" overrides any default. 988*9662Slinton */ 989*9662Slinton 990*9662Slinton public edit(filename) 991*9662Slinton String filename; 992*9662Slinton { 993*9662Slinton extern String getenv(); 994*9662Slinton String ed, src; 995*9662Slinton File f; 996*9662Slinton Symbol s; 997*9662Slinton Address addr; 998*9662Slinton char buff[10]; 999*9662Slinton 1000*9662Slinton ed = getenv("EDITOR"); 1001*9662Slinton if (ed == nil) { 1002*9662Slinton ed = DEF_EDITOR; 1003*9662Slinton } 1004*9662Slinton if (filename == nil) { 1005*9662Slinton call(ed, stdin, stdout, cursource, nil); 1006*9662Slinton } else { 1007*9662Slinton f = fopen(filename, "r"); 1008*9662Slinton if (f == nil) { 1009*9662Slinton s = which(identname(filename, true)); 1010*9662Slinton if (not isblock(s)) { 1011*9662Slinton error("can't read \"%s\"", filename); 1012*9662Slinton } 1013*9662Slinton addr = firstline(s); 1014*9662Slinton if (addr == NOADDR) { 1015*9662Slinton error("no source for \"%s\"", filename); 1016*9662Slinton } 1017*9662Slinton src = srcfilename(addr); 1018*9662Slinton sprintf(buff, "+%d", srcline(addr)); 1019*9662Slinton call(ed, stdin, stdout, buff, src, nil); 1020*9662Slinton } else { 1021*9662Slinton fclose(f); 1022*9662Slinton call(ed, stdin, stdout, filename, nil); 1023*9662Slinton } 1024*9662Slinton } 1025*9662Slinton } 1026*9662Slinton 1027*9662Slinton /* 1028*9662Slinton * Send some nasty mail to the current support person. 1029*9662Slinton */ 1030*9662Slinton 1031*9662Slinton public gripe() 1032*9662Slinton { 1033*9662Slinton typedef Operation(); 1034*9662Slinton Operation *old; 1035*9662Slinton 1036*9662Slinton char *maintainer = "linton@ucbarpa"; 1037*9662Slinton 1038*9662Slinton puts("Type control-D to end your message. Be sure to include"); 1039*9662Slinton puts("your name and the name of the file you are debugging."); 1040*9662Slinton putchar('\n'); 1041*9662Slinton old = signal(SIGINT, SIG_DFL); 1042*9662Slinton call("Mail", stdin, stdout, maintainer, nil); 1043*9662Slinton signal(SIGINT, old); 1044*9662Slinton puts("Thank you."); 1045*9662Slinton } 1046*9662Slinton 1047*9662Slinton /* 1048*9662Slinton * Give the user some help. 1049*9662Slinton */ 1050*9662Slinton 1051*9662Slinton public help() 1052*9662Slinton { 1053*9662Slinton puts("run - begin execution of the program"); 1054*9662Slinton puts("cont - continue execution"); 1055*9662Slinton puts("step - single step one line"); 1056*9662Slinton puts("next - step to next line (skip over calls)"); 1057*9662Slinton puts("trace <line#> - trace execution of the line"); 1058*9662Slinton puts("trace <proc> - trace calls to the procedure"); 1059*9662Slinton puts("trace <var> - trace changes to the variable"); 1060*9662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 1061*9662Slinton puts("stop at <line> - suspend execution at the line"); 1062*9662Slinton puts("stop in <proc> - suspend execution when <proc> is called"); 1063*9662Slinton puts("status - print trace/stop's in effect"); 1064*9662Slinton puts("delete <number> - remove trace or stop of given number"); 1065*9662Slinton puts("call <proc> - call the procedure"); 1066*9662Slinton puts("where - print currently active procedures"); 1067*9662Slinton puts("print <exp> - print the value of the expression"); 1068*9662Slinton puts("whatis <name> - print the declaration of the name"); 1069*9662Slinton puts("list <line>, <line> - list source lines"); 1070*9662Slinton puts("edit <proc> - edit file containing <proc>"); 1071*9662Slinton puts("gripe - send mail to the person in charge of dbx"); 1072*9662Slinton puts("quit - exit dbx"); 1073*9662Slinton } 1074*9662Slinton 1075*9662Slinton /* 1076*9662Slinton * Divert output to the given file name. 1077*9662Slinton * Cannot redirect to an existing file. 1078*9662Slinton */ 1079*9662Slinton 1080*9662Slinton private int so_fd; 1081*9662Slinton private Boolean notstdout; 1082*9662Slinton 1083*9662Slinton public setout(filename) 1084*9662Slinton String filename; 1085*9662Slinton { 1086*9662Slinton File f; 1087*9662Slinton 1088*9662Slinton f = fopen(filename, "r"); 1089*9662Slinton if (f != nil) { 1090*9662Slinton fclose(f); 1091*9662Slinton error("%s: file already exists", filename); 1092*9662Slinton } else { 1093*9662Slinton so_fd = dup(1); 1094*9662Slinton close(1); 1095*9662Slinton if (creat(filename, 0666) == nil) { 1096*9662Slinton unsetout(); 1097*9662Slinton error("can't create %s", filename); 1098*9662Slinton } 1099*9662Slinton notstdout = true; 1100*9662Slinton } 1101*9662Slinton } 1102*9662Slinton 1103*9662Slinton /* 1104*9662Slinton * Revert output to standard output. 1105*9662Slinton */ 1106*9662Slinton 1107*9662Slinton public unsetout() 1108*9662Slinton { 1109*9662Slinton fflush(stdout); 1110*9662Slinton close(1); 1111*9662Slinton if (dup(so_fd) != 1) { 1112*9662Slinton panic("standard out dup failed"); 1113*9662Slinton } 1114*9662Slinton close(so_fd); 1115*9662Slinton notstdout = false; 1116*9662Slinton } 1117*9662Slinton 1118*9662Slinton /* 1119*9662Slinton * Determine is standard output is currently being redirected 1120*9662Slinton * to a file (as far as we know). 1121*9662Slinton */ 1122*9662Slinton 1123*9662Slinton public Boolean isredirected() 1124*9662Slinton { 1125*9662Slinton return notstdout; 1126*9662Slinton } 1127