19662Slinton /* Copyright (c) 1982 Regents of the University of California */ 29662Slinton 3*12538Scsvaf static char sccsid[] = "@(#)eval.c 1.7 05/18/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 27*12538Scsvaf #define STACKSIZE 20000 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); 84*12538Scsvaf if(debug_flag[2]) { 85*12538Scsvaf fprintf(stderr," evaluating %s \n",showoperator(p->op)); 86*12538Scsvaf } 879662Slinton switch (degree(p->op)) { 889662Slinton case BINARY: 899662Slinton poparg(1, r1, fr1); 909662Slinton poparg(0, r0, fr0); 919662Slinton break; 929662Slinton 939662Slinton case UNARY: 949662Slinton poparg(0, r0, fr0); 959662Slinton break; 969662Slinton 979662Slinton default: 989662Slinton /* do nothing */; 999662Slinton } 1009662Slinton switch (p->op) { 1019662Slinton case O_SYM: 1029662Slinton s = p->value.sym; 1039662Slinton if (s == retaddrsym) { 1049662Slinton push(long, return_addr()); 1059662Slinton } else { 1069662Slinton if (isvariable(s)) { 1079662Slinton if (s != program and not isactive(container(s))) { 1089662Slinton error("\"%s\" is not active", symname(s)); 1099662Slinton } 1109662Slinton push(long, address(s, nil)); 1119662Slinton } else if (isblock(s)) { 1129662Slinton push(Symbol, s); 1139662Slinton } else { 1149662Slinton error("can't evaluate a %s", classname(s)); 1159662Slinton } 1169662Slinton } 1179662Slinton break; 1189662Slinton 1199662Slinton case O_LCON: 1209662Slinton r0 = p->value.lcon; 1219662Slinton pushsmall(p->nodetype, r0); 1229662Slinton break; 1239662Slinton 1249662Slinton case O_FCON: 1259662Slinton push(double, p->value.fcon); 1269662Slinton break; 1279662Slinton 1289662Slinton case O_SCON: 1299662Slinton len = size(p->nodetype); 1309662Slinton mov(p->value.scon, sp, len); 1319662Slinton sp += len; 1329662Slinton break; 1339662Slinton 1349662Slinton case O_INDEX: 1359662Slinton n = pop(long); 1369662Slinton i = evalindex(p->value.arg[0]->nodetype, 1379662Slinton popsmall(p->value.arg[1]->nodetype)); 1389662Slinton push(long, n + i*size(p->nodetype)); 1399662Slinton break; 1409662Slinton 1419662Slinton case O_DOT: 1429662Slinton s = p->value.arg[1]->value.sym; 1439662Slinton n = lval(p->value.arg[0]); 1449662Slinton push(long, n + (s->symvalue.field.offset div 8)); 1459662Slinton break; 1469662Slinton 1479662Slinton /* 1489662Slinton * Get the value of the expression addressed by the top of the stack. 1499662Slinton * Push the result back on the stack. 1509662Slinton */ 1519662Slinton 1529662Slinton case O_INDIR: 1539662Slinton case O_RVAL: 1549662Slinton addr = pop(long); 1559662Slinton if (addr == 0) { 1569662Slinton error("reference through nil pointer"); 1579662Slinton } 1589662Slinton if (p->op == O_INDIR) { 1599662Slinton len = sizeof(long); 1609662Slinton } else { 1619662Slinton len = size(p->nodetype); 1629662Slinton } 1639662Slinton rpush(addr, len); 164*12538Scsvaf addr = pop(long); 165*12538Scsvaf push(long, addr); 1669662Slinton break; 1679662Slinton 16811175Slinton /* 16911175Slinton * Effectively, we want to pop n bytes off for the evaluated subtree 17011175Slinton * and push len bytes on for the new type of the same tree. 17111175Slinton */ 17211175Slinton case O_TYPERENAME: 17311175Slinton n = size(p->value.arg[0]->nodetype); 17411175Slinton len = size(p->nodetype); 17511175Slinton sp = sp - n + len; 17611175Slinton break; 17711175Slinton 1789662Slinton case O_COMMA: 1799662Slinton break; 1809662Slinton 1819662Slinton case O_ITOF: 1829662Slinton push(double, (double) r0); 1839662Slinton break; 1849662Slinton 1859662Slinton case O_ADD: 1869662Slinton push(long, r0+r1); 1879662Slinton break; 1889662Slinton 1899662Slinton case O_ADDF: 1909662Slinton push(double, fr0+fr1); 1919662Slinton break; 1929662Slinton 1939662Slinton case O_SUB: 1949662Slinton push(long, r0-r1); 1959662Slinton break; 1969662Slinton 1979662Slinton case O_SUBF: 1989662Slinton push(double, fr0-fr1); 1999662Slinton break; 2009662Slinton 2019662Slinton case O_NEG: 2029662Slinton push(long, -r0); 2039662Slinton break; 2049662Slinton 2059662Slinton case O_NEGF: 2069662Slinton push(double, -fr0); 2079662Slinton break; 2089662Slinton 2099662Slinton case O_MUL: 2109662Slinton push(long, r0*r1); 2119662Slinton break; 2129662Slinton 2139662Slinton case O_MULF: 2149662Slinton push(double, fr0*fr1); 2159662Slinton break; 2169662Slinton 2179662Slinton case O_DIVF: 2189662Slinton if (fr1 == 0) { 2199662Slinton error("error: division by 0"); 2209662Slinton } 2219662Slinton push(double, fr0 / fr1); 2229662Slinton break; 2239662Slinton 2249662Slinton case O_DIV: 2259662Slinton if (r1 == 0) { 2269662Slinton error("error: div by 0"); 2279662Slinton } 2289662Slinton push(long, r0 div r1); 2299662Slinton break; 2309662Slinton 2319662Slinton case O_MOD: 2329662Slinton if (r1 == 0) { 2339662Slinton error("error: mod by 0"); 2349662Slinton } 2359662Slinton push(long, r0 mod r1); 2369662Slinton break; 2379662Slinton 2389662Slinton case O_LT: 2399662Slinton push(Boolrep, r0 < r1); 2409662Slinton break; 2419662Slinton 2429662Slinton case O_LTF: 2439662Slinton push(Boolrep, fr0 < fr1); 2449662Slinton break; 2459662Slinton 2469662Slinton case O_LE: 2479662Slinton push(Boolrep, r0 <= r1); 2489662Slinton break; 2499662Slinton 2509662Slinton case O_LEF: 2519662Slinton push(Boolrep, fr0 <= fr1); 2529662Slinton break; 2539662Slinton 2549662Slinton case O_GT: 2559662Slinton push(Boolrep, r0 > r1); 2569662Slinton break; 2579662Slinton 2589662Slinton case O_GTF: 2599662Slinton push(Boolrep, fr0 > fr1); 2609662Slinton break; 2619662Slinton 2629662Slinton case O_EQ: 2639662Slinton push(Boolrep, r0 == r1); 2649662Slinton break; 2659662Slinton 2669662Slinton case O_EQF: 2679662Slinton push(Boolrep, fr0 == fr1); 2689662Slinton break; 2699662Slinton 2709662Slinton case O_NE: 2719662Slinton push(Boolrep, r0 != r1); 2729662Slinton break; 2739662Slinton 2749662Slinton case O_NEF: 2759662Slinton push(Boolrep, fr0 != fr1); 2769662Slinton break; 2779662Slinton 2789662Slinton case O_AND: 2799662Slinton push(Boolrep, r0 and r1); 2809662Slinton break; 2819662Slinton 2829662Slinton case O_OR: 2839662Slinton push(Boolrep, r0 or r1); 2849662Slinton break; 2859662Slinton 2869662Slinton case O_ASSIGN: 2879662Slinton assign(p->value.arg[0], p->value.arg[1]); 2889662Slinton break; 2899662Slinton 2909662Slinton case O_CHFILE: 2919662Slinton if (p->value.scon == nil) { 2929662Slinton printf("%s\n", cursource); 2939662Slinton } else { 2949662Slinton file = opensource(p->value.scon); 2959662Slinton if (file == nil) { 2969662Slinton error("can't read \"%s\"", p->value.scon); 2979662Slinton } else { 2989662Slinton fclose(file); 2999662Slinton setsource(p->value.scon); 3009662Slinton } 3019662Slinton } 3029662Slinton break; 3039662Slinton 3049662Slinton case O_CONT: 30511871Slinton cont(p->value.lcon); 3069662Slinton printnews(); 3079662Slinton break; 3089662Slinton 3099662Slinton case O_LIST: 3109662Slinton if (p->value.arg[0]->op == O_SYM) { 3119662Slinton f = p->value.arg[0]->value.sym; 3129662Slinton addr = firstline(f); 3139662Slinton if (addr == NOADDR) { 3149662Slinton error("no source lines for \"%s\"", symname(f)); 3159662Slinton } 3169662Slinton setsource(srcfilename(addr)); 3179662Slinton r0 = srcline(addr) - 5; 3189662Slinton r1 = r0 + 10; 3199662Slinton if (r0 < 1) { 3209662Slinton r0 = 1; 3219662Slinton } 3229662Slinton } else { 3239662Slinton eval(p->value.arg[0]); 3249662Slinton r0 = pop(long); 3259662Slinton eval(p->value.arg[1]); 3269662Slinton r1 = pop(long); 3279662Slinton } 3289662Slinton printlines((Lineno) r0, (Lineno) r1); 3299662Slinton break; 3309662Slinton 3319662Slinton case O_FUNC: 3329662Slinton if (p->value.arg[0] == nil) { 3339662Slinton printname(stdout, curfunc); 3349662Slinton putchar('\n'); 3359662Slinton } else { 33611871Slinton s = p->value.arg[0]->value.sym; 33711871Slinton find(f, s->name) where 33811871Slinton f->class == FUNC or f->class == PROC 33911871Slinton endfind(f); 34011871Slinton if (f == nil) { 34111871Slinton error("%s is not a procedure or function", symname(s)); 34211771Slinton } 34311871Slinton curfunc = f; 3449662Slinton addr = codeloc(curfunc); 3459662Slinton if (addr != NOADDR) { 3469662Slinton setsource(srcfilename(addr)); 3479662Slinton cursrcline = srcline(addr) - 5; 3489662Slinton if (cursrcline < 1) { 3499662Slinton cursrcline = 1; 3509662Slinton } 3519662Slinton } 3529662Slinton } 3539662Slinton break; 3549662Slinton 3559662Slinton case O_EXAMINE: 3569662Slinton eval(p->value.examine.beginaddr); 3579662Slinton r0 = pop(long); 3589662Slinton if (p->value.examine.endaddr == nil) { 3599662Slinton n = p->value.examine.count; 36011175Slinton if (n == 0) { 36111175Slinton printvalue(r0, p->value.examine.mode); 36211175Slinton } else if (streq(p->value.examine.mode, "i")) { 3639662Slinton printninst(n, (Address) r0); 3649662Slinton } else { 3659662Slinton printndata(n, (Address) r0, p->value.examine.mode); 3669662Slinton } 3679662Slinton } else { 3689662Slinton eval(p->value.examine.endaddr); 3699662Slinton r1 = pop(long); 3709662Slinton if (streq(p->value.examine.mode, "i")) { 3719662Slinton printinst((Address)r0, (Address)r1); 3729662Slinton } else { 3739662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 3749662Slinton } 3759662Slinton } 3769662Slinton break; 3779662Slinton 3789662Slinton case O_PRINT: 3799662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 3809662Slinton eval(n1->value.arg[0]); 3819662Slinton printval(n1->value.arg[0]->nodetype); 3829662Slinton putchar(' '); 3839662Slinton } 3849662Slinton putchar('\n'); 3859662Slinton break; 3869662Slinton 3879662Slinton case O_PSYM: 3889662Slinton if (p->value.arg[0]->op == O_SYM) { 3899662Slinton psym(p->value.arg[0]->value.sym); 3909662Slinton } else { 3919662Slinton psym(p->value.arg[0]->nodetype); 3929662Slinton } 3939662Slinton break; 3949662Slinton 3959662Slinton case O_QLINE: 3969662Slinton eval(p->value.arg[1]); 3979662Slinton break; 3989662Slinton 3999662Slinton case O_STEP: 4009662Slinton b = inst_tracing; 4019662Slinton inst_tracing = (Boolean) (not p->value.step.source); 4029662Slinton if (p->value.step.skipcalls) { 4039662Slinton next(); 4049662Slinton } else { 4059662Slinton stepc(); 4069662Slinton } 4079662Slinton inst_tracing = b; 4089662Slinton printnews(); 4099662Slinton break; 4109662Slinton 4119662Slinton case O_WHATIS: 4129662Slinton if (p->value.arg[0]->op == O_SYM) { 4139662Slinton printdecl(p->value.arg[0]->value.sym); 4149662Slinton } else { 4159662Slinton printdecl(p->value.arg[0]->nodetype); 4169662Slinton } 4179662Slinton break; 4189662Slinton 4199662Slinton case O_WHERE: 4209662Slinton wherecmd(); 4219662Slinton break; 4229662Slinton 4239662Slinton case O_WHEREIS: 424*12538Scsvaf if (p->value.arg[0]->op == O_SYM) { 425*12538Scsvaf printwhereis(stdout,p->value.arg[0]->value.sym); 426*12538Scsvaf } else { 427*12538Scsvaf printwhereis(stdout,p->value.arg[0]->nodetype); 428*12538Scsvaf } 4299662Slinton break; 4309662Slinton 4319662Slinton case O_WHICH: 432*12538Scsvaf if (p->value.arg[0]->op == O_SYM) { 433*12538Scsvaf printwhich(stdout,p->value.arg[0]->value.sym); 434*12538Scsvaf } else { 435*12538Scsvaf printwhich(stdout,p->value.arg[0]->nodetype); 436*12538Scsvaf } 4379662Slinton putchar('\n'); 4389662Slinton break; 4399662Slinton 4409662Slinton case O_ALIAS: 4419662Slinton n1 = p->value.arg[0]; 4429662Slinton n2 = p->value.arg[1]; 4439662Slinton if (n1 == nil) { 4449662Slinton print_alias(nil); 4459662Slinton } else if (n2 == nil) { 4469662Slinton print_alias(n1->value.name); 4479662Slinton } else { 4489662Slinton enter_alias(n1->value.name, n2->value.name); 4499662Slinton } 4509662Slinton break; 4519662Slinton 4529662Slinton case O_CALL: 4539662Slinton callproc(p->value.arg[0], p->value.arg[1]); 4549662Slinton break; 4559662Slinton 4569662Slinton case O_CATCH: 4579662Slinton psigtrace(process, p->value.lcon, true); 4589662Slinton break; 4599662Slinton 4609662Slinton case O_EDIT: 4619662Slinton edit(p->value.scon); 4629662Slinton break; 4639662Slinton 464*12538Scsvaf case O_DEBUG: 465*12538Scsvaf debug(p); 466*12538Scsvaf break; 467*12538Scsvaf 4689662Slinton case O_DUMP: 4699662Slinton dump(); 4709662Slinton break; 4719662Slinton 4729662Slinton case O_GRIPE: 4739662Slinton gripe(); 4749662Slinton break; 4759662Slinton 4769662Slinton case O_HELP: 4779662Slinton help(); 4789662Slinton break; 4799662Slinton 4809662Slinton case O_IGNORE: 4819662Slinton psigtrace(process, p->value.lcon, false); 4829662Slinton break; 4839662Slinton 4849662Slinton case O_RUN: 4859662Slinton run(); 4869662Slinton break; 4879662Slinton 4889662Slinton case O_SOURCE: 4899662Slinton setinput(p->value.scon); 4909662Slinton break; 4919662Slinton 4929662Slinton case O_STATUS: 4939662Slinton status(); 4949662Slinton break; 4959662Slinton 4969662Slinton case O_TRACE: 4979662Slinton case O_TRACEI: 4989662Slinton trace(p); 4999662Slinton break; 5009662Slinton 5019662Slinton case O_STOP: 5029662Slinton case O_STOPI: 5039662Slinton stop(p); 5049662Slinton break; 5059662Slinton 5069662Slinton case O_ADDEVENT: 5079662Slinton addevent(p->value.event.cond, p->value.event.actions); 5089662Slinton break; 5099662Slinton 5109662Slinton case O_DELETE: 5119662Slinton delevent((unsigned int) p->value.lcon); 5129662Slinton break; 5139662Slinton 5149662Slinton case O_ENDX: 5159662Slinton endprogram(); 5169662Slinton break; 5179662Slinton 5189662Slinton case O_IF: 5199662Slinton if (cond(p->value.event.cond)) { 5209662Slinton evalcmdlist(p->value.event.actions); 5219662Slinton } 5229662Slinton break; 5239662Slinton 5249662Slinton case O_ONCE: 5259662Slinton event_once(p->value.event.cond, p->value.event.actions); 5269662Slinton break; 5279662Slinton 5289662Slinton case O_PRINTCALL: 5299662Slinton printcall(p->value.sym, whatblock(return_addr())); 5309662Slinton break; 5319662Slinton 5329662Slinton case O_PRINTIFCHANGED: 5339662Slinton printifchanged(p->value.arg[0]); 5349662Slinton break; 5359662Slinton 5369662Slinton case O_PRINTRTN: 5379662Slinton printrtn(p->value.sym); 5389662Slinton break; 5399662Slinton 5409662Slinton case O_PRINTSRCPOS: 5419662Slinton getsrcpos(); 5429662Slinton if (p->value.arg[0] == nil) { 5439662Slinton printsrcpos(); 5449662Slinton putchar('\n'); 5459662Slinton printlines(curline, curline); 5469662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 5479662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 5489662Slinton printf("tracei: "); 5499662Slinton printinst(pc, pc); 5509662Slinton } else { 5519662Slinton printf("trace: "); 5529662Slinton printlines(curline, curline); 5539662Slinton } 5549662Slinton } else { 5559662Slinton printsrcpos(); 5569662Slinton printf(": "); 5579662Slinton eval(p->value.arg[0]); 5589662Slinton prtree(stdout, p->value.arg[0]); 5599662Slinton printf(" = "); 5609662Slinton printval(p->value.arg[0]->nodetype); 5619662Slinton putchar('\n'); 5629662Slinton } 5639662Slinton break; 5649662Slinton 5659662Slinton case O_PROCRTN: 5669662Slinton procreturn(p->value.sym); 5679662Slinton break; 5689662Slinton 5699662Slinton case O_STOPIFCHANGED: 5709662Slinton stopifchanged(p->value.arg[0]); 5719662Slinton break; 5729662Slinton 5739662Slinton case O_STOPX: 5749662Slinton isstopped = true; 5759662Slinton break; 5769662Slinton 5779662Slinton case O_TRACEON: 5789662Slinton traceon(p->value.trace.inst, p->value.trace.event, 5799662Slinton p->value.trace.actions); 5809662Slinton break; 5819662Slinton 5829662Slinton case O_TRACEOFF: 5839662Slinton traceoff(p->value.lcon); 5849662Slinton break; 5859662Slinton 5869662Slinton default: 5879662Slinton panic("eval: bad op %d", p->op); 5889662Slinton } 589*12538Scsvaf if(debug_flag[2]) { 590*12538Scsvaf fprintf(stderr," evaluated %s \n",showoperator(p->op)); 591*12538Scsvaf } 592*12538Scsvaf 5939662Slinton } 5949662Slinton 5959662Slinton /* 5969662Slinton * Evaluate a list of commands. 5979662Slinton */ 5989662Slinton 5999662Slinton public evalcmdlist(cl) 6009662Slinton Cmdlist cl; 6019662Slinton { 6029662Slinton Command c; 6039662Slinton 6049662Slinton foreach (Command, c, cl) 6059662Slinton evalcmd(c); 6069662Slinton endfor 6079662Slinton } 6089662Slinton 6099662Slinton /* 6109662Slinton * Push "len" bytes onto the expression stack from address "addr" 6119662Slinton * in the process. If there isn't room on the stack, print an error message. 6129662Slinton */ 6139662Slinton 6149662Slinton public rpush(addr, len) 6159662Slinton Address addr; 6169662Slinton int len; 6179662Slinton { 6189662Slinton if (not canpush(len)) { 6199662Slinton error("expression too large to evaluate"); 6209662Slinton } else { 6219662Slinton chksp(); 6229662Slinton dread(sp, addr, len); 6239662Slinton sp += len; 6249662Slinton } 6259662Slinton } 6269662Slinton 6279662Slinton /* 6289662Slinton * Check if the stack has n bytes available. 6299662Slinton */ 6309662Slinton 6319662Slinton public Boolean canpush(n) 6329662Slinton Integer n; 6339662Slinton { 6349662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 6359662Slinton } 6369662Slinton 6379662Slinton /* 6389662Slinton * Push a small scalar of the given type onto the stack. 6399662Slinton */ 6409662Slinton 6419662Slinton public pushsmall(t, v) 6429662Slinton Symbol t; 6439662Slinton long v; 6449662Slinton { 6459662Slinton register Integer s; 6469662Slinton 6479662Slinton s = size(t); 6489662Slinton switch (s) { 6499662Slinton case sizeof(char): 6509662Slinton push(char, v); 6519662Slinton break; 6529662Slinton 6539662Slinton case sizeof(short): 6549662Slinton push(short, v); 6559662Slinton break; 6569662Slinton 6579662Slinton case sizeof(long): 6589662Slinton push(long, v); 6599662Slinton break; 6609662Slinton 6619662Slinton default: 6629662Slinton panic("bad size %d in popsmall", s); 6639662Slinton } 6649662Slinton } 6659662Slinton 6669662Slinton /* 6679662Slinton * Pop an item of the given type which is assumed to be no larger 6689662Slinton * than a long and return it expanded into a long. 6699662Slinton */ 6709662Slinton 6719662Slinton public long popsmall(t) 6729662Slinton Symbol t; 6739662Slinton { 6749662Slinton long r; 6759662Slinton 6769662Slinton switch (size(t)) { 6779662Slinton case sizeof(char): 6789662Slinton r = (long) pop(char); 6799662Slinton break; 6809662Slinton 6819662Slinton case sizeof(short): 6829662Slinton r = (long) pop(short); 6839662Slinton break; 6849662Slinton 6859662Slinton case sizeof(long): 6869662Slinton r = pop(long); 6879662Slinton break; 6889662Slinton 6899662Slinton default: 6909662Slinton panic("popsmall: size is %d", size(t)); 6919662Slinton } 6929662Slinton return r; 6939662Slinton } 6949662Slinton 6959662Slinton /* 6969662Slinton * Evaluate a conditional expression. 6979662Slinton */ 6989662Slinton 6999662Slinton public Boolean cond(p) 7009662Slinton Node p; 7019662Slinton { 7029662Slinton register Boolean b; 7039662Slinton 7049662Slinton if (p == nil) { 7059662Slinton b = true; 7069662Slinton } else { 7079662Slinton eval(p); 7089662Slinton b = pop(Boolean); 7099662Slinton } 7109662Slinton return b; 7119662Slinton } 7129662Slinton 7139662Slinton /* 7149662Slinton * Return the address corresponding to a given tree. 7159662Slinton */ 7169662Slinton 7179662Slinton public Address lval(p) 7189662Slinton Node p; 7199662Slinton { 7209662Slinton if (p->op == O_RVAL) { 7219662Slinton eval(p->value.arg[0]); 7229662Slinton } else { 7239662Slinton eval(p); 7249662Slinton } 7259662Slinton return (Address) (pop(long)); 7269662Slinton } 7279662Slinton 7289662Slinton /* 7299662Slinton * Process a trace command, translating into the appropriate events 7309662Slinton * and associated actions. 7319662Slinton */ 7329662Slinton 7339662Slinton public trace(p) 7349662Slinton Node p; 7359662Slinton { 7369662Slinton Node exp, place, cond; 7379662Slinton Node left; 7389662Slinton 7399662Slinton exp = p->value.arg[0]; 7409662Slinton place = p->value.arg[1]; 7419662Slinton cond = p->value.arg[2]; 7429662Slinton if (exp == nil) { 7439662Slinton traceall(p->op, place, cond); 74411771Slinton } else if (exp->op == O_QLINE or exp->op == O_LCON) { 7459662Slinton traceinst(p->op, exp, cond); 7469662Slinton } else if (place != nil and place->op == O_QLINE) { 7479662Slinton traceat(p->op, exp, place, cond); 7489662Slinton } else { 7499861Slinton left = exp; 7509861Slinton if (left->op == O_RVAL or left->op == O_CALL) { 7519861Slinton left = left->value.arg[0]; 7529861Slinton } 7539662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 7549662Slinton traceproc(p->op, left->value.sym, place, cond); 7559662Slinton } else { 7569662Slinton tracedata(p->op, exp, place, cond); 7579662Slinton } 7589662Slinton } 7599662Slinton } 7609662Slinton 7619662Slinton /* 7629662Slinton * Set a breakpoint that will turn on tracing. 7639662Slinton */ 7649662Slinton 7659662Slinton private traceall(op, place, cond) 7669662Slinton Operator op; 7679662Slinton Node place; 7689662Slinton Node cond; 7699662Slinton { 7709662Slinton Symbol s; 7719662Slinton Node event; 7729662Slinton Command action; 7739662Slinton 7749662Slinton if (place == nil) { 7759662Slinton s = program; 7769662Slinton } else { 7779662Slinton s = place->value.sym; 7789662Slinton } 7799662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 7809662Slinton action = build(O_PRINTSRCPOS, 7819662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 7829662Slinton if (cond != nil) { 7839662Slinton action = build(O_IF, cond, buildcmdlist(action)); 7849662Slinton } 7859662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 7869662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 78711871Slinton if (isstdin()) { 78811871Slinton printevent(action->value.trace.event); 78911871Slinton } 7909662Slinton } 7919662Slinton 7929662Slinton /* 7939662Slinton * Set up the appropriate breakpoint for tracing an instruction. 7949662Slinton */ 7959662Slinton 7969662Slinton private traceinst(op, exp, cond) 7979662Slinton Operator op; 7989662Slinton Node exp; 7999662Slinton Node cond; 8009662Slinton { 80111771Slinton Node event, wh; 8029662Slinton Command action; 80311871Slinton Event e; 8049662Slinton 80511771Slinton if (exp->op == O_LCON) { 80611771Slinton wh = build(O_QLINE, build(O_SCON, cursource), exp); 80711771Slinton } else { 80811771Slinton wh = exp; 80911771Slinton } 8109662Slinton if (op == O_TRACEI) { 81111771Slinton event = build(O_EQ, build(O_SYM, pcsym), wh); 8129662Slinton } else { 81311771Slinton event = build(O_EQ, build(O_SYM, linesym), wh); 8149662Slinton } 81511771Slinton action = build(O_PRINTSRCPOS, wh); 8169662Slinton if (cond) { 8179662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8189662Slinton } 81911871Slinton e = addevent(event, buildcmdlist(action)); 82011871Slinton if (isstdin()) { 82111871Slinton printevent(e); 82211871Slinton } 8239662Slinton } 8249662Slinton 8259662Slinton /* 8269662Slinton * Set a breakpoint to print an expression at a given line or address. 8279662Slinton */ 8289662Slinton 8299662Slinton private traceat(op, exp, place, cond) 8309662Slinton Operator op; 8319662Slinton Node exp; 8329662Slinton Node place; 8339662Slinton Node cond; 8349662Slinton { 8359662Slinton Node event; 8369662Slinton Command action; 83711871Slinton Event e; 8389662Slinton 8399662Slinton if (op == O_TRACEI) { 8409662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 8419662Slinton } else { 8429662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 8439662Slinton } 8449662Slinton action = build(O_PRINTSRCPOS, exp); 8459662Slinton if (cond != nil) { 8469662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8479662Slinton } 84811871Slinton e = addevent(event, buildcmdlist(action)); 84911871Slinton if (isstdin()) { 85011871Slinton printevent(e); 85111871Slinton } 8529662Slinton } 8539662Slinton 8549662Slinton /* 8559662Slinton * Construct event for tracing a procedure. 8569662Slinton * 8579662Slinton * What we want here is 8589662Slinton * 8599662Slinton * when $proc = p do 8609662Slinton * if <condition> then 8619662Slinton * printcall; 8629662Slinton * once $pc = $retaddr do 8639662Slinton * printrtn; 8649662Slinton * end; 8659662Slinton * end if; 8669662Slinton * end; 8679662Slinton * 8689662Slinton * Note that "once" is like "when" except that the event 8699662Slinton * deletes itself as part of its associated action. 8709662Slinton */ 8719662Slinton 8729662Slinton private traceproc(op, p, place, cond) 8739662Slinton Operator op; 8749662Slinton Symbol p; 8759662Slinton Node place; 8769662Slinton Node cond; 8779662Slinton { 8789662Slinton Node event; 8799662Slinton Command action; 8809662Slinton Cmdlist actionlist; 88111871Slinton Event e; 8829662Slinton 8839662Slinton action = build(O_PRINTCALL, p); 8849662Slinton actionlist = list_alloc(); 8859662Slinton cmdlist_append(action, actionlist); 8869662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 8879662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 8889662Slinton cmdlist_append(action, actionlist); 8899662Slinton if (cond != nil) { 8909662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 8919662Slinton } 8929662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 89311871Slinton e = addevent(event, actionlist); 89411871Slinton if (isstdin()) { 89511871Slinton printevent(e); 89611871Slinton } 8979662Slinton } 8989662Slinton 8999662Slinton /* 9009662Slinton * Set up breakpoint for tracing data. 9019662Slinton */ 9029662Slinton 9039662Slinton private tracedata(op, exp, place, cond) 9049662Slinton Operator op; 9059662Slinton Node exp; 9069662Slinton Node place; 9079662Slinton Node cond; 9089662Slinton { 9099662Slinton Symbol p; 9109662Slinton Node event; 9119662Slinton Command action; 9129662Slinton 9139662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 9149662Slinton if (p == nil) { 9159662Slinton p = program; 9169662Slinton } 9179662Slinton action = build(O_PRINTIFCHANGED, exp); 9189662Slinton if (cond != nil) { 9199662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9209662Slinton } 9219662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 9229662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 9239662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 92411871Slinton if (isstdin()) { 92511871Slinton printevent(action->value.trace.event); 92611871Slinton } 9279662Slinton } 9289662Slinton 9299662Slinton /* 9309662Slinton * Setting and unsetting of stops. 9319662Slinton */ 9329662Slinton 9339662Slinton public stop(p) 9349662Slinton Node p; 9359662Slinton { 9369662Slinton Node exp, place, cond; 9379662Slinton Symbol s; 9389662Slinton Command action; 93911871Slinton Event e; 9409662Slinton 9419662Slinton exp = p->value.arg[0]; 9429662Slinton place = p->value.arg[1]; 9439662Slinton cond = p->value.arg[2]; 9449662Slinton if (exp != nil) { 9459662Slinton stopvar(p->op, exp, place, cond); 9469662Slinton } else if (cond != nil) { 9479662Slinton s = (place == nil) ? program : place->value.sym; 9489662Slinton action = build(O_IF, cond, buildcmdlist(build(O_STOPX))); 9499662Slinton action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action)); 9509662Slinton cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 9519662Slinton action->value.trace.event = addevent(cond, buildcmdlist(action)); 9529662Slinton } else if (place->op == O_SYM) { 9539662Slinton s = place->value.sym; 9549662Slinton cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 95511871Slinton e = addevent(cond, buildcmdlist(build(O_STOPX))); 95611871Slinton if (isstdin()) { 95711871Slinton printevent(e); 95811871Slinton } 9599662Slinton } else { 9609662Slinton stopinst(p->op, place, cond); 9619662Slinton } 9629662Slinton } 9639662Slinton 9649662Slinton private stopinst(op, place, cond) 9659662Slinton Operator op; 9669662Slinton Node place; 9679662Slinton Node cond; 9689662Slinton { 9699662Slinton Node event; 97011871Slinton Event e; 9719662Slinton 9729662Slinton if (op == O_STOP) { 9739662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 9749662Slinton } else { 9759662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 9769662Slinton } 97711871Slinton e = addevent(event, buildcmdlist(build(O_STOPX))); 97811871Slinton if (isstdin()) { 97911871Slinton printevent(e); 98011871Slinton } 9819662Slinton } 9829662Slinton 9839662Slinton /* 9849662Slinton * Implement stopping on assignment to a variable by adding it to 9859662Slinton * the variable list. 9869662Slinton */ 9879662Slinton 9889662Slinton private stopvar(op, exp, place, cond) 9899662Slinton Operator op; 9909662Slinton Node exp; 9919662Slinton Node place; 9929662Slinton Node cond; 9939662Slinton { 9949662Slinton Symbol p; 9959662Slinton Node event; 9969662Slinton Command action; 9979662Slinton 9989662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 9999662Slinton if (p == nil) { 10009662Slinton p = program; 10019662Slinton } 10029662Slinton action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp))); 10039662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 10049662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 10059662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 100611871Slinton if (isstdin()) { 100711871Slinton printevent(action->value.trace.event); 100811871Slinton } 10099662Slinton } 10109662Slinton 10119662Slinton /* 10129662Slinton * Assign the value of an expression to a variable (or term). 10139662Slinton */ 10149662Slinton 10159662Slinton public assign(var, exp) 10169662Slinton Node var; 10179662Slinton Node exp; 10189662Slinton { 10199662Slinton Address addr; 10209662Slinton int varsize; 10219662Slinton char cvalue; 10229662Slinton short svalue; 10239662Slinton long lvalue; 10249662Slinton 10259662Slinton if (not compatible(var->nodetype, exp->nodetype)) { 10269662Slinton error("incompatible types"); 10279662Slinton } 10289662Slinton addr = lval(var); 10299662Slinton eval(exp); 10309662Slinton varsize = size(var->nodetype); 10319662Slinton if (varsize < sizeof(long)) { 10329662Slinton lvalue = pop(long); 10339662Slinton switch (varsize) { 10349662Slinton case sizeof(char): 10359662Slinton cvalue = lvalue; 10369662Slinton dwrite(&cvalue, addr, varsize); 10379662Slinton break; 10389662Slinton 10399662Slinton case sizeof(short): 10409662Slinton svalue = lvalue; 10419662Slinton dwrite(&svalue, addr, varsize); 10429662Slinton break; 10439662Slinton 10449662Slinton default: 10459662Slinton panic("bad size %d", varsize); 10469662Slinton } 10479662Slinton } else { 10489662Slinton sp -= varsize; 10499662Slinton dwrite(sp, addr, varsize); 10509662Slinton } 10519662Slinton } 10529662Slinton 10539662Slinton #define DEF_EDITOR "vi" 10549662Slinton 10559662Slinton /* 10569662Slinton * Invoke an editor on the given file. Which editor to use might change 10579662Slinton * installation to installation. For now, we use "vi". In any event, 10589662Slinton * the environment variable "EDITOR" overrides any default. 10599662Slinton */ 10609662Slinton 10619662Slinton public edit(filename) 10629662Slinton String filename; 10639662Slinton { 10649662Slinton extern String getenv(); 10659662Slinton String ed, src; 10669662Slinton File f; 10679662Slinton Symbol s; 10689662Slinton Address addr; 10699662Slinton char buff[10]; 10709662Slinton 10719662Slinton ed = getenv("EDITOR"); 10729662Slinton if (ed == nil) { 10739662Slinton ed = DEF_EDITOR; 10749662Slinton } 10759662Slinton if (filename == nil) { 10769662Slinton call(ed, stdin, stdout, cursource, nil); 10779662Slinton } else { 10789662Slinton f = fopen(filename, "r"); 10799662Slinton if (f == nil) { 10809662Slinton s = which(identname(filename, true)); 10819662Slinton if (not isblock(s)) { 10829662Slinton error("can't read \"%s\"", filename); 10839662Slinton } 10849662Slinton addr = firstline(s); 10859662Slinton if (addr == NOADDR) { 10869662Slinton error("no source for \"%s\"", filename); 10879662Slinton } 10889662Slinton src = srcfilename(addr); 10899662Slinton sprintf(buff, "+%d", srcline(addr)); 10909662Slinton call(ed, stdin, stdout, buff, src, nil); 10919662Slinton } else { 10929662Slinton fclose(f); 10939662Slinton call(ed, stdin, stdout, filename, nil); 10949662Slinton } 10959662Slinton } 10969662Slinton } 10979662Slinton 10989662Slinton /* 10999662Slinton * Send some nasty mail to the current support person. 11009662Slinton */ 11019662Slinton 11029662Slinton public gripe() 11039662Slinton { 11049662Slinton typedef Operation(); 11059662Slinton Operation *old; 11069662Slinton 11079662Slinton char *maintainer = "linton@ucbarpa"; 11089662Slinton 11099662Slinton puts("Type control-D to end your message. Be sure to include"); 11109662Slinton puts("your name and the name of the file you are debugging."); 11119662Slinton putchar('\n'); 11129662Slinton old = signal(SIGINT, SIG_DFL); 11139662Slinton call("Mail", stdin, stdout, maintainer, nil); 11149662Slinton signal(SIGINT, old); 11159662Slinton puts("Thank you."); 11169662Slinton } 11179662Slinton 11189662Slinton /* 11199662Slinton * Give the user some help. 11209662Slinton */ 11219662Slinton 11229662Slinton public help() 11239662Slinton { 11249662Slinton puts("run - begin execution of the program"); 11259662Slinton puts("cont - continue execution"); 11269662Slinton puts("step - single step one line"); 11279662Slinton puts("next - step to next line (skip over calls)"); 11289662Slinton puts("trace <line#> - trace execution of the line"); 11299662Slinton puts("trace <proc> - trace calls to the procedure"); 11309662Slinton puts("trace <var> - trace changes to the variable"); 11319662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 11329662Slinton puts("stop at <line> - suspend execution at the line"); 11339662Slinton puts("stop in <proc> - suspend execution when <proc> is called"); 11349662Slinton puts("status - print trace/stop's in effect"); 11359662Slinton puts("delete <number> - remove trace or stop of given number"); 11369662Slinton puts("call <proc> - call the procedure"); 11379662Slinton puts("where - print currently active procedures"); 11389662Slinton puts("print <exp> - print the value of the expression"); 11399662Slinton puts("whatis <name> - print the declaration of the name"); 11409662Slinton puts("list <line>, <line> - list source lines"); 11419662Slinton puts("edit <proc> - edit file containing <proc>"); 11429662Slinton puts("gripe - send mail to the person in charge of dbx"); 11439662Slinton puts("quit - exit dbx"); 11449662Slinton } 11459662Slinton 11469662Slinton /* 11479662Slinton * Divert output to the given file name. 11489662Slinton * Cannot redirect to an existing file. 11499662Slinton */ 11509662Slinton 11519662Slinton private int so_fd; 11529662Slinton private Boolean notstdout; 11539662Slinton 11549662Slinton public setout(filename) 11559662Slinton String filename; 11569662Slinton { 11579662Slinton File f; 11589662Slinton 11599662Slinton f = fopen(filename, "r"); 11609662Slinton if (f != nil) { 11619662Slinton fclose(f); 11629662Slinton error("%s: file already exists", filename); 11639662Slinton } else { 11649662Slinton so_fd = dup(1); 11659662Slinton close(1); 11669662Slinton if (creat(filename, 0666) == nil) { 11679662Slinton unsetout(); 11689662Slinton error("can't create %s", filename); 11699662Slinton } 11709662Slinton notstdout = true; 11719662Slinton } 11729662Slinton } 11739662Slinton 11749662Slinton /* 11759662Slinton * Revert output to standard output. 11769662Slinton */ 11779662Slinton 11789662Slinton public unsetout() 11799662Slinton { 11809662Slinton fflush(stdout); 11819662Slinton close(1); 11829662Slinton if (dup(so_fd) != 1) { 11839662Slinton panic("standard out dup failed"); 11849662Slinton } 11859662Slinton close(so_fd); 11869662Slinton notstdout = false; 11879662Slinton } 11889662Slinton 11899662Slinton /* 11909662Slinton * Determine is standard output is currently being redirected 11919662Slinton * to a file (as far as we know). 11929662Slinton */ 11939662Slinton 11949662Slinton public Boolean isredirected() 11959662Slinton { 11969662Slinton return notstdout; 11979662Slinton } 1198