19662Slinton /* Copyright (c) 1982 Regents of the University of California */ 29662Slinton 3*11771Slinton static char sccsid[] = "@(#)eval.c 1.5 03/30/83"; 49662Slinton 59662Slinton /* 69662Slinton * Tree evaluation. 79662Slinton */ 89662Slinton 99662Slinton #include "defs.h" 109662Slinton #include "tree.h" 119662Slinton #include "operators.h" 129662Slinton #include "eval.h" 139662Slinton #include "events.h" 149662Slinton #include "symbols.h" 159662Slinton #include "scanner.h" 169662Slinton #include "source.h" 179662Slinton #include "object.h" 189662Slinton #include "mappings.h" 199662Slinton #include "process.h" 209662Slinton #include "machine.h" 219662Slinton #include <signal.h> 229662Slinton 239662Slinton #ifndef public 249662Slinton 259662Slinton #include "machine.h" 269662Slinton 279662Slinton #define STACKSIZE 2000 289662Slinton 299662Slinton typedef Char Stack; 309662Slinton 319662Slinton #define push(type, value) { \ 329662Slinton ((type *) (sp += sizeof(type)))[-1] = (value); \ 339662Slinton } 349662Slinton 359662Slinton #define pop(type) ( \ 369662Slinton (*((type *) (sp -= sizeof(type)))) \ 379662Slinton ) 389662Slinton 399662Slinton #define alignstack() { \ 409662Slinton sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \ 419662Slinton } 429662Slinton 439662Slinton #endif 449662Slinton 459662Slinton public Stack stack[STACKSIZE]; 469662Slinton public Stack *sp = &stack[0]; 479662Slinton 489662Slinton #define chksp() \ 499662Slinton { \ 509662Slinton if (sp < &stack[0]) { \ 519662Slinton panic("stack underflow"); \ 529662Slinton } \ 539662Slinton } 549662Slinton 559662Slinton #define poparg(n, r, fr) { \ 569662Slinton eval(p->value.arg[n]); \ 579662Slinton if (isreal(p->op)) { \ 589662Slinton fr = pop(double); \ 599662Slinton } else if (isint(p->op)) { \ 609662Slinton r = popsmall(p->value.arg[n]->nodetype); \ 619662Slinton } \ 629662Slinton } 639662Slinton 649662Slinton #define Boolrep char /* underlying representation type for booleans */ 659662Slinton 669662Slinton /* 679662Slinton * Evaluate a parse tree leaving the value on the top of the stack. 689662Slinton */ 699662Slinton 709662Slinton public eval(p) 719662Slinton register Node p; 729662Slinton { 739662Slinton long r0, r1; 749662Slinton double fr0, fr1; 759662Slinton Address addr; 769662Slinton long i, n; 779662Slinton int len; 789662Slinton Symbol s, f; 799662Slinton Node n1, n2; 809662Slinton Boolean b; 819662Slinton File file; 829662Slinton 839662Slinton checkref(p); 849662Slinton switch (degree(p->op)) { 859662Slinton case BINARY: 869662Slinton poparg(1, r1, fr1); 879662Slinton poparg(0, r0, fr0); 889662Slinton break; 899662Slinton 909662Slinton case UNARY: 919662Slinton poparg(0, r0, fr0); 929662Slinton break; 939662Slinton 949662Slinton default: 959662Slinton /* do nothing */; 969662Slinton } 979662Slinton switch (p->op) { 989662Slinton case O_SYM: 999662Slinton s = p->value.sym; 1009662Slinton if (s == retaddrsym) { 1019662Slinton push(long, return_addr()); 1029662Slinton } else { 1039662Slinton if (isvariable(s)) { 1049662Slinton if (s != program and not isactive(container(s))) { 1059662Slinton error("\"%s\" is not active", symname(s)); 1069662Slinton } 1079662Slinton push(long, address(s, nil)); 1089662Slinton } else if (isblock(s)) { 1099662Slinton push(Symbol, s); 1109662Slinton } else { 1119662Slinton error("can't evaluate a %s", classname(s)); 1129662Slinton } 1139662Slinton } 1149662Slinton break; 1159662Slinton 1169662Slinton case O_LCON: 1179662Slinton r0 = p->value.lcon; 1189662Slinton pushsmall(p->nodetype, r0); 1199662Slinton break; 1209662Slinton 1219662Slinton case O_FCON: 1229662Slinton push(double, p->value.fcon); 1239662Slinton break; 1249662Slinton 1259662Slinton case O_SCON: 1269662Slinton len = size(p->nodetype); 1279662Slinton mov(p->value.scon, sp, len); 1289662Slinton sp += len; 1299662Slinton break; 1309662Slinton 1319662Slinton case O_INDEX: 1329662Slinton n = pop(long); 1339662Slinton i = evalindex(p->value.arg[0]->nodetype, 1349662Slinton popsmall(p->value.arg[1]->nodetype)); 1359662Slinton push(long, n + i*size(p->nodetype)); 1369662Slinton break; 1379662Slinton 1389662Slinton case O_DOT: 1399662Slinton s = p->value.arg[1]->value.sym; 1409662Slinton n = lval(p->value.arg[0]); 1419662Slinton push(long, n + (s->symvalue.field.offset div 8)); 1429662Slinton break; 1439662Slinton 1449662Slinton /* 1459662Slinton * Get the value of the expression addressed by the top of the stack. 1469662Slinton * Push the result back on the stack. 1479662Slinton */ 1489662Slinton 1499662Slinton case O_INDIR: 1509662Slinton case O_RVAL: 1519662Slinton addr = pop(long); 1529662Slinton if (addr == 0) { 1539662Slinton error("reference through nil pointer"); 1549662Slinton } 1559662Slinton if (p->op == O_INDIR) { 1569662Slinton len = sizeof(long); 1579662Slinton } else { 1589662Slinton len = size(p->nodetype); 1599662Slinton } 1609662Slinton rpush(addr, len); 1619662Slinton break; 1629662Slinton 16311175Slinton /* 16411175Slinton * Effectively, we want to pop n bytes off for the evaluated subtree 16511175Slinton * and push len bytes on for the new type of the same tree. 16611175Slinton */ 16711175Slinton case O_TYPERENAME: 16811175Slinton n = size(p->value.arg[0]->nodetype); 16911175Slinton len = size(p->nodetype); 17011175Slinton sp = sp - n + len; 17111175Slinton break; 17211175Slinton 1739662Slinton case O_COMMA: 1749662Slinton break; 1759662Slinton 1769662Slinton case O_ITOF: 1779662Slinton push(double, (double) r0); 1789662Slinton break; 1799662Slinton 1809662Slinton case O_ADD: 1819662Slinton push(long, r0+r1); 1829662Slinton break; 1839662Slinton 1849662Slinton case O_ADDF: 1859662Slinton push(double, fr0+fr1); 1869662Slinton break; 1879662Slinton 1889662Slinton case O_SUB: 1899662Slinton push(long, r0-r1); 1909662Slinton break; 1919662Slinton 1929662Slinton case O_SUBF: 1939662Slinton push(double, fr0-fr1); 1949662Slinton break; 1959662Slinton 1969662Slinton case O_NEG: 1979662Slinton push(long, -r0); 1989662Slinton break; 1999662Slinton 2009662Slinton case O_NEGF: 2019662Slinton push(double, -fr0); 2029662Slinton break; 2039662Slinton 2049662Slinton case O_MUL: 2059662Slinton push(long, r0*r1); 2069662Slinton break; 2079662Slinton 2089662Slinton case O_MULF: 2099662Slinton push(double, fr0*fr1); 2109662Slinton break; 2119662Slinton 2129662Slinton case O_DIVF: 2139662Slinton if (fr1 == 0) { 2149662Slinton error("error: division by 0"); 2159662Slinton } 2169662Slinton push(double, fr0 / fr1); 2179662Slinton break; 2189662Slinton 2199662Slinton case O_DIV: 2209662Slinton if (r1 == 0) { 2219662Slinton error("error: div by 0"); 2229662Slinton } 2239662Slinton push(long, r0 div r1); 2249662Slinton break; 2259662Slinton 2269662Slinton case O_MOD: 2279662Slinton if (r1 == 0) { 2289662Slinton error("error: mod by 0"); 2299662Slinton } 2309662Slinton push(long, r0 mod r1); 2319662Slinton break; 2329662Slinton 2339662Slinton case O_LT: 2349662Slinton push(Boolrep, r0 < r1); 2359662Slinton break; 2369662Slinton 2379662Slinton case O_LTF: 2389662Slinton push(Boolrep, fr0 < fr1); 2399662Slinton break; 2409662Slinton 2419662Slinton case O_LE: 2429662Slinton push(Boolrep, r0 <= r1); 2439662Slinton break; 2449662Slinton 2459662Slinton case O_LEF: 2469662Slinton push(Boolrep, fr0 <= fr1); 2479662Slinton break; 2489662Slinton 2499662Slinton case O_GT: 2509662Slinton push(Boolrep, r0 > r1); 2519662Slinton break; 2529662Slinton 2539662Slinton case O_GTF: 2549662Slinton push(Boolrep, fr0 > fr1); 2559662Slinton break; 2569662Slinton 2579662Slinton case O_EQ: 2589662Slinton push(Boolrep, r0 == r1); 2599662Slinton break; 2609662Slinton 2619662Slinton case O_EQF: 2629662Slinton push(Boolrep, fr0 == fr1); 2639662Slinton break; 2649662Slinton 2659662Slinton case O_NE: 2669662Slinton push(Boolrep, r0 != r1); 2679662Slinton break; 2689662Slinton 2699662Slinton case O_NEF: 2709662Slinton push(Boolrep, fr0 != fr1); 2719662Slinton break; 2729662Slinton 2739662Slinton case O_AND: 2749662Slinton push(Boolrep, r0 and r1); 2759662Slinton break; 2769662Slinton 2779662Slinton case O_OR: 2789662Slinton push(Boolrep, r0 or r1); 2799662Slinton break; 2809662Slinton 2819662Slinton case O_ASSIGN: 2829662Slinton assign(p->value.arg[0], p->value.arg[1]); 2839662Slinton break; 2849662Slinton 2859662Slinton case O_CHFILE: 2869662Slinton if (p->value.scon == nil) { 2879662Slinton printf("%s\n", cursource); 2889662Slinton } else { 2899662Slinton file = opensource(p->value.scon); 2909662Slinton if (file == nil) { 2919662Slinton error("can't read \"%s\"", p->value.scon); 2929662Slinton } else { 2939662Slinton fclose(file); 2949662Slinton setsource(p->value.scon); 2959662Slinton } 2969662Slinton } 2979662Slinton break; 2989662Slinton 2999662Slinton case O_CONT: 3009662Slinton cont(); 3019662Slinton printnews(); 3029662Slinton break; 3039662Slinton 3049662Slinton case O_LIST: 3059662Slinton if (p->value.arg[0]->op == O_SYM) { 3069662Slinton f = p->value.arg[0]->value.sym; 3079662Slinton addr = firstline(f); 3089662Slinton if (addr == NOADDR) { 3099662Slinton error("no source lines for \"%s\"", symname(f)); 3109662Slinton } 3119662Slinton setsource(srcfilename(addr)); 3129662Slinton r0 = srcline(addr) - 5; 3139662Slinton r1 = r0 + 10; 3149662Slinton if (r0 < 1) { 3159662Slinton r0 = 1; 3169662Slinton } 3179662Slinton } else { 3189662Slinton eval(p->value.arg[0]); 3199662Slinton r0 = pop(long); 3209662Slinton eval(p->value.arg[1]); 3219662Slinton r1 = pop(long); 3229662Slinton } 3239662Slinton printlines((Lineno) r0, (Lineno) r1); 3249662Slinton break; 3259662Slinton 3269662Slinton case O_FUNC: 3279662Slinton if (p->value.arg[0] == nil) { 3289662Slinton printname(stdout, curfunc); 3299662Slinton putchar('\n'); 3309662Slinton } else { 3319662Slinton curfunc = p->value.arg[0]->value.sym; 332*11771Slinton if (isblock(curfunc) and not ismodule(curfunc)) { 333*11771Slinton error("%s is not a procedure or function", 334*11771Slinton symname(curfunc)); 335*11771Slinton } 3369662Slinton addr = codeloc(curfunc); 3379662Slinton if (addr != NOADDR) { 3389662Slinton setsource(srcfilename(addr)); 3399662Slinton cursrcline = srcline(addr) - 5; 3409662Slinton if (cursrcline < 1) { 3419662Slinton cursrcline = 1; 3429662Slinton } 3439662Slinton } 3449662Slinton } 3459662Slinton break; 3469662Slinton 3479662Slinton case O_EXAMINE: 3489662Slinton eval(p->value.examine.beginaddr); 3499662Slinton r0 = pop(long); 3509662Slinton if (p->value.examine.endaddr == nil) { 3519662Slinton n = p->value.examine.count; 35211175Slinton if (n == 0) { 35311175Slinton printvalue(r0, p->value.examine.mode); 35411175Slinton } else if (streq(p->value.examine.mode, "i")) { 3559662Slinton printninst(n, (Address) r0); 3569662Slinton } else { 3579662Slinton printndata(n, (Address) r0, p->value.examine.mode); 3589662Slinton } 3599662Slinton } else { 3609662Slinton eval(p->value.examine.endaddr); 3619662Slinton r1 = pop(long); 3629662Slinton if (streq(p->value.examine.mode, "i")) { 3639662Slinton printinst((Address)r0, (Address)r1); 3649662Slinton } else { 3659662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 3669662Slinton } 3679662Slinton } 3689662Slinton break; 3699662Slinton 3709662Slinton case O_PRINT: 3719662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 3729662Slinton eval(n1->value.arg[0]); 3739662Slinton printval(n1->value.arg[0]->nodetype); 3749662Slinton putchar(' '); 3759662Slinton } 3769662Slinton putchar('\n'); 3779662Slinton break; 3789662Slinton 3799662Slinton case O_PSYM: 3809662Slinton if (p->value.arg[0]->op == O_SYM) { 3819662Slinton psym(p->value.arg[0]->value.sym); 3829662Slinton } else { 3839662Slinton psym(p->value.arg[0]->nodetype); 3849662Slinton } 3859662Slinton break; 3869662Slinton 3879662Slinton case O_QLINE: 3889662Slinton eval(p->value.arg[1]); 3899662Slinton break; 3909662Slinton 3919662Slinton case O_STEP: 3929662Slinton b = inst_tracing; 3939662Slinton inst_tracing = (Boolean) (not p->value.step.source); 3949662Slinton if (p->value.step.skipcalls) { 3959662Slinton next(); 3969662Slinton } else { 3979662Slinton stepc(); 3989662Slinton } 3999662Slinton inst_tracing = b; 4009662Slinton printnews(); 4019662Slinton break; 4029662Slinton 4039662Slinton case O_WHATIS: 4049662Slinton if (p->value.arg[0]->op == O_SYM) { 4059662Slinton printdecl(p->value.arg[0]->value.sym); 4069662Slinton } else { 4079662Slinton printdecl(p->value.arg[0]->nodetype); 4089662Slinton } 4099662Slinton break; 4109662Slinton 4119662Slinton case O_WHERE: 4129662Slinton wherecmd(); 4139662Slinton break; 4149662Slinton 4159662Slinton case O_WHEREIS: 4169662Slinton printwhereis(stdout, p->value.arg[0]->value.sym); 4179662Slinton break; 4189662Slinton 4199662Slinton case O_WHICH: 4209662Slinton printwhich(stdout, p->value.arg[0]->value.sym); 4219662Slinton putchar('\n'); 4229662Slinton break; 4239662Slinton 4249662Slinton case O_ALIAS: 4259662Slinton n1 = p->value.arg[0]; 4269662Slinton n2 = p->value.arg[1]; 4279662Slinton if (n1 == nil) { 4289662Slinton print_alias(nil); 4299662Slinton } else if (n2 == nil) { 4309662Slinton print_alias(n1->value.name); 4319662Slinton } else { 4329662Slinton enter_alias(n1->value.name, n2->value.name); 4339662Slinton } 4349662Slinton break; 4359662Slinton 4369662Slinton case O_CALL: 4379662Slinton callproc(p->value.arg[0], p->value.arg[1]); 4389662Slinton break; 4399662Slinton 4409662Slinton case O_CATCH: 4419662Slinton psigtrace(process, p->value.lcon, true); 4429662Slinton break; 4439662Slinton 4449662Slinton case O_EDIT: 4459662Slinton edit(p->value.scon); 4469662Slinton break; 4479662Slinton 4489662Slinton case O_DUMP: 4499662Slinton dump(); 4509662Slinton break; 4519662Slinton 4529662Slinton case O_GRIPE: 4539662Slinton gripe(); 4549662Slinton break; 4559662Slinton 4569662Slinton case O_HELP: 4579662Slinton help(); 4589662Slinton break; 4599662Slinton 4609662Slinton case O_IGNORE: 4619662Slinton psigtrace(process, p->value.lcon, false); 4629662Slinton break; 4639662Slinton 4649662Slinton case O_RUN: 4659662Slinton run(); 4669662Slinton break; 4679662Slinton 4689662Slinton case O_SOURCE: 4699662Slinton setinput(p->value.scon); 4709662Slinton break; 4719662Slinton 4729662Slinton case O_STATUS: 4739662Slinton status(); 4749662Slinton break; 4759662Slinton 4769662Slinton case O_TRACE: 4779662Slinton case O_TRACEI: 4789662Slinton trace(p); 4799662Slinton if (isstdin()) { 4809662Slinton status(); 4819662Slinton } 4829662Slinton break; 4839662Slinton 4849662Slinton case O_STOP: 4859662Slinton case O_STOPI: 4869662Slinton stop(p); 4879662Slinton if (isstdin()) { 4889662Slinton status(); 4899662Slinton } 4909662Slinton break; 4919662Slinton 4929662Slinton case O_ADDEVENT: 4939662Slinton addevent(p->value.event.cond, p->value.event.actions); 4949662Slinton break; 4959662Slinton 4969662Slinton case O_DELETE: 4979662Slinton delevent((unsigned int) p->value.lcon); 4989662Slinton break; 4999662Slinton 5009662Slinton case O_ENDX: 5019662Slinton endprogram(); 5029662Slinton break; 5039662Slinton 5049662Slinton case O_IF: 5059662Slinton if (cond(p->value.event.cond)) { 5069662Slinton evalcmdlist(p->value.event.actions); 5079662Slinton } 5089662Slinton break; 5099662Slinton 5109662Slinton case O_ONCE: 5119662Slinton event_once(p->value.event.cond, p->value.event.actions); 5129662Slinton break; 5139662Slinton 5149662Slinton case O_PRINTCALL: 5159662Slinton printcall(p->value.sym, whatblock(return_addr())); 5169662Slinton break; 5179662Slinton 5189662Slinton case O_PRINTIFCHANGED: 5199662Slinton printifchanged(p->value.arg[0]); 5209662Slinton break; 5219662Slinton 5229662Slinton case O_PRINTRTN: 5239662Slinton printrtn(p->value.sym); 5249662Slinton break; 5259662Slinton 5269662Slinton case O_PRINTSRCPOS: 5279662Slinton getsrcpos(); 5289662Slinton if (p->value.arg[0] == nil) { 5299662Slinton printsrcpos(); 5309662Slinton putchar('\n'); 5319662Slinton printlines(curline, curline); 5329662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 5339662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 5349662Slinton printf("tracei: "); 5359662Slinton printinst(pc, pc); 5369662Slinton } else { 5379662Slinton printf("trace: "); 5389662Slinton printlines(curline, curline); 5399662Slinton } 5409662Slinton } else { 5419662Slinton printsrcpos(); 5429662Slinton printf(": "); 5439662Slinton eval(p->value.arg[0]); 5449662Slinton prtree(stdout, p->value.arg[0]); 5459662Slinton printf(" = "); 5469662Slinton printval(p->value.arg[0]->nodetype); 5479662Slinton putchar('\n'); 5489662Slinton } 5499662Slinton break; 5509662Slinton 5519662Slinton case O_PROCRTN: 5529662Slinton procreturn(p->value.sym); 5539662Slinton break; 5549662Slinton 5559662Slinton case O_STOPIFCHANGED: 5569662Slinton stopifchanged(p->value.arg[0]); 5579662Slinton break; 5589662Slinton 5599662Slinton case O_STOPX: 5609662Slinton isstopped = true; 5619662Slinton break; 5629662Slinton 5639662Slinton case O_TRACEON: 5649662Slinton traceon(p->value.trace.inst, p->value.trace.event, 5659662Slinton p->value.trace.actions); 5669662Slinton break; 5679662Slinton 5689662Slinton case O_TRACEOFF: 5699662Slinton traceoff(p->value.lcon); 5709662Slinton break; 5719662Slinton 5729662Slinton default: 5739662Slinton panic("eval: bad op %d", p->op); 5749662Slinton } 5759662Slinton } 5769662Slinton 5779662Slinton /* 5789662Slinton * Evaluate a list of commands. 5799662Slinton */ 5809662Slinton 5819662Slinton public evalcmdlist(cl) 5829662Slinton Cmdlist cl; 5839662Slinton { 5849662Slinton Command c; 5859662Slinton 5869662Slinton foreach (Command, c, cl) 5879662Slinton evalcmd(c); 5889662Slinton endfor 5899662Slinton } 5909662Slinton 5919662Slinton /* 5929662Slinton * Push "len" bytes onto the expression stack from address "addr" 5939662Slinton * in the process. If there isn't room on the stack, print an error message. 5949662Slinton */ 5959662Slinton 5969662Slinton public rpush(addr, len) 5979662Slinton Address addr; 5989662Slinton int len; 5999662Slinton { 6009662Slinton if (not canpush(len)) { 6019662Slinton error("expression too large to evaluate"); 6029662Slinton } else { 6039662Slinton chksp(); 6049662Slinton dread(sp, addr, len); 6059662Slinton sp += len; 6069662Slinton } 6079662Slinton } 6089662Slinton 6099662Slinton /* 6109662Slinton * Check if the stack has n bytes available. 6119662Slinton */ 6129662Slinton 6139662Slinton public Boolean canpush(n) 6149662Slinton Integer n; 6159662Slinton { 6169662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 6179662Slinton } 6189662Slinton 6199662Slinton /* 6209662Slinton * Push a small scalar of the given type onto the stack. 6219662Slinton */ 6229662Slinton 6239662Slinton public pushsmall(t, v) 6249662Slinton Symbol t; 6259662Slinton long v; 6269662Slinton { 6279662Slinton register Integer s; 6289662Slinton 6299662Slinton s = size(t); 6309662Slinton switch (s) { 6319662Slinton case sizeof(char): 6329662Slinton push(char, v); 6339662Slinton break; 6349662Slinton 6359662Slinton case sizeof(short): 6369662Slinton push(short, v); 6379662Slinton break; 6389662Slinton 6399662Slinton case sizeof(long): 6409662Slinton push(long, v); 6419662Slinton break; 6429662Slinton 6439662Slinton default: 6449662Slinton panic("bad size %d in popsmall", s); 6459662Slinton } 6469662Slinton } 6479662Slinton 6489662Slinton /* 6499662Slinton * Pop an item of the given type which is assumed to be no larger 6509662Slinton * than a long and return it expanded into a long. 6519662Slinton */ 6529662Slinton 6539662Slinton public long popsmall(t) 6549662Slinton Symbol t; 6559662Slinton { 6569662Slinton long r; 6579662Slinton 6589662Slinton switch (size(t)) { 6599662Slinton case sizeof(char): 6609662Slinton r = (long) pop(char); 6619662Slinton break; 6629662Slinton 6639662Slinton case sizeof(short): 6649662Slinton r = (long) pop(short); 6659662Slinton break; 6669662Slinton 6679662Slinton case sizeof(long): 6689662Slinton r = pop(long); 6699662Slinton break; 6709662Slinton 6719662Slinton default: 6729662Slinton panic("popsmall: size is %d", size(t)); 6739662Slinton } 6749662Slinton return r; 6759662Slinton } 6769662Slinton 6779662Slinton /* 6789662Slinton * Evaluate a conditional expression. 6799662Slinton */ 6809662Slinton 6819662Slinton public Boolean cond(p) 6829662Slinton Node p; 6839662Slinton { 6849662Slinton register Boolean b; 6859662Slinton 6869662Slinton if (p == nil) { 6879662Slinton b = true; 6889662Slinton } else { 6899662Slinton eval(p); 6909662Slinton b = pop(Boolean); 6919662Slinton } 6929662Slinton return b; 6939662Slinton } 6949662Slinton 6959662Slinton /* 6969662Slinton * Return the address corresponding to a given tree. 6979662Slinton */ 6989662Slinton 6999662Slinton public Address lval(p) 7009662Slinton Node p; 7019662Slinton { 7029662Slinton if (p->op == O_RVAL) { 7039662Slinton eval(p->value.arg[0]); 7049662Slinton } else { 7059662Slinton eval(p); 7069662Slinton } 7079662Slinton return (Address) (pop(long)); 7089662Slinton } 7099662Slinton 7109662Slinton /* 7119662Slinton * Process a trace command, translating into the appropriate events 7129662Slinton * and associated actions. 7139662Slinton */ 7149662Slinton 7159662Slinton public trace(p) 7169662Slinton Node p; 7179662Slinton { 7189662Slinton Node exp, place, cond; 7199662Slinton Node left; 7209662Slinton 7219662Slinton exp = p->value.arg[0]; 7229662Slinton place = p->value.arg[1]; 7239662Slinton cond = p->value.arg[2]; 7249662Slinton if (exp == nil) { 7259662Slinton traceall(p->op, place, cond); 726*11771Slinton } else if (exp->op == O_QLINE or exp->op == O_LCON) { 7279662Slinton traceinst(p->op, exp, cond); 7289662Slinton } else if (place != nil and place->op == O_QLINE) { 7299662Slinton traceat(p->op, exp, place, cond); 7309662Slinton } else { 7319861Slinton left = exp; 7329861Slinton if (left->op == O_RVAL or left->op == O_CALL) { 7339861Slinton left = left->value.arg[0]; 7349861Slinton } 7359662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 7369662Slinton traceproc(p->op, left->value.sym, place, cond); 7379662Slinton } else { 7389662Slinton tracedata(p->op, exp, place, cond); 7399662Slinton } 7409662Slinton } 7419662Slinton } 7429662Slinton 7439662Slinton /* 7449662Slinton * Set a breakpoint that will turn on tracing. 7459662Slinton */ 7469662Slinton 7479662Slinton private traceall(op, place, cond) 7489662Slinton Operator op; 7499662Slinton Node place; 7509662Slinton Node cond; 7519662Slinton { 7529662Slinton Symbol s; 7539662Slinton Node event; 7549662Slinton Command action; 7559662Slinton 7569662Slinton if (place == nil) { 7579662Slinton s = program; 7589662Slinton } else { 7599662Slinton s = place->value.sym; 7609662Slinton } 7619662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 7629662Slinton action = build(O_PRINTSRCPOS, 7639662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 7649662Slinton if (cond != nil) { 7659662Slinton action = build(O_IF, cond, buildcmdlist(action)); 7669662Slinton } 7679662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 7689662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 7699662Slinton } 7709662Slinton 7719662Slinton /* 7729662Slinton * Set up the appropriate breakpoint for tracing an instruction. 7739662Slinton */ 7749662Slinton 7759662Slinton private traceinst(op, exp, cond) 7769662Slinton Operator op; 7779662Slinton Node exp; 7789662Slinton Node cond; 7799662Slinton { 780*11771Slinton Node event, wh; 7819662Slinton Command action; 7829662Slinton 783*11771Slinton if (exp->op == O_LCON) { 784*11771Slinton wh = build(O_QLINE, build(O_SCON, cursource), exp); 785*11771Slinton } else { 786*11771Slinton wh = exp; 787*11771Slinton } 7889662Slinton if (op == O_TRACEI) { 789*11771Slinton event = build(O_EQ, build(O_SYM, pcsym), wh); 7909662Slinton } else { 791*11771Slinton event = build(O_EQ, build(O_SYM, linesym), wh); 7929662Slinton } 793*11771Slinton action = build(O_PRINTSRCPOS, wh); 7949662Slinton if (cond) { 7959662Slinton action = build(O_IF, cond, buildcmdlist(action)); 7969662Slinton } 7979662Slinton addevent(event, buildcmdlist(action)); 7989662Slinton } 7999662Slinton 8009662Slinton /* 8019662Slinton * Set a breakpoint to print an expression at a given line or address. 8029662Slinton */ 8039662Slinton 8049662Slinton private traceat(op, exp, place, cond) 8059662Slinton Operator op; 8069662Slinton Node exp; 8079662Slinton Node place; 8089662Slinton Node cond; 8099662Slinton { 8109662Slinton Node event; 8119662Slinton Command action; 8129662Slinton 8139662Slinton if (op == O_TRACEI) { 8149662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 8159662Slinton } else { 8169662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 8179662Slinton } 8189662Slinton action = build(O_PRINTSRCPOS, exp); 8199662Slinton if (cond != nil) { 8209662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8219662Slinton } 8229662Slinton addevent(event, buildcmdlist(action)); 8239662Slinton } 8249662Slinton 8259662Slinton /* 8269662Slinton * Construct event for tracing a procedure. 8279662Slinton * 8289662Slinton * What we want here is 8299662Slinton * 8309662Slinton * when $proc = p do 8319662Slinton * if <condition> then 8329662Slinton * printcall; 8339662Slinton * once $pc = $retaddr do 8349662Slinton * printrtn; 8359662Slinton * end; 8369662Slinton * end if; 8379662Slinton * end; 8389662Slinton * 8399662Slinton * Note that "once" is like "when" except that the event 8409662Slinton * deletes itself as part of its associated action. 8419662Slinton */ 8429662Slinton 8439662Slinton private traceproc(op, p, place, cond) 8449662Slinton Operator op; 8459662Slinton Symbol p; 8469662Slinton Node place; 8479662Slinton Node cond; 8489662Slinton { 8499662Slinton Node event; 8509662Slinton Command action; 8519662Slinton Cmdlist actionlist; 8529662Slinton 8539662Slinton action = build(O_PRINTCALL, p); 8549662Slinton actionlist = list_alloc(); 8559662Slinton cmdlist_append(action, actionlist); 8569662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 8579662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 8589662Slinton cmdlist_append(action, actionlist); 8599662Slinton if (cond != nil) { 8609662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 8619662Slinton } 8629662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 8639662Slinton addevent(event, actionlist); 8649662Slinton } 8659662Slinton 8669662Slinton /* 8679662Slinton * Set up breakpoint for tracing data. 8689662Slinton */ 8699662Slinton 8709662Slinton private tracedata(op, exp, place, cond) 8719662Slinton Operator op; 8729662Slinton Node exp; 8739662Slinton Node place; 8749662Slinton Node cond; 8759662Slinton { 8769662Slinton Symbol p; 8779662Slinton Node event; 8789662Slinton Command action; 8799662Slinton 8809662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 8819662Slinton if (p == nil) { 8829662Slinton p = program; 8839662Slinton } 8849662Slinton action = build(O_PRINTIFCHANGED, exp); 8859662Slinton if (cond != nil) { 8869662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8879662Slinton } 8889662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 8899662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 8909662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 8919662Slinton } 8929662Slinton 8939662Slinton /* 8949662Slinton * Setting and unsetting of stops. 8959662Slinton */ 8969662Slinton 8979662Slinton public stop(p) 8989662Slinton Node p; 8999662Slinton { 9009662Slinton Node exp, place, cond; 9019662Slinton Symbol s; 9029662Slinton Command action; 9039662Slinton 9049662Slinton exp = p->value.arg[0]; 9059662Slinton place = p->value.arg[1]; 9069662Slinton cond = p->value.arg[2]; 9079662Slinton if (exp != nil) { 9089662Slinton stopvar(p->op, exp, place, cond); 9099662Slinton } else if (cond != nil) { 9109662Slinton s = (place == nil) ? program : place->value.sym; 9119662Slinton action = build(O_IF, cond, buildcmdlist(build(O_STOPX))); 9129662Slinton action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action)); 9139662Slinton cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 9149662Slinton action->value.trace.event = addevent(cond, buildcmdlist(action)); 9159662Slinton } else if (place->op == O_SYM) { 9169662Slinton s = place->value.sym; 9179662Slinton cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 9189662Slinton addevent(cond, buildcmdlist(build(O_STOPX))); 9199662Slinton } else { 9209662Slinton stopinst(p->op, place, cond); 9219662Slinton } 9229662Slinton } 9239662Slinton 9249662Slinton private stopinst(op, place, cond) 9259662Slinton Operator op; 9269662Slinton Node place; 9279662Slinton Node cond; 9289662Slinton { 9299662Slinton Node event; 9309662Slinton 9319662Slinton if (op == O_STOP) { 9329662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 9339662Slinton } else { 9349662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 9359662Slinton } 9369662Slinton addevent(event, buildcmdlist(build(O_STOPX))); 9379662Slinton } 9389662Slinton 9399662Slinton /* 9409662Slinton * Implement stopping on assignment to a variable by adding it to 9419662Slinton * the variable list. 9429662Slinton */ 9439662Slinton 9449662Slinton private stopvar(op, exp, place, cond) 9459662Slinton Operator op; 9469662Slinton Node exp; 9479662Slinton Node place; 9489662Slinton Node cond; 9499662Slinton { 9509662Slinton Symbol p; 9519662Slinton Node event; 9529662Slinton Command action; 9539662Slinton 9549662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 9559662Slinton if (p == nil) { 9569662Slinton p = program; 9579662Slinton } 9589662Slinton action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp))); 9599662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 9609662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 9619662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 9629662Slinton } 9639662Slinton 9649662Slinton /* 9659662Slinton * Assign the value of an expression to a variable (or term). 9669662Slinton */ 9679662Slinton 9689662Slinton public assign(var, exp) 9699662Slinton Node var; 9709662Slinton Node exp; 9719662Slinton { 9729662Slinton Address addr; 9739662Slinton int varsize; 9749662Slinton char cvalue; 9759662Slinton short svalue; 9769662Slinton long lvalue; 9779662Slinton 9789662Slinton if (not compatible(var->nodetype, exp->nodetype)) { 9799662Slinton error("incompatible types"); 9809662Slinton } 9819662Slinton addr = lval(var); 9829662Slinton eval(exp); 9839662Slinton varsize = size(var->nodetype); 9849662Slinton if (varsize < sizeof(long)) { 9859662Slinton lvalue = pop(long); 9869662Slinton switch (varsize) { 9879662Slinton case sizeof(char): 9889662Slinton cvalue = lvalue; 9899662Slinton dwrite(&cvalue, addr, varsize); 9909662Slinton break; 9919662Slinton 9929662Slinton case sizeof(short): 9939662Slinton svalue = lvalue; 9949662Slinton dwrite(&svalue, addr, varsize); 9959662Slinton break; 9969662Slinton 9979662Slinton default: 9989662Slinton panic("bad size %d", varsize); 9999662Slinton } 10009662Slinton } else { 10019662Slinton sp -= varsize; 10029662Slinton dwrite(sp, addr, varsize); 10039662Slinton } 10049662Slinton } 10059662Slinton 10069662Slinton #define DEF_EDITOR "vi" 10079662Slinton 10089662Slinton /* 10099662Slinton * Invoke an editor on the given file. Which editor to use might change 10109662Slinton * installation to installation. For now, we use "vi". In any event, 10119662Slinton * the environment variable "EDITOR" overrides any default. 10129662Slinton */ 10139662Slinton 10149662Slinton public edit(filename) 10159662Slinton String filename; 10169662Slinton { 10179662Slinton extern String getenv(); 10189662Slinton String ed, src; 10199662Slinton File f; 10209662Slinton Symbol s; 10219662Slinton Address addr; 10229662Slinton char buff[10]; 10239662Slinton 10249662Slinton ed = getenv("EDITOR"); 10259662Slinton if (ed == nil) { 10269662Slinton ed = DEF_EDITOR; 10279662Slinton } 10289662Slinton if (filename == nil) { 10299662Slinton call(ed, stdin, stdout, cursource, nil); 10309662Slinton } else { 10319662Slinton f = fopen(filename, "r"); 10329662Slinton if (f == nil) { 10339662Slinton s = which(identname(filename, true)); 10349662Slinton if (not isblock(s)) { 10359662Slinton error("can't read \"%s\"", filename); 10369662Slinton } 10379662Slinton addr = firstline(s); 10389662Slinton if (addr == NOADDR) { 10399662Slinton error("no source for \"%s\"", filename); 10409662Slinton } 10419662Slinton src = srcfilename(addr); 10429662Slinton sprintf(buff, "+%d", srcline(addr)); 10439662Slinton call(ed, stdin, stdout, buff, src, nil); 10449662Slinton } else { 10459662Slinton fclose(f); 10469662Slinton call(ed, stdin, stdout, filename, nil); 10479662Slinton } 10489662Slinton } 10499662Slinton } 10509662Slinton 10519662Slinton /* 10529662Slinton * Send some nasty mail to the current support person. 10539662Slinton */ 10549662Slinton 10559662Slinton public gripe() 10569662Slinton { 10579662Slinton typedef Operation(); 10589662Slinton Operation *old; 10599662Slinton 10609662Slinton char *maintainer = "linton@ucbarpa"; 10619662Slinton 10629662Slinton puts("Type control-D to end your message. Be sure to include"); 10639662Slinton puts("your name and the name of the file you are debugging."); 10649662Slinton putchar('\n'); 10659662Slinton old = signal(SIGINT, SIG_DFL); 10669662Slinton call("Mail", stdin, stdout, maintainer, nil); 10679662Slinton signal(SIGINT, old); 10689662Slinton puts("Thank you."); 10699662Slinton } 10709662Slinton 10719662Slinton /* 10729662Slinton * Give the user some help. 10739662Slinton */ 10749662Slinton 10759662Slinton public help() 10769662Slinton { 10779662Slinton puts("run - begin execution of the program"); 10789662Slinton puts("cont - continue execution"); 10799662Slinton puts("step - single step one line"); 10809662Slinton puts("next - step to next line (skip over calls)"); 10819662Slinton puts("trace <line#> - trace execution of the line"); 10829662Slinton puts("trace <proc> - trace calls to the procedure"); 10839662Slinton puts("trace <var> - trace changes to the variable"); 10849662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 10859662Slinton puts("stop at <line> - suspend execution at the line"); 10869662Slinton puts("stop in <proc> - suspend execution when <proc> is called"); 10879662Slinton puts("status - print trace/stop's in effect"); 10889662Slinton puts("delete <number> - remove trace or stop of given number"); 10899662Slinton puts("call <proc> - call the procedure"); 10909662Slinton puts("where - print currently active procedures"); 10919662Slinton puts("print <exp> - print the value of the expression"); 10929662Slinton puts("whatis <name> - print the declaration of the name"); 10939662Slinton puts("list <line>, <line> - list source lines"); 10949662Slinton puts("edit <proc> - edit file containing <proc>"); 10959662Slinton puts("gripe - send mail to the person in charge of dbx"); 10969662Slinton puts("quit - exit dbx"); 10979662Slinton } 10989662Slinton 10999662Slinton /* 11009662Slinton * Divert output to the given file name. 11019662Slinton * Cannot redirect to an existing file. 11029662Slinton */ 11039662Slinton 11049662Slinton private int so_fd; 11059662Slinton private Boolean notstdout; 11069662Slinton 11079662Slinton public setout(filename) 11089662Slinton String filename; 11099662Slinton { 11109662Slinton File f; 11119662Slinton 11129662Slinton f = fopen(filename, "r"); 11139662Slinton if (f != nil) { 11149662Slinton fclose(f); 11159662Slinton error("%s: file already exists", filename); 11169662Slinton } else { 11179662Slinton so_fd = dup(1); 11189662Slinton close(1); 11199662Slinton if (creat(filename, 0666) == nil) { 11209662Slinton unsetout(); 11219662Slinton error("can't create %s", filename); 11229662Slinton } 11239662Slinton notstdout = true; 11249662Slinton } 11259662Slinton } 11269662Slinton 11279662Slinton /* 11289662Slinton * Revert output to standard output. 11299662Slinton */ 11309662Slinton 11319662Slinton public unsetout() 11329662Slinton { 11339662Slinton fflush(stdout); 11349662Slinton close(1); 11359662Slinton if (dup(so_fd) != 1) { 11369662Slinton panic("standard out dup failed"); 11379662Slinton } 11389662Slinton close(so_fd); 11399662Slinton notstdout = false; 11409662Slinton } 11419662Slinton 11429662Slinton /* 11439662Slinton * Determine is standard output is currently being redirected 11449662Slinton * to a file (as far as we know). 11459662Slinton */ 11469662Slinton 11479662Slinton public Boolean isredirected() 11489662Slinton { 11499662Slinton return notstdout; 11509662Slinton } 1151