19662Slinton /* Copyright (c) 1982 Regents of the University of California */ 29662Slinton 3*16608Ssam static char sccsid[] = "@(#)eval.c 1.10 8/17/83"; 49662Slinton 5*16608Ssam static char rcsid[] = "$Header: eval.c,v 1.3 84/03/27 10:20:23 linton Exp $"; 6*16608Ssam 79662Slinton /* 89662Slinton * Tree evaluation. 99662Slinton */ 109662Slinton 119662Slinton #include "defs.h" 129662Slinton #include "tree.h" 139662Slinton #include "operators.h" 149662Slinton #include "eval.h" 159662Slinton #include "events.h" 169662Slinton #include "symbols.h" 179662Slinton #include "scanner.h" 189662Slinton #include "source.h" 199662Slinton #include "object.h" 209662Slinton #include "mappings.h" 219662Slinton #include "process.h" 22*16608Ssam #include "runtime.h" 239662Slinton #include "machine.h" 249662Slinton #include <signal.h> 259662Slinton 269662Slinton #ifndef public 279662Slinton 289662Slinton #include "machine.h" 299662Slinton 3012538Scsvaf #define STACKSIZE 20000 319662Slinton 329662Slinton typedef Char Stack; 339662Slinton 349662Slinton #define push(type, value) { \ 359662Slinton ((type *) (sp += sizeof(type)))[-1] = (value); \ 369662Slinton } 379662Slinton 389662Slinton #define pop(type) ( \ 399662Slinton (*((type *) (sp -= sizeof(type)))) \ 409662Slinton ) 419662Slinton 42*16608Ssam #define popn(n, dest) { \ 43*16608Ssam sp -= n; \ 44*16608Ssam bcopy(sp, dest, n); \ 45*16608Ssam } 46*16608Ssam 479662Slinton #define alignstack() { \ 489662Slinton sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \ 499662Slinton } 509662Slinton 519662Slinton #endif 529662Slinton 539662Slinton public Stack stack[STACKSIZE]; 549662Slinton public Stack *sp = &stack[0]; 5514674Slinton public Boolean useInstLoc = false; 569662Slinton 579662Slinton #define chksp() \ 589662Slinton { \ 599662Slinton if (sp < &stack[0]) { \ 609662Slinton panic("stack underflow"); \ 619662Slinton } \ 629662Slinton } 639662Slinton 649662Slinton #define poparg(n, r, fr) { \ 659662Slinton eval(p->value.arg[n]); \ 669662Slinton if (isreal(p->op)) { \ 67*16608Ssam if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \ 68*16608Ssam fr = pop(float); \ 69*16608Ssam } else { \ 70*16608Ssam fr = pop(double); \ 71*16608Ssam } \ 729662Slinton } else if (isint(p->op)) { \ 739662Slinton r = popsmall(p->value.arg[n]->nodetype); \ 749662Slinton } \ 759662Slinton } 769662Slinton 779662Slinton #define Boolrep char /* underlying representation type for booleans */ 789662Slinton 799662Slinton /* 809662Slinton * Evaluate a parse tree leaving the value on the top of the stack. 819662Slinton */ 829662Slinton 839662Slinton public eval(p) 849662Slinton register Node p; 859662Slinton { 869662Slinton long r0, r1; 879662Slinton double fr0, fr1; 889662Slinton Address addr; 899662Slinton long i, n; 909662Slinton int len; 919662Slinton Symbol s, f; 929662Slinton Node n1, n2; 939662Slinton Boolean b; 949662Slinton File file; 959662Slinton 969662Slinton checkref(p); 9713846Slinton if (debug_flag[2]) { 9813846Slinton fprintf(stderr," evaluating %s \n",showoperator(p->op)); 9912538Scsvaf } 1009662Slinton switch (degree(p->op)) { 1019662Slinton case BINARY: 1029662Slinton poparg(1, r1, fr1); 1039662Slinton poparg(0, r0, fr0); 1049662Slinton break; 1059662Slinton 1069662Slinton case UNARY: 1079662Slinton poparg(0, r0, fr0); 1089662Slinton break; 1099662Slinton 1109662Slinton default: 1119662Slinton /* do nothing */; 1129662Slinton } 1139662Slinton switch (p->op) { 1149662Slinton case O_SYM: 1159662Slinton s = p->value.sym; 1169662Slinton if (s == retaddrsym) { 1179662Slinton push(long, return_addr()); 1189662Slinton } else { 1199662Slinton if (isvariable(s)) { 1209662Slinton if (s != program and not isactive(container(s))) { 1219662Slinton error("\"%s\" is not active", symname(s)); 1229662Slinton } 1239662Slinton push(long, address(s, nil)); 1249662Slinton } else if (isblock(s)) { 1259662Slinton push(Symbol, s); 1269662Slinton } else { 1279662Slinton error("can't evaluate a %s", classname(s)); 1289662Slinton } 1299662Slinton } 1309662Slinton break; 1319662Slinton 1329662Slinton case O_LCON: 1339662Slinton r0 = p->value.lcon; 1349662Slinton pushsmall(p->nodetype, r0); 1359662Slinton break; 1369662Slinton 1379662Slinton case O_FCON: 1389662Slinton push(double, p->value.fcon); 1399662Slinton break; 1409662Slinton 1419662Slinton case O_SCON: 1429662Slinton len = size(p->nodetype); 1439662Slinton mov(p->value.scon, sp, len); 1449662Slinton sp += len; 1459662Slinton break; 1469662Slinton 1479662Slinton case O_INDEX: 1489662Slinton n = pop(long); 1499662Slinton i = evalindex(p->value.arg[0]->nodetype, 1509662Slinton popsmall(p->value.arg[1]->nodetype)); 1519662Slinton push(long, n + i*size(p->nodetype)); 1529662Slinton break; 1539662Slinton 1549662Slinton case O_DOT: 1559662Slinton s = p->value.arg[1]->value.sym; 1569662Slinton n = lval(p->value.arg[0]); 1579662Slinton push(long, n + (s->symvalue.field.offset div 8)); 1589662Slinton break; 1599662Slinton 1609662Slinton /* 1619662Slinton * Get the value of the expression addressed by the top of the stack. 1629662Slinton * Push the result back on the stack. 1639662Slinton */ 1649662Slinton 1659662Slinton case O_INDIR: 1669662Slinton case O_RVAL: 1679662Slinton addr = pop(long); 1689662Slinton if (addr == 0) { 1699662Slinton error("reference through nil pointer"); 1709662Slinton } 1719662Slinton if (p->op == O_INDIR) { 1729662Slinton len = sizeof(long); 1739662Slinton } else { 1749662Slinton len = size(p->nodetype); 1759662Slinton } 1769662Slinton rpush(addr, len); 1779662Slinton break; 1789662Slinton 17911175Slinton /* 18011175Slinton * Effectively, we want to pop n bytes off for the evaluated subtree 18111175Slinton * and push len bytes on for the new type of the same tree. 18211175Slinton */ 18311175Slinton case O_TYPERENAME: 18411175Slinton n = size(p->value.arg[0]->nodetype); 18511175Slinton len = size(p->nodetype); 18611175Slinton sp = sp - n + len; 18711175Slinton break; 18811175Slinton 1899662Slinton case O_COMMA: 1909662Slinton break; 1919662Slinton 1929662Slinton case O_ITOF: 1939662Slinton push(double, (double) r0); 1949662Slinton break; 1959662Slinton 1969662Slinton case O_ADD: 1979662Slinton push(long, r0+r1); 1989662Slinton break; 1999662Slinton 2009662Slinton case O_ADDF: 2019662Slinton push(double, fr0+fr1); 2029662Slinton break; 2039662Slinton 2049662Slinton case O_SUB: 2059662Slinton push(long, r0-r1); 2069662Slinton break; 2079662Slinton 2089662Slinton case O_SUBF: 2099662Slinton push(double, fr0-fr1); 2109662Slinton break; 2119662Slinton 2129662Slinton case O_NEG: 2139662Slinton push(long, -r0); 2149662Slinton break; 2159662Slinton 2169662Slinton case O_NEGF: 2179662Slinton push(double, -fr0); 2189662Slinton break; 2199662Slinton 2209662Slinton case O_MUL: 2219662Slinton push(long, r0*r1); 2229662Slinton break; 2239662Slinton 2249662Slinton case O_MULF: 2259662Slinton push(double, fr0*fr1); 2269662Slinton break; 2279662Slinton 2289662Slinton case O_DIVF: 2299662Slinton if (fr1 == 0) { 2309662Slinton error("error: division by 0"); 2319662Slinton } 2329662Slinton push(double, fr0 / fr1); 2339662Slinton break; 2349662Slinton 2359662Slinton case O_DIV: 2369662Slinton if (r1 == 0) { 2379662Slinton error("error: div by 0"); 2389662Slinton } 2399662Slinton push(long, r0 div r1); 2409662Slinton break; 2419662Slinton 2429662Slinton case O_MOD: 2439662Slinton if (r1 == 0) { 2449662Slinton error("error: mod by 0"); 2459662Slinton } 2469662Slinton push(long, r0 mod r1); 2479662Slinton break; 2489662Slinton 2499662Slinton case O_LT: 2509662Slinton push(Boolrep, r0 < r1); 2519662Slinton break; 2529662Slinton 2539662Slinton case O_LTF: 2549662Slinton push(Boolrep, fr0 < fr1); 2559662Slinton break; 2569662Slinton 2579662Slinton case O_LE: 2589662Slinton push(Boolrep, r0 <= r1); 2599662Slinton break; 2609662Slinton 2619662Slinton case O_LEF: 2629662Slinton push(Boolrep, fr0 <= fr1); 2639662Slinton break; 2649662Slinton 2659662Slinton case O_GT: 2669662Slinton push(Boolrep, r0 > r1); 2679662Slinton break; 2689662Slinton 2699662Slinton case O_GTF: 2709662Slinton push(Boolrep, fr0 > fr1); 2719662Slinton break; 2729662Slinton 2739662Slinton case O_EQ: 2749662Slinton push(Boolrep, r0 == r1); 2759662Slinton break; 2769662Slinton 2779662Slinton case O_EQF: 2789662Slinton push(Boolrep, fr0 == fr1); 2799662Slinton break; 2809662Slinton 2819662Slinton case O_NE: 2829662Slinton push(Boolrep, r0 != r1); 2839662Slinton break; 2849662Slinton 2859662Slinton case O_NEF: 2869662Slinton push(Boolrep, fr0 != fr1); 2879662Slinton break; 2889662Slinton 2899662Slinton case O_AND: 2909662Slinton push(Boolrep, r0 and r1); 2919662Slinton break; 2929662Slinton 2939662Slinton case O_OR: 2949662Slinton push(Boolrep, r0 or r1); 2959662Slinton break; 2969662Slinton 2979662Slinton case O_ASSIGN: 2989662Slinton assign(p->value.arg[0], p->value.arg[1]); 2999662Slinton break; 3009662Slinton 3019662Slinton case O_CHFILE: 3029662Slinton if (p->value.scon == nil) { 3039662Slinton printf("%s\n", cursource); 3049662Slinton } else { 3059662Slinton file = opensource(p->value.scon); 3069662Slinton if (file == nil) { 3079662Slinton error("can't read \"%s\"", p->value.scon); 3089662Slinton } else { 3099662Slinton fclose(file); 3109662Slinton setsource(p->value.scon); 3119662Slinton } 3129662Slinton } 3139662Slinton break; 3149662Slinton 3159662Slinton case O_CONT: 31611871Slinton cont(p->value.lcon); 3179662Slinton printnews(); 3189662Slinton break; 3199662Slinton 3209662Slinton case O_LIST: 3219662Slinton if (p->value.arg[0]->op == O_SYM) { 3229662Slinton f = p->value.arg[0]->value.sym; 3239662Slinton addr = firstline(f); 3249662Slinton if (addr == NOADDR) { 3259662Slinton error("no source lines for \"%s\"", symname(f)); 3269662Slinton } 3279662Slinton setsource(srcfilename(addr)); 3289662Slinton r0 = srcline(addr) - 5; 3299662Slinton r1 = r0 + 10; 3309662Slinton if (r0 < 1) { 3319662Slinton r0 = 1; 3329662Slinton } 3339662Slinton } else { 3349662Slinton eval(p->value.arg[0]); 3359662Slinton r0 = pop(long); 3369662Slinton eval(p->value.arg[1]); 3379662Slinton r1 = pop(long); 3389662Slinton } 3399662Slinton printlines((Lineno) r0, (Lineno) r1); 3409662Slinton break; 3419662Slinton 3429662Slinton case O_FUNC: 3439662Slinton if (p->value.arg[0] == nil) { 3449662Slinton printname(stdout, curfunc); 3459662Slinton putchar('\n'); 3469662Slinton } else { 34711871Slinton s = p->value.arg[0]->value.sym; 348*16608Ssam if (isroutine(s)) { 349*16608Ssam setcurfunc(s); 350*16608Ssam } else { 351*16608Ssam find(f, s->name) where isroutine(f) endfind(f); 352*16608Ssam if (f == nil) { 353*16608Ssam error("%s is not a procedure or function", symname(s)); 354*16608Ssam } 355*16608Ssam setcurfunc(f); 35611771Slinton } 3579662Slinton addr = codeloc(curfunc); 3589662Slinton if (addr != NOADDR) { 3599662Slinton setsource(srcfilename(addr)); 3609662Slinton cursrcline = srcline(addr) - 5; 3619662Slinton if (cursrcline < 1) { 3629662Slinton cursrcline = 1; 3639662Slinton } 3649662Slinton } 3659662Slinton } 3669662Slinton break; 3679662Slinton 3689662Slinton case O_EXAMINE: 3699662Slinton eval(p->value.examine.beginaddr); 3709662Slinton r0 = pop(long); 3719662Slinton if (p->value.examine.endaddr == nil) { 3729662Slinton n = p->value.examine.count; 37311175Slinton if (n == 0) { 37411175Slinton printvalue(r0, p->value.examine.mode); 37511175Slinton } else if (streq(p->value.examine.mode, "i")) { 3769662Slinton printninst(n, (Address) r0); 3779662Slinton } else { 3789662Slinton printndata(n, (Address) r0, p->value.examine.mode); 3799662Slinton } 3809662Slinton } else { 3819662Slinton eval(p->value.examine.endaddr); 3829662Slinton r1 = pop(long); 3839662Slinton if (streq(p->value.examine.mode, "i")) { 3849662Slinton printinst((Address)r0, (Address)r1); 3859662Slinton } else { 3869662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 3879662Slinton } 3889662Slinton } 3899662Slinton break; 3909662Slinton 3919662Slinton case O_PRINT: 3929662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 3939662Slinton eval(n1->value.arg[0]); 3949662Slinton printval(n1->value.arg[0]->nodetype); 3959662Slinton putchar(' '); 3969662Slinton } 3979662Slinton putchar('\n'); 3989662Slinton break; 3999662Slinton 4009662Slinton case O_PSYM: 4019662Slinton if (p->value.arg[0]->op == O_SYM) { 4029662Slinton psym(p->value.arg[0]->value.sym); 4039662Slinton } else { 4049662Slinton psym(p->value.arg[0]->nodetype); 4059662Slinton } 4069662Slinton break; 4079662Slinton 4089662Slinton case O_QLINE: 4099662Slinton eval(p->value.arg[1]); 4109662Slinton break; 4119662Slinton 4129662Slinton case O_STEP: 4139662Slinton b = inst_tracing; 4149662Slinton inst_tracing = (Boolean) (not p->value.step.source); 4159662Slinton if (p->value.step.skipcalls) { 4169662Slinton next(); 4179662Slinton } else { 4189662Slinton stepc(); 4199662Slinton } 4209662Slinton inst_tracing = b; 42114674Slinton useInstLoc = (Boolean) (not p->value.step.source); 4229662Slinton printnews(); 4239662Slinton break; 4249662Slinton 4259662Slinton case O_WHATIS: 4269662Slinton if (p->value.arg[0]->op == O_SYM) { 4279662Slinton printdecl(p->value.arg[0]->value.sym); 4289662Slinton } else { 4299662Slinton printdecl(p->value.arg[0]->nodetype); 4309662Slinton } 4319662Slinton break; 4329662Slinton 4339662Slinton case O_WHERE: 4349662Slinton wherecmd(); 4359662Slinton break; 4369662Slinton 4379662Slinton case O_WHEREIS: 43812538Scsvaf if (p->value.arg[0]->op == O_SYM) { 43912538Scsvaf printwhereis(stdout,p->value.arg[0]->value.sym); 44012538Scsvaf } else { 44112538Scsvaf printwhereis(stdout,p->value.arg[0]->nodetype); 44212538Scsvaf } 4439662Slinton break; 4449662Slinton 4459662Slinton case O_WHICH: 44612538Scsvaf if (p->value.arg[0]->op == O_SYM) { 44712538Scsvaf printwhich(stdout,p->value.arg[0]->value.sym); 44812538Scsvaf } else { 44912538Scsvaf printwhich(stdout,p->value.arg[0]->nodetype); 45012538Scsvaf } 4519662Slinton putchar('\n'); 4529662Slinton break; 4539662Slinton 4549662Slinton case O_ALIAS: 4559662Slinton n1 = p->value.arg[0]; 4569662Slinton n2 = p->value.arg[1]; 4579662Slinton if (n1 == nil) { 4589662Slinton print_alias(nil); 4599662Slinton } else if (n2 == nil) { 4609662Slinton print_alias(n1->value.name); 4619662Slinton } else { 4629662Slinton enter_alias(n1->value.name, n2->value.name); 4639662Slinton } 4649662Slinton break; 4659662Slinton 4669662Slinton case O_CALL: 4679662Slinton callproc(p->value.arg[0], p->value.arg[1]); 4689662Slinton break; 4699662Slinton 4709662Slinton case O_CATCH: 4719662Slinton psigtrace(process, p->value.lcon, true); 4729662Slinton break; 4739662Slinton 4749662Slinton case O_EDIT: 4759662Slinton edit(p->value.scon); 4769662Slinton break; 4779662Slinton 47812538Scsvaf case O_DEBUG: 47912538Scsvaf debug(p); 48012538Scsvaf break; 48112538Scsvaf 482*16608Ssam case O_DOWN: 483*16608Ssam checkref(p->value.arg[0]); 484*16608Ssam assert(p->value.arg[0]->op == O_LCON); 485*16608Ssam down(p->value.arg[0]->value.lcon); 486*16608Ssam break; 487*16608Ssam 4889662Slinton case O_DUMP: 4899662Slinton dump(); 4909662Slinton break; 4919662Slinton 4929662Slinton case O_GRIPE: 4939662Slinton gripe(); 4949662Slinton break; 4959662Slinton 4969662Slinton case O_HELP: 4979662Slinton help(); 4989662Slinton break; 4999662Slinton 5009662Slinton case O_IGNORE: 5019662Slinton psigtrace(process, p->value.lcon, false); 5029662Slinton break; 5039662Slinton 504*16608Ssam case O_RETURN: 505*16608Ssam if (p->value.arg[0] == nil) { 506*16608Ssam rtnfunc(nil); 507*16608Ssam } else { 508*16608Ssam assert(p->value.arg[0]->op == O_SYM); 509*16608Ssam rtnfunc(p->value.arg[0]->value.sym); 510*16608Ssam } 511*16608Ssam break; 512*16608Ssam 5139662Slinton case O_RUN: 5149662Slinton run(); 5159662Slinton break; 5169662Slinton 5179662Slinton case O_SOURCE: 5189662Slinton setinput(p->value.scon); 5199662Slinton break; 5209662Slinton 5219662Slinton case O_STATUS: 5229662Slinton status(); 5239662Slinton break; 5249662Slinton 5259662Slinton case O_TRACE: 5269662Slinton case O_TRACEI: 5279662Slinton trace(p); 5289662Slinton break; 5299662Slinton 5309662Slinton case O_STOP: 5319662Slinton case O_STOPI: 5329662Slinton stop(p); 5339662Slinton break; 5349662Slinton 535*16608Ssam case O_UP: 536*16608Ssam checkref(p->value.arg[0]); 537*16608Ssam assert(p->value.arg[0]->op == O_LCON); 538*16608Ssam up(p->value.arg[0]->value.lcon); 539*16608Ssam break; 540*16608Ssam 5419662Slinton case O_ADDEVENT: 5429662Slinton addevent(p->value.event.cond, p->value.event.actions); 5439662Slinton break; 5449662Slinton 5459662Slinton case O_DELETE: 546*16608Ssam n1 = p->value.arg[0]; 547*16608Ssam while (n1->op == O_COMMA) { 548*16608Ssam n2 = n1->value.arg[0]; 549*16608Ssam assert(n2->op == O_LCON); 550*16608Ssam if (not delevent((unsigned int) n2->value.lcon)) { 551*16608Ssam error("unknown event %ld", n2->value.lcon); 552*16608Ssam } 553*16608Ssam n1 = n1->value.arg[1]; 554*16608Ssam } 555*16608Ssam assert(n1->op == O_LCON); 556*16608Ssam if (not delevent((unsigned int) n1->value.lcon)) { 557*16608Ssam error("unknown event %ld", n1->value.lcon); 558*16608Ssam } 5599662Slinton break; 5609662Slinton 5619662Slinton case O_ENDX: 5629662Slinton endprogram(); 5639662Slinton break; 5649662Slinton 5659662Slinton case O_IF: 5669662Slinton if (cond(p->value.event.cond)) { 5679662Slinton evalcmdlist(p->value.event.actions); 5689662Slinton } 5699662Slinton break; 5709662Slinton 5719662Slinton case O_ONCE: 5729662Slinton event_once(p->value.event.cond, p->value.event.actions); 5739662Slinton break; 5749662Slinton 5759662Slinton case O_PRINTCALL: 5769662Slinton printcall(p->value.sym, whatblock(return_addr())); 5779662Slinton break; 5789662Slinton 5799662Slinton case O_PRINTIFCHANGED: 5809662Slinton printifchanged(p->value.arg[0]); 5819662Slinton break; 5829662Slinton 5839662Slinton case O_PRINTRTN: 5849662Slinton printrtn(p->value.sym); 5859662Slinton break; 5869662Slinton 5879662Slinton case O_PRINTSRCPOS: 5889662Slinton getsrcpos(); 5899662Slinton if (p->value.arg[0] == nil) { 5909662Slinton printsrcpos(); 5919662Slinton putchar('\n'); 5929662Slinton printlines(curline, curline); 5939662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 5949662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 5959662Slinton printf("tracei: "); 5969662Slinton printinst(pc, pc); 5979662Slinton } else { 5989662Slinton printf("trace: "); 5999662Slinton printlines(curline, curline); 6009662Slinton } 6019662Slinton } else { 6029662Slinton printsrcpos(); 6039662Slinton printf(": "); 6049662Slinton eval(p->value.arg[0]); 6059662Slinton prtree(stdout, p->value.arg[0]); 6069662Slinton printf(" = "); 6079662Slinton printval(p->value.arg[0]->nodetype); 6089662Slinton putchar('\n'); 6099662Slinton } 6109662Slinton break; 6119662Slinton 6129662Slinton case O_PROCRTN: 6139662Slinton procreturn(p->value.sym); 6149662Slinton break; 6159662Slinton 6169662Slinton case O_STOPIFCHANGED: 6179662Slinton stopifchanged(p->value.arg[0]); 6189662Slinton break; 6199662Slinton 6209662Slinton case O_STOPX: 6219662Slinton isstopped = true; 6229662Slinton break; 6239662Slinton 6249662Slinton case O_TRACEON: 6259662Slinton traceon(p->value.trace.inst, p->value.trace.event, 6269662Slinton p->value.trace.actions); 6279662Slinton break; 6289662Slinton 6299662Slinton case O_TRACEOFF: 6309662Slinton traceoff(p->value.lcon); 6319662Slinton break; 6329662Slinton 6339662Slinton default: 6349662Slinton panic("eval: bad op %d", p->op); 6359662Slinton } 63612538Scsvaf if(debug_flag[2]) { 63712538Scsvaf fprintf(stderr," evaluated %s \n",showoperator(p->op)); 63812538Scsvaf } 63912538Scsvaf 6409662Slinton } 6419662Slinton 6429662Slinton /* 6439662Slinton * Evaluate a list of commands. 6449662Slinton */ 6459662Slinton 6469662Slinton public evalcmdlist(cl) 6479662Slinton Cmdlist cl; 6489662Slinton { 6499662Slinton Command c; 6509662Slinton 6519662Slinton foreach (Command, c, cl) 6529662Slinton evalcmd(c); 6539662Slinton endfor 6549662Slinton } 6559662Slinton 6569662Slinton /* 6579662Slinton * Push "len" bytes onto the expression stack from address "addr" 6589662Slinton * in the process. If there isn't room on the stack, print an error message. 6599662Slinton */ 6609662Slinton 6619662Slinton public rpush(addr, len) 6629662Slinton Address addr; 6639662Slinton int len; 6649662Slinton { 6659662Slinton if (not canpush(len)) { 6669662Slinton error("expression too large to evaluate"); 6679662Slinton } else { 6689662Slinton chksp(); 6699662Slinton dread(sp, addr, len); 6709662Slinton sp += len; 6719662Slinton } 6729662Slinton } 6739662Slinton 6749662Slinton /* 6759662Slinton * Check if the stack has n bytes available. 6769662Slinton */ 6779662Slinton 6789662Slinton public Boolean canpush(n) 6799662Slinton Integer n; 6809662Slinton { 6819662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 6829662Slinton } 6839662Slinton 6849662Slinton /* 6859662Slinton * Push a small scalar of the given type onto the stack. 6869662Slinton */ 6879662Slinton 6889662Slinton public pushsmall(t, v) 6899662Slinton Symbol t; 6909662Slinton long v; 6919662Slinton { 6929662Slinton register Integer s; 6939662Slinton 6949662Slinton s = size(t); 6959662Slinton switch (s) { 6969662Slinton case sizeof(char): 6979662Slinton push(char, v); 6989662Slinton break; 6999662Slinton 7009662Slinton case sizeof(short): 7019662Slinton push(short, v); 7029662Slinton break; 7039662Slinton 7049662Slinton case sizeof(long): 7059662Slinton push(long, v); 7069662Slinton break; 7079662Slinton 7089662Slinton default: 7099662Slinton panic("bad size %d in popsmall", s); 7109662Slinton } 7119662Slinton } 7129662Slinton 7139662Slinton /* 7149662Slinton * Pop an item of the given type which is assumed to be no larger 7159662Slinton * than a long and return it expanded into a long. 7169662Slinton */ 7179662Slinton 7189662Slinton public long popsmall(t) 7199662Slinton Symbol t; 7209662Slinton { 7219662Slinton long r; 7229662Slinton 7239662Slinton switch (size(t)) { 7249662Slinton case sizeof(char): 7259662Slinton r = (long) pop(char); 7269662Slinton break; 7279662Slinton 7289662Slinton case sizeof(short): 7299662Slinton r = (long) pop(short); 7309662Slinton break; 7319662Slinton 7329662Slinton case sizeof(long): 7339662Slinton r = pop(long); 7349662Slinton break; 7359662Slinton 7369662Slinton default: 7379662Slinton panic("popsmall: size is %d", size(t)); 7389662Slinton } 7399662Slinton return r; 7409662Slinton } 7419662Slinton 7429662Slinton /* 7439662Slinton * Evaluate a conditional expression. 7449662Slinton */ 7459662Slinton 7469662Slinton public Boolean cond(p) 7479662Slinton Node p; 7489662Slinton { 7499662Slinton register Boolean b; 7509662Slinton 7519662Slinton if (p == nil) { 7529662Slinton b = true; 7539662Slinton } else { 7549662Slinton eval(p); 75513846Slinton b = (Boolean) pop(Boolrep); 7569662Slinton } 7579662Slinton return b; 7589662Slinton } 7599662Slinton 7609662Slinton /* 7619662Slinton * Return the address corresponding to a given tree. 7629662Slinton */ 7639662Slinton 7649662Slinton public Address lval(p) 7659662Slinton Node p; 7669662Slinton { 7679662Slinton if (p->op == O_RVAL) { 7689662Slinton eval(p->value.arg[0]); 7699662Slinton } else { 7709662Slinton eval(p); 7719662Slinton } 7729662Slinton return (Address) (pop(long)); 7739662Slinton } 7749662Slinton 7759662Slinton /* 7769662Slinton * Process a trace command, translating into the appropriate events 7779662Slinton * and associated actions. 7789662Slinton */ 7799662Slinton 7809662Slinton public trace(p) 7819662Slinton Node p; 7829662Slinton { 7839662Slinton Node exp, place, cond; 7849662Slinton Node left; 7859662Slinton 7869662Slinton exp = p->value.arg[0]; 7879662Slinton place = p->value.arg[1]; 7889662Slinton cond = p->value.arg[2]; 7899662Slinton if (exp == nil) { 7909662Slinton traceall(p->op, place, cond); 79111771Slinton } else if (exp->op == O_QLINE or exp->op == O_LCON) { 7929662Slinton traceinst(p->op, exp, cond); 7939662Slinton } else if (place != nil and place->op == O_QLINE) { 7949662Slinton traceat(p->op, exp, place, cond); 7959662Slinton } else { 7969861Slinton left = exp; 7979861Slinton if (left->op == O_RVAL or left->op == O_CALL) { 7989861Slinton left = left->value.arg[0]; 7999861Slinton } 8009662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 8019662Slinton traceproc(p->op, left->value.sym, place, cond); 8029662Slinton } else { 8039662Slinton tracedata(p->op, exp, place, cond); 8049662Slinton } 8059662Slinton } 8069662Slinton } 8079662Slinton 8089662Slinton /* 8099662Slinton * Set a breakpoint that will turn on tracing. 8109662Slinton */ 8119662Slinton 8129662Slinton private traceall(op, place, cond) 8139662Slinton Operator op; 8149662Slinton Node place; 8159662Slinton Node cond; 8169662Slinton { 8179662Slinton Symbol s; 8189662Slinton Node event; 8199662Slinton Command action; 8209662Slinton 8219662Slinton if (place == nil) { 8229662Slinton s = program; 8239662Slinton } else { 8249662Slinton s = place->value.sym; 8259662Slinton } 8269662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 8279662Slinton action = build(O_PRINTSRCPOS, 8289662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 8299662Slinton if (cond != nil) { 8309662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8319662Slinton } 8329662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 8339662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 83411871Slinton if (isstdin()) { 83511871Slinton printevent(action->value.trace.event); 83611871Slinton } 8379662Slinton } 8389662Slinton 8399662Slinton /* 8409662Slinton * Set up the appropriate breakpoint for tracing an instruction. 8419662Slinton */ 8429662Slinton 8439662Slinton private traceinst(op, exp, cond) 8449662Slinton Operator op; 8459662Slinton Node exp; 8469662Slinton Node cond; 8479662Slinton { 84811771Slinton Node event, wh; 8499662Slinton Command action; 85011871Slinton Event e; 8519662Slinton 85211771Slinton if (exp->op == O_LCON) { 85311771Slinton wh = build(O_QLINE, build(O_SCON, cursource), exp); 85411771Slinton } else { 85511771Slinton wh = exp; 85611771Slinton } 8579662Slinton if (op == O_TRACEI) { 85811771Slinton event = build(O_EQ, build(O_SYM, pcsym), wh); 8599662Slinton } else { 86011771Slinton event = build(O_EQ, build(O_SYM, linesym), wh); 8619662Slinton } 86211771Slinton action = build(O_PRINTSRCPOS, wh); 8639662Slinton if (cond) { 8649662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8659662Slinton } 86611871Slinton e = addevent(event, buildcmdlist(action)); 86711871Slinton if (isstdin()) { 86811871Slinton printevent(e); 86911871Slinton } 8709662Slinton } 8719662Slinton 8729662Slinton /* 8739662Slinton * Set a breakpoint to print an expression at a given line or address. 8749662Slinton */ 8759662Slinton 8769662Slinton private traceat(op, exp, place, cond) 8779662Slinton Operator op; 8789662Slinton Node exp; 8799662Slinton Node place; 8809662Slinton Node cond; 8819662Slinton { 8829662Slinton Node event; 8839662Slinton Command action; 88411871Slinton Event e; 8859662Slinton 8869662Slinton if (op == O_TRACEI) { 8879662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 8889662Slinton } else { 8899662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 8909662Slinton } 8919662Slinton action = build(O_PRINTSRCPOS, exp); 8929662Slinton if (cond != nil) { 8939662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8949662Slinton } 89511871Slinton e = addevent(event, buildcmdlist(action)); 89611871Slinton if (isstdin()) { 89711871Slinton printevent(e); 89811871Slinton } 8999662Slinton } 9009662Slinton 9019662Slinton /* 9029662Slinton * Construct event for tracing a procedure. 9039662Slinton * 9049662Slinton * What we want here is 9059662Slinton * 9069662Slinton * when $proc = p do 9079662Slinton * if <condition> then 9089662Slinton * printcall; 9099662Slinton * once $pc = $retaddr do 9109662Slinton * printrtn; 9119662Slinton * end; 9129662Slinton * end if; 9139662Slinton * end; 9149662Slinton * 9159662Slinton * Note that "once" is like "when" except that the event 9169662Slinton * deletes itself as part of its associated action. 9179662Slinton */ 9189662Slinton 9199662Slinton private traceproc(op, p, place, cond) 9209662Slinton Operator op; 9219662Slinton Symbol p; 9229662Slinton Node place; 9239662Slinton Node cond; 9249662Slinton { 9259662Slinton Node event; 9269662Slinton Command action; 9279662Slinton Cmdlist actionlist; 92811871Slinton Event e; 9299662Slinton 9309662Slinton action = build(O_PRINTCALL, p); 9319662Slinton actionlist = list_alloc(); 9329662Slinton cmdlist_append(action, actionlist); 9339662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 9349662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 9359662Slinton cmdlist_append(action, actionlist); 9369662Slinton if (cond != nil) { 9379662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 9389662Slinton } 9399662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 94011871Slinton e = addevent(event, actionlist); 94111871Slinton if (isstdin()) { 94211871Slinton printevent(e); 94311871Slinton } 9449662Slinton } 9459662Slinton 9469662Slinton /* 9479662Slinton * Set up breakpoint for tracing data. 9489662Slinton */ 9499662Slinton 9509662Slinton private tracedata(op, exp, place, cond) 9519662Slinton Operator op; 9529662Slinton Node exp; 9539662Slinton Node place; 9549662Slinton Node cond; 9559662Slinton { 9569662Slinton Symbol p; 9579662Slinton Node event; 9589662Slinton Command action; 9599662Slinton 9609662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 9619662Slinton if (p == nil) { 9629662Slinton p = program; 9639662Slinton } 9649662Slinton action = build(O_PRINTIFCHANGED, exp); 9659662Slinton if (cond != nil) { 9669662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9679662Slinton } 9689662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 9699662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 9709662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 97111871Slinton if (isstdin()) { 97211871Slinton printevent(action->value.trace.event); 97311871Slinton } 9749662Slinton } 9759662Slinton 9769662Slinton /* 9779662Slinton * Setting and unsetting of stops. 9789662Slinton */ 9799662Slinton 9809662Slinton public stop(p) 9819662Slinton Node p; 9829662Slinton { 98313846Slinton Node exp, place, cond, t; 9849662Slinton Symbol s; 9859662Slinton Command action; 98611871Slinton Event e; 9879662Slinton 9889662Slinton exp = p->value.arg[0]; 9899662Slinton place = p->value.arg[1]; 9909662Slinton cond = p->value.arg[2]; 9919662Slinton if (exp != nil) { 9929662Slinton stopvar(p->op, exp, place, cond); 99313846Slinton } else { 99413846Slinton action = build(O_STOPX); 99513846Slinton if (cond != nil) { 99613846Slinton action = build(O_IF, cond, buildcmdlist(action)); 99711871Slinton } 998*16608Ssam if (place == nil or place->op == O_SYM) { 999*16608Ssam if (place == nil) { 1000*16608Ssam s = program; 1001*16608Ssam } else { 1002*16608Ssam s = place->value.sym; 1003*16608Ssam } 100413846Slinton t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 100513846Slinton if (cond != nil) { 100613846Slinton action = build(O_TRACEON, (p->op == O_STOPI), 100713846Slinton buildcmdlist(action)); 100813846Slinton e = addevent(t, buildcmdlist(action)); 100913846Slinton action->value.trace.event = e; 101013846Slinton } else { 101113846Slinton e = addevent(t, buildcmdlist(action)); 101213846Slinton } 101313846Slinton if (isstdin()) { 101413846Slinton printevent(e); 101513846Slinton } 101613846Slinton } else { 101713846Slinton stopinst(p->op, place, cond, action); 101813846Slinton } 10199662Slinton } 10209662Slinton } 10219662Slinton 102213846Slinton private stopinst(op, place, cond, action) 10239662Slinton Operator op; 10249662Slinton Node place; 10259662Slinton Node cond; 102613846Slinton Command action; 10279662Slinton { 10289662Slinton Node event; 102911871Slinton Event e; 10309662Slinton 10319662Slinton if (op == O_STOP) { 10329662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 10339662Slinton } else { 10349662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 10359662Slinton } 103613846Slinton e = addevent(event, buildcmdlist(action)); 103711871Slinton if (isstdin()) { 103811871Slinton printevent(e); 103911871Slinton } 10409662Slinton } 10419662Slinton 10429662Slinton /* 10439662Slinton * Implement stopping on assignment to a variable by adding it to 10449662Slinton * the variable list. 10459662Slinton */ 10469662Slinton 10479662Slinton private stopvar(op, exp, place, cond) 10489662Slinton Operator op; 10499662Slinton Node exp; 10509662Slinton Node place; 10519662Slinton Node cond; 10529662Slinton { 10539662Slinton Symbol p; 10549662Slinton Node event; 10559662Slinton Command action; 10569662Slinton 105714445Slinton if (place == nil) { 105814445Slinton if (exp->op == O_LCON) { 105914445Slinton p = program; 106014445Slinton } else { 106114445Slinton p = tcontainer(exp); 106214445Slinton if (p == nil) { 106314445Slinton p = program; 106414445Slinton } 106514445Slinton } 106614445Slinton } else { 106714445Slinton p = place->value.sym; 10689662Slinton } 106914445Slinton action = build(O_STOPIFCHANGED, exp); 107014445Slinton if (cond != nil) { 107114445Slinton action = build(O_IF, cond, buildcmdlist(action)); 107214445Slinton } 10739662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 10749662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 10759662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 107611871Slinton if (isstdin()) { 107711871Slinton printevent(action->value.trace.event); 107811871Slinton } 10799662Slinton } 10809662Slinton 10819662Slinton /* 10829662Slinton * Assign the value of an expression to a variable (or term). 10839662Slinton */ 10849662Slinton 10859662Slinton public assign(var, exp) 10869662Slinton Node var; 10879662Slinton Node exp; 10889662Slinton { 10899662Slinton Address addr; 1090*16608Ssam integer varsize, expsize; 10919662Slinton char cvalue; 10929662Slinton short svalue; 10939662Slinton long lvalue; 1094*16608Ssam float fvalue; 10959662Slinton 10969662Slinton if (not compatible(var->nodetype, exp->nodetype)) { 10979662Slinton error("incompatible types"); 10989662Slinton } 10999662Slinton addr = lval(var); 1100*16608Ssam varsize = size(var->nodetype); 1101*16608Ssam expsize = size(exp->nodetype); 11029662Slinton eval(exp); 1103*16608Ssam if (varsize == sizeof(float) and expsize == sizeof(double)) { 1104*16608Ssam fvalue = (float) pop(double); 1105*16608Ssam dwrite(&fvalue, addr, sizeof(fvalue)); 1106*16608Ssam } else { 1107*16608Ssam if (varsize < sizeof(long)) { 1108*16608Ssam lvalue = 0; 1109*16608Ssam popn(expsize, &lvalue); 1110*16608Ssam switch (varsize) { 1111*16608Ssam case sizeof(char): 1112*16608Ssam cvalue = lvalue; 1113*16608Ssam dwrite(&cvalue, addr, sizeof(cvalue)); 1114*16608Ssam break; 11159662Slinton 1116*16608Ssam case sizeof(short): 1117*16608Ssam svalue = lvalue; 1118*16608Ssam dwrite(&svalue, addr, sizeof(svalue)); 1119*16608Ssam break; 11209662Slinton 1121*16608Ssam default: 1122*16608Ssam panic("bad size %d", varsize); 1123*16608Ssam } 1124*16608Ssam } else { 1125*16608Ssam if (expsize <= varsize) { 1126*16608Ssam sp -= expsize; 1127*16608Ssam dwrite(sp, addr, expsize); 1128*16608Ssam } else { 1129*16608Ssam sp -= expsize; 1130*16608Ssam dwrite(sp, addr, varsize); 1131*16608Ssam } 11329662Slinton } 11339662Slinton } 11349662Slinton } 11359662Slinton 11369662Slinton /* 11379662Slinton * Send some nasty mail to the current support person. 11389662Slinton */ 11399662Slinton 11409662Slinton public gripe() 11419662Slinton { 11429662Slinton typedef Operation(); 11439662Slinton Operation *old; 114414445Slinton int pid, status; 1145*16608Ssam extern int versionNumber; 1146*16608Ssam char subject[100]; 114714445Slinton char *maintainer = "linton@berkeley"; 11489662Slinton 11499662Slinton puts("Type control-D to end your message. Be sure to include"); 11509662Slinton puts("your name and the name of the file you are debugging."); 11519662Slinton putchar('\n'); 11529662Slinton old = signal(SIGINT, SIG_DFL); 1153*16608Ssam sprintf(subject, "dbx (version %d) gripe", versionNumber); 1154*16608Ssam pid = back("Mail", stdin, stdout, "-s", subject, maintainer, nil); 115514445Slinton signal(SIGINT, SIG_IGN); 115614445Slinton pwait(pid, &status); 11579662Slinton signal(SIGINT, old); 115814445Slinton if (status == 0) { 115914445Slinton puts("Thank you."); 116014445Slinton } else { 116114445Slinton puts("\nMail not sent."); 116214445Slinton } 11639662Slinton } 11649662Slinton 11659662Slinton /* 11669662Slinton * Give the user some help. 11679662Slinton */ 11689662Slinton 11699662Slinton public help() 11709662Slinton { 11719662Slinton puts("run - begin execution of the program"); 1172*16608Ssam puts("print <exp> - print the value of the expression"); 1173*16608Ssam puts("where - print currently active procedures"); 1174*16608Ssam puts("stop at <line> - suspend execution at the line"); 1175*16608Ssam puts("stop in <proc> - suspend execution when <proc> is called"); 11769662Slinton puts("cont - continue execution"); 11779662Slinton puts("step - single step one line"); 11789662Slinton puts("next - step to next line (skip over calls)"); 11799662Slinton puts("trace <line#> - trace execution of the line"); 11809662Slinton puts("trace <proc> - trace calls to the procedure"); 11819662Slinton puts("trace <var> - trace changes to the variable"); 11829662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 11839662Slinton puts("status - print trace/stop's in effect"); 11849662Slinton puts("delete <number> - remove trace or stop of given number"); 1185*16608Ssam puts("call <proc> - call a procedure in program"); 11869662Slinton puts("whatis <name> - print the declaration of the name"); 11879662Slinton puts("list <line>, <line> - list source lines"); 11889662Slinton puts("gripe - send mail to the person in charge of dbx"); 11899662Slinton puts("quit - exit dbx"); 11909662Slinton } 11919662Slinton 11929662Slinton /* 11939662Slinton * Divert output to the given file name. 11949662Slinton * Cannot redirect to an existing file. 11959662Slinton */ 11969662Slinton 11979662Slinton private int so_fd; 11989662Slinton private Boolean notstdout; 11999662Slinton 12009662Slinton public setout(filename) 12019662Slinton String filename; 12029662Slinton { 12039662Slinton File f; 12049662Slinton 12059662Slinton f = fopen(filename, "r"); 12069662Slinton if (f != nil) { 12079662Slinton fclose(f); 12089662Slinton error("%s: file already exists", filename); 12099662Slinton } else { 12109662Slinton so_fd = dup(1); 12119662Slinton close(1); 12129662Slinton if (creat(filename, 0666) == nil) { 12139662Slinton unsetout(); 12149662Slinton error("can't create %s", filename); 12159662Slinton } 12169662Slinton notstdout = true; 12179662Slinton } 12189662Slinton } 12199662Slinton 12209662Slinton /* 12219662Slinton * Revert output to standard output. 12229662Slinton */ 12239662Slinton 12249662Slinton public unsetout() 12259662Slinton { 12269662Slinton fflush(stdout); 12279662Slinton close(1); 12289662Slinton if (dup(so_fd) != 1) { 12299662Slinton panic("standard out dup failed"); 12309662Slinton } 12319662Slinton close(so_fd); 12329662Slinton notstdout = false; 12339662Slinton } 12349662Slinton 12359662Slinton /* 12369662Slinton * Determine is standard output is currently being redirected 12379662Slinton * to a file (as far as we know). 12389662Slinton */ 12399662Slinton 12409662Slinton public Boolean isredirected() 12419662Slinton { 12429662Slinton return notstdout; 12439662Slinton } 1244