19662Slinton /* Copyright (c) 1982 Regents of the University of California */ 29662Slinton 3*14674Slinton static char sccsid[] = "@(#)eval.c 1.10 08/17/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 2712538Scsvaf #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]; 47*14674Slinton public Boolean useInstLoc = false; 489662Slinton 499662Slinton #define chksp() \ 509662Slinton { \ 519662Slinton if (sp < &stack[0]) { \ 529662Slinton panic("stack underflow"); \ 539662Slinton } \ 549662Slinton } 559662Slinton 569662Slinton #define poparg(n, r, fr) { \ 579662Slinton eval(p->value.arg[n]); \ 589662Slinton if (isreal(p->op)) { \ 599662Slinton fr = pop(double); \ 609662Slinton } else if (isint(p->op)) { \ 619662Slinton r = popsmall(p->value.arg[n]->nodetype); \ 629662Slinton } \ 639662Slinton } 649662Slinton 659662Slinton #define Boolrep char /* underlying representation type for booleans */ 669662Slinton 679662Slinton /* 689662Slinton * Evaluate a parse tree leaving the value on the top of the stack. 699662Slinton */ 709662Slinton 719662Slinton public eval(p) 729662Slinton register Node p; 739662Slinton { 749662Slinton long r0, r1; 759662Slinton double fr0, fr1; 769662Slinton Address addr; 779662Slinton long i, n; 789662Slinton int len; 799662Slinton Symbol s, f; 809662Slinton Node n1, n2; 819662Slinton Boolean b; 829662Slinton File file; 839662Slinton 849662Slinton checkref(p); 8513846Slinton if (debug_flag[2]) { 8613846Slinton fprintf(stderr," evaluating %s \n",showoperator(p->op)); 8712538Scsvaf } 889662Slinton switch (degree(p->op)) { 899662Slinton case BINARY: 909662Slinton poparg(1, r1, fr1); 919662Slinton poparg(0, r0, fr0); 929662Slinton break; 939662Slinton 949662Slinton case UNARY: 959662Slinton poparg(0, r0, fr0); 969662Slinton break; 979662Slinton 989662Slinton default: 999662Slinton /* do nothing */; 1009662Slinton } 1019662Slinton switch (p->op) { 1029662Slinton case O_SYM: 1039662Slinton s = p->value.sym; 1049662Slinton if (s == retaddrsym) { 1059662Slinton push(long, return_addr()); 1069662Slinton } else { 1079662Slinton if (isvariable(s)) { 1089662Slinton if (s != program and not isactive(container(s))) { 1099662Slinton error("\"%s\" is not active", symname(s)); 1109662Slinton } 1119662Slinton push(long, address(s, nil)); 1129662Slinton } else if (isblock(s)) { 1139662Slinton push(Symbol, s); 1149662Slinton } else { 1159662Slinton error("can't evaluate a %s", classname(s)); 1169662Slinton } 1179662Slinton } 1189662Slinton break; 1199662Slinton 1209662Slinton case O_LCON: 1219662Slinton r0 = p->value.lcon; 1229662Slinton pushsmall(p->nodetype, r0); 1239662Slinton break; 1249662Slinton 1259662Slinton case O_FCON: 1269662Slinton push(double, p->value.fcon); 1279662Slinton break; 1289662Slinton 1299662Slinton case O_SCON: 1309662Slinton len = size(p->nodetype); 1319662Slinton mov(p->value.scon, sp, len); 1329662Slinton sp += len; 1339662Slinton break; 1349662Slinton 1359662Slinton case O_INDEX: 1369662Slinton n = pop(long); 1379662Slinton i = evalindex(p->value.arg[0]->nodetype, 1389662Slinton popsmall(p->value.arg[1]->nodetype)); 1399662Slinton push(long, n + i*size(p->nodetype)); 1409662Slinton break; 1419662Slinton 1429662Slinton case O_DOT: 1439662Slinton s = p->value.arg[1]->value.sym; 1449662Slinton n = lval(p->value.arg[0]); 1459662Slinton push(long, n + (s->symvalue.field.offset div 8)); 1469662Slinton break; 1479662Slinton 1489662Slinton /* 1499662Slinton * Get the value of the expression addressed by the top of the stack. 1509662Slinton * Push the result back on the stack. 1519662Slinton */ 1529662Slinton 1539662Slinton case O_INDIR: 1549662Slinton case O_RVAL: 1559662Slinton addr = pop(long); 1569662Slinton if (addr == 0) { 1579662Slinton error("reference through nil pointer"); 1589662Slinton } 1599662Slinton if (p->op == O_INDIR) { 1609662Slinton len = sizeof(long); 1619662Slinton } else { 1629662Slinton len = size(p->nodetype); 1639662Slinton } 1649662Slinton rpush(addr, len); 16512538Scsvaf addr = pop(long); 16612538Scsvaf push(long, addr); 1679662Slinton break; 1689662Slinton 16911175Slinton /* 17011175Slinton * Effectively, we want to pop n bytes off for the evaluated subtree 17111175Slinton * and push len bytes on for the new type of the same tree. 17211175Slinton */ 17311175Slinton case O_TYPERENAME: 17411175Slinton n = size(p->value.arg[0]->nodetype); 17511175Slinton len = size(p->nodetype); 17611175Slinton sp = sp - n + len; 17711175Slinton break; 17811175Slinton 1799662Slinton case O_COMMA: 1809662Slinton break; 1819662Slinton 1829662Slinton case O_ITOF: 1839662Slinton push(double, (double) r0); 1849662Slinton break; 1859662Slinton 1869662Slinton case O_ADD: 1879662Slinton push(long, r0+r1); 1889662Slinton break; 1899662Slinton 1909662Slinton case O_ADDF: 1919662Slinton push(double, fr0+fr1); 1929662Slinton break; 1939662Slinton 1949662Slinton case O_SUB: 1959662Slinton push(long, r0-r1); 1969662Slinton break; 1979662Slinton 1989662Slinton case O_SUBF: 1999662Slinton push(double, fr0-fr1); 2009662Slinton break; 2019662Slinton 2029662Slinton case O_NEG: 2039662Slinton push(long, -r0); 2049662Slinton break; 2059662Slinton 2069662Slinton case O_NEGF: 2079662Slinton push(double, -fr0); 2089662Slinton break; 2099662Slinton 2109662Slinton case O_MUL: 2119662Slinton push(long, r0*r1); 2129662Slinton break; 2139662Slinton 2149662Slinton case O_MULF: 2159662Slinton push(double, fr0*fr1); 2169662Slinton break; 2179662Slinton 2189662Slinton case O_DIVF: 2199662Slinton if (fr1 == 0) { 2209662Slinton error("error: division by 0"); 2219662Slinton } 2229662Slinton push(double, fr0 / fr1); 2239662Slinton break; 2249662Slinton 2259662Slinton case O_DIV: 2269662Slinton if (r1 == 0) { 2279662Slinton error("error: div by 0"); 2289662Slinton } 2299662Slinton push(long, r0 div r1); 2309662Slinton break; 2319662Slinton 2329662Slinton case O_MOD: 2339662Slinton if (r1 == 0) { 2349662Slinton error("error: mod by 0"); 2359662Slinton } 2369662Slinton push(long, r0 mod r1); 2379662Slinton break; 2389662Slinton 2399662Slinton case O_LT: 2409662Slinton push(Boolrep, r0 < r1); 2419662Slinton break; 2429662Slinton 2439662Slinton case O_LTF: 2449662Slinton push(Boolrep, fr0 < fr1); 2459662Slinton break; 2469662Slinton 2479662Slinton case O_LE: 2489662Slinton push(Boolrep, r0 <= r1); 2499662Slinton break; 2509662Slinton 2519662Slinton case O_LEF: 2529662Slinton push(Boolrep, fr0 <= fr1); 2539662Slinton break; 2549662Slinton 2559662Slinton case O_GT: 2569662Slinton push(Boolrep, r0 > r1); 2579662Slinton break; 2589662Slinton 2599662Slinton case O_GTF: 2609662Slinton push(Boolrep, fr0 > fr1); 2619662Slinton break; 2629662Slinton 2639662Slinton case O_EQ: 2649662Slinton push(Boolrep, r0 == r1); 2659662Slinton break; 2669662Slinton 2679662Slinton case O_EQF: 2689662Slinton push(Boolrep, fr0 == fr1); 2699662Slinton break; 2709662Slinton 2719662Slinton case O_NE: 2729662Slinton push(Boolrep, r0 != r1); 2739662Slinton break; 2749662Slinton 2759662Slinton case O_NEF: 2769662Slinton push(Boolrep, fr0 != fr1); 2779662Slinton break; 2789662Slinton 2799662Slinton case O_AND: 2809662Slinton push(Boolrep, r0 and r1); 2819662Slinton break; 2829662Slinton 2839662Slinton case O_OR: 2849662Slinton push(Boolrep, r0 or r1); 2859662Slinton break; 2869662Slinton 2879662Slinton case O_ASSIGN: 2889662Slinton assign(p->value.arg[0], p->value.arg[1]); 2899662Slinton break; 2909662Slinton 2919662Slinton case O_CHFILE: 2929662Slinton if (p->value.scon == nil) { 2939662Slinton printf("%s\n", cursource); 2949662Slinton } else { 2959662Slinton file = opensource(p->value.scon); 2969662Slinton if (file == nil) { 2979662Slinton error("can't read \"%s\"", p->value.scon); 2989662Slinton } else { 2999662Slinton fclose(file); 3009662Slinton setsource(p->value.scon); 3019662Slinton } 3029662Slinton } 3039662Slinton break; 3049662Slinton 3059662Slinton case O_CONT: 30611871Slinton cont(p->value.lcon); 3079662Slinton printnews(); 3089662Slinton break; 3099662Slinton 3109662Slinton case O_LIST: 3119662Slinton if (p->value.arg[0]->op == O_SYM) { 3129662Slinton f = p->value.arg[0]->value.sym; 3139662Slinton addr = firstline(f); 3149662Slinton if (addr == NOADDR) { 3159662Slinton error("no source lines for \"%s\"", symname(f)); 3169662Slinton } 3179662Slinton setsource(srcfilename(addr)); 3189662Slinton r0 = srcline(addr) - 5; 3199662Slinton r1 = r0 + 10; 3209662Slinton if (r0 < 1) { 3219662Slinton r0 = 1; 3229662Slinton } 3239662Slinton } else { 3249662Slinton eval(p->value.arg[0]); 3259662Slinton r0 = pop(long); 3269662Slinton eval(p->value.arg[1]); 3279662Slinton r1 = pop(long); 3289662Slinton } 3299662Slinton printlines((Lineno) r0, (Lineno) r1); 3309662Slinton break; 3319662Slinton 3329662Slinton case O_FUNC: 3339662Slinton if (p->value.arg[0] == nil) { 3349662Slinton printname(stdout, curfunc); 3359662Slinton putchar('\n'); 3369662Slinton } else { 33711871Slinton s = p->value.arg[0]->value.sym; 33811871Slinton find(f, s->name) where 33911871Slinton f->class == FUNC or f->class == PROC 34011871Slinton endfind(f); 34111871Slinton if (f == nil) { 34211871Slinton error("%s is not a procedure or function", symname(s)); 34311771Slinton } 34411871Slinton curfunc = f; 3459662Slinton addr = codeloc(curfunc); 3469662Slinton if (addr != NOADDR) { 3479662Slinton setsource(srcfilename(addr)); 3489662Slinton cursrcline = srcline(addr) - 5; 3499662Slinton if (cursrcline < 1) { 3509662Slinton cursrcline = 1; 3519662Slinton } 3529662Slinton } 3539662Slinton } 3549662Slinton break; 3559662Slinton 3569662Slinton case O_EXAMINE: 3579662Slinton eval(p->value.examine.beginaddr); 3589662Slinton r0 = pop(long); 3599662Slinton if (p->value.examine.endaddr == nil) { 3609662Slinton n = p->value.examine.count; 36111175Slinton if (n == 0) { 36211175Slinton printvalue(r0, p->value.examine.mode); 36311175Slinton } else if (streq(p->value.examine.mode, "i")) { 3649662Slinton printninst(n, (Address) r0); 3659662Slinton } else { 3669662Slinton printndata(n, (Address) r0, p->value.examine.mode); 3679662Slinton } 3689662Slinton } else { 3699662Slinton eval(p->value.examine.endaddr); 3709662Slinton r1 = pop(long); 3719662Slinton if (streq(p->value.examine.mode, "i")) { 3729662Slinton printinst((Address)r0, (Address)r1); 3739662Slinton } else { 3749662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 3759662Slinton } 3769662Slinton } 3779662Slinton break; 3789662Slinton 3799662Slinton case O_PRINT: 3809662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 3819662Slinton eval(n1->value.arg[0]); 3829662Slinton printval(n1->value.arg[0]->nodetype); 3839662Slinton putchar(' '); 3849662Slinton } 3859662Slinton putchar('\n'); 3869662Slinton break; 3879662Slinton 3889662Slinton case O_PSYM: 3899662Slinton if (p->value.arg[0]->op == O_SYM) { 3909662Slinton psym(p->value.arg[0]->value.sym); 3919662Slinton } else { 3929662Slinton psym(p->value.arg[0]->nodetype); 3939662Slinton } 3949662Slinton break; 3959662Slinton 3969662Slinton case O_QLINE: 3979662Slinton eval(p->value.arg[1]); 3989662Slinton break; 3999662Slinton 4009662Slinton case O_STEP: 4019662Slinton b = inst_tracing; 4029662Slinton inst_tracing = (Boolean) (not p->value.step.source); 4039662Slinton if (p->value.step.skipcalls) { 4049662Slinton next(); 4059662Slinton } else { 4069662Slinton stepc(); 4079662Slinton } 4089662Slinton inst_tracing = b; 409*14674Slinton useInstLoc = (Boolean) (not p->value.step.source); 4109662Slinton printnews(); 4119662Slinton break; 4129662Slinton 4139662Slinton case O_WHATIS: 4149662Slinton if (p->value.arg[0]->op == O_SYM) { 4159662Slinton printdecl(p->value.arg[0]->value.sym); 4169662Slinton } else { 4179662Slinton printdecl(p->value.arg[0]->nodetype); 4189662Slinton } 4199662Slinton break; 4209662Slinton 4219662Slinton case O_WHERE: 4229662Slinton wherecmd(); 4239662Slinton break; 4249662Slinton 4259662Slinton case O_WHEREIS: 42612538Scsvaf if (p->value.arg[0]->op == O_SYM) { 42712538Scsvaf printwhereis(stdout,p->value.arg[0]->value.sym); 42812538Scsvaf } else { 42912538Scsvaf printwhereis(stdout,p->value.arg[0]->nodetype); 43012538Scsvaf } 4319662Slinton break; 4329662Slinton 4339662Slinton case O_WHICH: 43412538Scsvaf if (p->value.arg[0]->op == O_SYM) { 43512538Scsvaf printwhich(stdout,p->value.arg[0]->value.sym); 43612538Scsvaf } else { 43712538Scsvaf printwhich(stdout,p->value.arg[0]->nodetype); 43812538Scsvaf } 4399662Slinton putchar('\n'); 4409662Slinton break; 4419662Slinton 4429662Slinton case O_ALIAS: 4439662Slinton n1 = p->value.arg[0]; 4449662Slinton n2 = p->value.arg[1]; 4459662Slinton if (n1 == nil) { 4469662Slinton print_alias(nil); 4479662Slinton } else if (n2 == nil) { 4489662Slinton print_alias(n1->value.name); 4499662Slinton } else { 4509662Slinton enter_alias(n1->value.name, n2->value.name); 4519662Slinton } 4529662Slinton break; 4539662Slinton 4549662Slinton case O_CALL: 4559662Slinton callproc(p->value.arg[0], p->value.arg[1]); 4569662Slinton break; 4579662Slinton 4589662Slinton case O_CATCH: 4599662Slinton psigtrace(process, p->value.lcon, true); 4609662Slinton break; 4619662Slinton 4629662Slinton case O_EDIT: 4639662Slinton edit(p->value.scon); 4649662Slinton break; 4659662Slinton 46612538Scsvaf case O_DEBUG: 46712538Scsvaf debug(p); 46812538Scsvaf break; 46912538Scsvaf 4709662Slinton case O_DUMP: 4719662Slinton dump(); 4729662Slinton break; 4739662Slinton 4749662Slinton case O_GRIPE: 4759662Slinton gripe(); 4769662Slinton break; 4779662Slinton 4789662Slinton case O_HELP: 4799662Slinton help(); 4809662Slinton break; 4819662Slinton 4829662Slinton case O_IGNORE: 4839662Slinton psigtrace(process, p->value.lcon, false); 4849662Slinton break; 4859662Slinton 4869662Slinton case O_RUN: 4879662Slinton run(); 4889662Slinton break; 4899662Slinton 4909662Slinton case O_SOURCE: 4919662Slinton setinput(p->value.scon); 4929662Slinton break; 4939662Slinton 4949662Slinton case O_STATUS: 4959662Slinton status(); 4969662Slinton break; 4979662Slinton 4989662Slinton case O_TRACE: 4999662Slinton case O_TRACEI: 5009662Slinton trace(p); 5019662Slinton break; 5029662Slinton 5039662Slinton case O_STOP: 5049662Slinton case O_STOPI: 5059662Slinton stop(p); 5069662Slinton break; 5079662Slinton 5089662Slinton case O_ADDEVENT: 5099662Slinton addevent(p->value.event.cond, p->value.event.actions); 5109662Slinton break; 5119662Slinton 5129662Slinton case O_DELETE: 5139662Slinton delevent((unsigned int) p->value.lcon); 5149662Slinton break; 5159662Slinton 5169662Slinton case O_ENDX: 5179662Slinton endprogram(); 5189662Slinton break; 5199662Slinton 5209662Slinton case O_IF: 5219662Slinton if (cond(p->value.event.cond)) { 5229662Slinton evalcmdlist(p->value.event.actions); 5239662Slinton } 5249662Slinton break; 5259662Slinton 5269662Slinton case O_ONCE: 5279662Slinton event_once(p->value.event.cond, p->value.event.actions); 5289662Slinton break; 5299662Slinton 5309662Slinton case O_PRINTCALL: 5319662Slinton printcall(p->value.sym, whatblock(return_addr())); 5329662Slinton break; 5339662Slinton 5349662Slinton case O_PRINTIFCHANGED: 5359662Slinton printifchanged(p->value.arg[0]); 5369662Slinton break; 5379662Slinton 5389662Slinton case O_PRINTRTN: 5399662Slinton printrtn(p->value.sym); 5409662Slinton break; 5419662Slinton 5429662Slinton case O_PRINTSRCPOS: 5439662Slinton getsrcpos(); 5449662Slinton if (p->value.arg[0] == nil) { 5459662Slinton printsrcpos(); 5469662Slinton putchar('\n'); 5479662Slinton printlines(curline, curline); 5489662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 5499662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 5509662Slinton printf("tracei: "); 5519662Slinton printinst(pc, pc); 5529662Slinton } else { 5539662Slinton printf("trace: "); 5549662Slinton printlines(curline, curline); 5559662Slinton } 5569662Slinton } else { 5579662Slinton printsrcpos(); 5589662Slinton printf(": "); 5599662Slinton eval(p->value.arg[0]); 5609662Slinton prtree(stdout, p->value.arg[0]); 5619662Slinton printf(" = "); 5629662Slinton printval(p->value.arg[0]->nodetype); 5639662Slinton putchar('\n'); 5649662Slinton } 5659662Slinton break; 5669662Slinton 5679662Slinton case O_PROCRTN: 5689662Slinton procreturn(p->value.sym); 5699662Slinton break; 5709662Slinton 5719662Slinton case O_STOPIFCHANGED: 5729662Slinton stopifchanged(p->value.arg[0]); 5739662Slinton break; 5749662Slinton 5759662Slinton case O_STOPX: 5769662Slinton isstopped = true; 5779662Slinton break; 5789662Slinton 5799662Slinton case O_TRACEON: 5809662Slinton traceon(p->value.trace.inst, p->value.trace.event, 5819662Slinton p->value.trace.actions); 5829662Slinton break; 5839662Slinton 5849662Slinton case O_TRACEOFF: 5859662Slinton traceoff(p->value.lcon); 5869662Slinton break; 5879662Slinton 5889662Slinton default: 5899662Slinton panic("eval: bad op %d", p->op); 5909662Slinton } 59112538Scsvaf if(debug_flag[2]) { 59212538Scsvaf fprintf(stderr," evaluated %s \n",showoperator(p->op)); 59312538Scsvaf } 59412538Scsvaf 5959662Slinton } 5969662Slinton 5979662Slinton /* 5989662Slinton * Evaluate a list of commands. 5999662Slinton */ 6009662Slinton 6019662Slinton public evalcmdlist(cl) 6029662Slinton Cmdlist cl; 6039662Slinton { 6049662Slinton Command c; 6059662Slinton 6069662Slinton foreach (Command, c, cl) 6079662Slinton evalcmd(c); 6089662Slinton endfor 6099662Slinton } 6109662Slinton 6119662Slinton /* 6129662Slinton * Push "len" bytes onto the expression stack from address "addr" 6139662Slinton * in the process. If there isn't room on the stack, print an error message. 6149662Slinton */ 6159662Slinton 6169662Slinton public rpush(addr, len) 6179662Slinton Address addr; 6189662Slinton int len; 6199662Slinton { 6209662Slinton if (not canpush(len)) { 6219662Slinton error("expression too large to evaluate"); 6229662Slinton } else { 6239662Slinton chksp(); 6249662Slinton dread(sp, addr, len); 6259662Slinton sp += len; 6269662Slinton } 6279662Slinton } 6289662Slinton 6299662Slinton /* 6309662Slinton * Check if the stack has n bytes available. 6319662Slinton */ 6329662Slinton 6339662Slinton public Boolean canpush(n) 6349662Slinton Integer n; 6359662Slinton { 6369662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 6379662Slinton } 6389662Slinton 6399662Slinton /* 6409662Slinton * Push a small scalar of the given type onto the stack. 6419662Slinton */ 6429662Slinton 6439662Slinton public pushsmall(t, v) 6449662Slinton Symbol t; 6459662Slinton long v; 6469662Slinton { 6479662Slinton register Integer s; 6489662Slinton 6499662Slinton s = size(t); 6509662Slinton switch (s) { 6519662Slinton case sizeof(char): 6529662Slinton push(char, v); 6539662Slinton break; 6549662Slinton 6559662Slinton case sizeof(short): 6569662Slinton push(short, v); 6579662Slinton break; 6589662Slinton 6599662Slinton case sizeof(long): 6609662Slinton push(long, v); 6619662Slinton break; 6629662Slinton 6639662Slinton default: 6649662Slinton panic("bad size %d in popsmall", s); 6659662Slinton } 6669662Slinton } 6679662Slinton 6689662Slinton /* 6699662Slinton * Pop an item of the given type which is assumed to be no larger 6709662Slinton * than a long and return it expanded into a long. 6719662Slinton */ 6729662Slinton 6739662Slinton public long popsmall(t) 6749662Slinton Symbol t; 6759662Slinton { 6769662Slinton long r; 6779662Slinton 6789662Slinton switch (size(t)) { 6799662Slinton case sizeof(char): 6809662Slinton r = (long) pop(char); 6819662Slinton break; 6829662Slinton 6839662Slinton case sizeof(short): 6849662Slinton r = (long) pop(short); 6859662Slinton break; 6869662Slinton 6879662Slinton case sizeof(long): 6889662Slinton r = pop(long); 6899662Slinton break; 6909662Slinton 6919662Slinton default: 6929662Slinton panic("popsmall: size is %d", size(t)); 6939662Slinton } 6949662Slinton return r; 6959662Slinton } 6969662Slinton 6979662Slinton /* 6989662Slinton * Evaluate a conditional expression. 6999662Slinton */ 7009662Slinton 7019662Slinton public Boolean cond(p) 7029662Slinton Node p; 7039662Slinton { 7049662Slinton register Boolean b; 7059662Slinton 7069662Slinton if (p == nil) { 7079662Slinton b = true; 7089662Slinton } else { 7099662Slinton eval(p); 71013846Slinton b = (Boolean) pop(Boolrep); 7119662Slinton } 7129662Slinton return b; 7139662Slinton } 7149662Slinton 7159662Slinton /* 7169662Slinton * Return the address corresponding to a given tree. 7179662Slinton */ 7189662Slinton 7199662Slinton public Address lval(p) 7209662Slinton Node p; 7219662Slinton { 7229662Slinton if (p->op == O_RVAL) { 7239662Slinton eval(p->value.arg[0]); 7249662Slinton } else { 7259662Slinton eval(p); 7269662Slinton } 7279662Slinton return (Address) (pop(long)); 7289662Slinton } 7299662Slinton 7309662Slinton /* 7319662Slinton * Process a trace command, translating into the appropriate events 7329662Slinton * and associated actions. 7339662Slinton */ 7349662Slinton 7359662Slinton public trace(p) 7369662Slinton Node p; 7379662Slinton { 7389662Slinton Node exp, place, cond; 7399662Slinton Node left; 7409662Slinton 7419662Slinton exp = p->value.arg[0]; 7429662Slinton place = p->value.arg[1]; 7439662Slinton cond = p->value.arg[2]; 7449662Slinton if (exp == nil) { 7459662Slinton traceall(p->op, place, cond); 74611771Slinton } else if (exp->op == O_QLINE or exp->op == O_LCON) { 7479662Slinton traceinst(p->op, exp, cond); 7489662Slinton } else if (place != nil and place->op == O_QLINE) { 7499662Slinton traceat(p->op, exp, place, cond); 7509662Slinton } else { 7519861Slinton left = exp; 7529861Slinton if (left->op == O_RVAL or left->op == O_CALL) { 7539861Slinton left = left->value.arg[0]; 7549861Slinton } 7559662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 7569662Slinton traceproc(p->op, left->value.sym, place, cond); 7579662Slinton } else { 7589662Slinton tracedata(p->op, exp, place, cond); 7599662Slinton } 7609662Slinton } 7619662Slinton } 7629662Slinton 7639662Slinton /* 7649662Slinton * Set a breakpoint that will turn on tracing. 7659662Slinton */ 7669662Slinton 7679662Slinton private traceall(op, place, cond) 7689662Slinton Operator op; 7699662Slinton Node place; 7709662Slinton Node cond; 7719662Slinton { 7729662Slinton Symbol s; 7739662Slinton Node event; 7749662Slinton Command action; 7759662Slinton 7769662Slinton if (place == nil) { 7779662Slinton s = program; 7789662Slinton } else { 7799662Slinton s = place->value.sym; 7809662Slinton } 7819662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 7829662Slinton action = build(O_PRINTSRCPOS, 7839662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 7849662Slinton if (cond != nil) { 7859662Slinton action = build(O_IF, cond, buildcmdlist(action)); 7869662Slinton } 7879662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 7889662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 78911871Slinton if (isstdin()) { 79011871Slinton printevent(action->value.trace.event); 79111871Slinton } 7929662Slinton } 7939662Slinton 7949662Slinton /* 7959662Slinton * Set up the appropriate breakpoint for tracing an instruction. 7969662Slinton */ 7979662Slinton 7989662Slinton private traceinst(op, exp, cond) 7999662Slinton Operator op; 8009662Slinton Node exp; 8019662Slinton Node cond; 8029662Slinton { 80311771Slinton Node event, wh; 8049662Slinton Command action; 80511871Slinton Event e; 8069662Slinton 80711771Slinton if (exp->op == O_LCON) { 80811771Slinton wh = build(O_QLINE, build(O_SCON, cursource), exp); 80911771Slinton } else { 81011771Slinton wh = exp; 81111771Slinton } 8129662Slinton if (op == O_TRACEI) { 81311771Slinton event = build(O_EQ, build(O_SYM, pcsym), wh); 8149662Slinton } else { 81511771Slinton event = build(O_EQ, build(O_SYM, linesym), wh); 8169662Slinton } 81711771Slinton action = build(O_PRINTSRCPOS, wh); 8189662Slinton if (cond) { 8199662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8209662Slinton } 82111871Slinton e = addevent(event, buildcmdlist(action)); 82211871Slinton if (isstdin()) { 82311871Slinton printevent(e); 82411871Slinton } 8259662Slinton } 8269662Slinton 8279662Slinton /* 8289662Slinton * Set a breakpoint to print an expression at a given line or address. 8299662Slinton */ 8309662Slinton 8319662Slinton private traceat(op, exp, place, cond) 8329662Slinton Operator op; 8339662Slinton Node exp; 8349662Slinton Node place; 8359662Slinton Node cond; 8369662Slinton { 8379662Slinton Node event; 8389662Slinton Command action; 83911871Slinton Event e; 8409662Slinton 8419662Slinton if (op == O_TRACEI) { 8429662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 8439662Slinton } else { 8449662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 8459662Slinton } 8469662Slinton action = build(O_PRINTSRCPOS, exp); 8479662Slinton if (cond != nil) { 8489662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8499662Slinton } 85011871Slinton e = addevent(event, buildcmdlist(action)); 85111871Slinton if (isstdin()) { 85211871Slinton printevent(e); 85311871Slinton } 8549662Slinton } 8559662Slinton 8569662Slinton /* 8579662Slinton * Construct event for tracing a procedure. 8589662Slinton * 8599662Slinton * What we want here is 8609662Slinton * 8619662Slinton * when $proc = p do 8629662Slinton * if <condition> then 8639662Slinton * printcall; 8649662Slinton * once $pc = $retaddr do 8659662Slinton * printrtn; 8669662Slinton * end; 8679662Slinton * end if; 8689662Slinton * end; 8699662Slinton * 8709662Slinton * Note that "once" is like "when" except that the event 8719662Slinton * deletes itself as part of its associated action. 8729662Slinton */ 8739662Slinton 8749662Slinton private traceproc(op, p, place, cond) 8759662Slinton Operator op; 8769662Slinton Symbol p; 8779662Slinton Node place; 8789662Slinton Node cond; 8799662Slinton { 8809662Slinton Node event; 8819662Slinton Command action; 8829662Slinton Cmdlist actionlist; 88311871Slinton Event e; 8849662Slinton 8859662Slinton action = build(O_PRINTCALL, p); 8869662Slinton actionlist = list_alloc(); 8879662Slinton cmdlist_append(action, actionlist); 8889662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 8899662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 8909662Slinton cmdlist_append(action, actionlist); 8919662Slinton if (cond != nil) { 8929662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 8939662Slinton } 8949662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 89511871Slinton e = addevent(event, actionlist); 89611871Slinton if (isstdin()) { 89711871Slinton printevent(e); 89811871Slinton } 8999662Slinton } 9009662Slinton 9019662Slinton /* 9029662Slinton * Set up breakpoint for tracing data. 9039662Slinton */ 9049662Slinton 9059662Slinton private tracedata(op, exp, place, cond) 9069662Slinton Operator op; 9079662Slinton Node exp; 9089662Slinton Node place; 9099662Slinton Node cond; 9109662Slinton { 9119662Slinton Symbol p; 9129662Slinton Node event; 9139662Slinton Command action; 9149662Slinton 9159662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 9169662Slinton if (p == nil) { 9179662Slinton p = program; 9189662Slinton } 9199662Slinton action = build(O_PRINTIFCHANGED, exp); 9209662Slinton if (cond != nil) { 9219662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9229662Slinton } 9239662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 9249662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 9259662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 92611871Slinton if (isstdin()) { 92711871Slinton printevent(action->value.trace.event); 92811871Slinton } 9299662Slinton } 9309662Slinton 9319662Slinton /* 9329662Slinton * Setting and unsetting of stops. 9339662Slinton */ 9349662Slinton 9359662Slinton public stop(p) 9369662Slinton Node p; 9379662Slinton { 93813846Slinton Node exp, place, cond, t; 9399662Slinton Symbol s; 9409662Slinton Command action; 94111871Slinton Event e; 9429662Slinton 9439662Slinton exp = p->value.arg[0]; 9449662Slinton place = p->value.arg[1]; 9459662Slinton cond = p->value.arg[2]; 9469662Slinton if (exp != nil) { 9479662Slinton stopvar(p->op, exp, place, cond); 94813846Slinton } else { 94913846Slinton action = build(O_STOPX); 95013846Slinton if (cond != nil) { 95113846Slinton action = build(O_IF, cond, buildcmdlist(action)); 95211871Slinton } 95313846Slinton if (place != nil and place->op == O_SYM) { 95413846Slinton s = place->value.sym; 95513846Slinton t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 95613846Slinton if (cond != nil) { 95713846Slinton action = build(O_TRACEON, (p->op == O_STOPI), 95813846Slinton buildcmdlist(action)); 95913846Slinton e = addevent(t, buildcmdlist(action)); 96013846Slinton action->value.trace.event = e; 96113846Slinton } else { 96213846Slinton e = addevent(t, buildcmdlist(action)); 96313846Slinton } 96413846Slinton if (isstdin()) { 96513846Slinton printevent(e); 96613846Slinton } 96713846Slinton } else { 96813846Slinton stopinst(p->op, place, cond, action); 96913846Slinton } 9709662Slinton } 9719662Slinton } 9729662Slinton 97313846Slinton private stopinst(op, place, cond, action) 9749662Slinton Operator op; 9759662Slinton Node place; 9769662Slinton Node cond; 97713846Slinton Command action; 9789662Slinton { 9799662Slinton Node event; 98011871Slinton Event e; 9819662Slinton 9829662Slinton if (op == O_STOP) { 9839662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 9849662Slinton } else { 9859662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 9869662Slinton } 98713846Slinton e = addevent(event, buildcmdlist(action)); 98811871Slinton if (isstdin()) { 98911871Slinton printevent(e); 99011871Slinton } 9919662Slinton } 9929662Slinton 9939662Slinton /* 9949662Slinton * Implement stopping on assignment to a variable by adding it to 9959662Slinton * the variable list. 9969662Slinton */ 9979662Slinton 9989662Slinton private stopvar(op, exp, place, cond) 9999662Slinton Operator op; 10009662Slinton Node exp; 10019662Slinton Node place; 10029662Slinton Node cond; 10039662Slinton { 10049662Slinton Symbol p; 10059662Slinton Node event; 10069662Slinton Command action; 10079662Slinton 100814445Slinton if (place == nil) { 100914445Slinton if (exp->op == O_LCON) { 101014445Slinton p = program; 101114445Slinton } else { 101214445Slinton p = tcontainer(exp); 101314445Slinton if (p == nil) { 101414445Slinton p = program; 101514445Slinton } 101614445Slinton } 101714445Slinton } else { 101814445Slinton p = place->value.sym; 10199662Slinton } 102014445Slinton action = build(O_STOPIFCHANGED, exp); 102114445Slinton if (cond != nil) { 102214445Slinton action = build(O_IF, cond, buildcmdlist(action)); 102314445Slinton } 10249662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 10259662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 10269662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 102711871Slinton if (isstdin()) { 102811871Slinton printevent(action->value.trace.event); 102911871Slinton } 10309662Slinton } 10319662Slinton 10329662Slinton /* 10339662Slinton * Assign the value of an expression to a variable (or term). 10349662Slinton */ 10359662Slinton 10369662Slinton public assign(var, exp) 10379662Slinton Node var; 10389662Slinton Node exp; 10399662Slinton { 10409662Slinton Address addr; 10419662Slinton int varsize; 10429662Slinton char cvalue; 10439662Slinton short svalue; 10449662Slinton long lvalue; 10459662Slinton 10469662Slinton if (not compatible(var->nodetype, exp->nodetype)) { 10479662Slinton error("incompatible types"); 10489662Slinton } 10499662Slinton addr = lval(var); 10509662Slinton eval(exp); 10519662Slinton varsize = size(var->nodetype); 10529662Slinton if (varsize < sizeof(long)) { 10539662Slinton lvalue = pop(long); 10549662Slinton switch (varsize) { 10559662Slinton case sizeof(char): 10569662Slinton cvalue = lvalue; 10579662Slinton dwrite(&cvalue, addr, varsize); 10589662Slinton break; 10599662Slinton 10609662Slinton case sizeof(short): 10619662Slinton svalue = lvalue; 10629662Slinton dwrite(&svalue, addr, varsize); 10639662Slinton break; 10649662Slinton 10659662Slinton default: 10669662Slinton panic("bad size %d", varsize); 10679662Slinton } 10689662Slinton } else { 10699662Slinton sp -= varsize; 10709662Slinton dwrite(sp, addr, varsize); 10719662Slinton } 10729662Slinton } 10739662Slinton 10749662Slinton /* 10759662Slinton * Send some nasty mail to the current support person. 10769662Slinton */ 10779662Slinton 10789662Slinton public gripe() 10799662Slinton { 10809662Slinton typedef Operation(); 10819662Slinton Operation *old; 108214445Slinton int pid, status; 10839662Slinton 108414445Slinton char *maintainer = "linton@berkeley"; 10859662Slinton 10869662Slinton puts("Type control-D to end your message. Be sure to include"); 10879662Slinton puts("your name and the name of the file you are debugging."); 10889662Slinton putchar('\n'); 10899662Slinton old = signal(SIGINT, SIG_DFL); 109014445Slinton pid = back("Mail", stdin, stdout, "-s", "dbx gripe", maintainer, nil); 109114445Slinton signal(SIGINT, SIG_IGN); 109214445Slinton pwait(pid, &status); 10939662Slinton signal(SIGINT, old); 109414445Slinton if (status == 0) { 109514445Slinton puts("Thank you."); 109614445Slinton } else { 109714445Slinton puts("\nMail not sent."); 109814445Slinton } 10999662Slinton } 11009662Slinton 11019662Slinton /* 11029662Slinton * Give the user some help. 11039662Slinton */ 11049662Slinton 11059662Slinton public help() 11069662Slinton { 11079662Slinton puts("run - begin execution of the program"); 11089662Slinton puts("cont - continue execution"); 11099662Slinton puts("step - single step one line"); 11109662Slinton puts("next - step to next line (skip over calls)"); 11119662Slinton puts("trace <line#> - trace execution of the line"); 11129662Slinton puts("trace <proc> - trace calls to the procedure"); 11139662Slinton puts("trace <var> - trace changes to the variable"); 11149662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 11159662Slinton puts("stop at <line> - suspend execution at the line"); 11169662Slinton puts("stop in <proc> - suspend execution when <proc> is called"); 11179662Slinton puts("status - print trace/stop's in effect"); 11189662Slinton puts("delete <number> - remove trace or stop of given number"); 11199662Slinton puts("call <proc> - call the procedure"); 11209662Slinton puts("where - print currently active procedures"); 11219662Slinton puts("print <exp> - print the value of the expression"); 11229662Slinton puts("whatis <name> - print the declaration of the name"); 11239662Slinton puts("list <line>, <line> - list source lines"); 11249662Slinton puts("edit <proc> - edit file containing <proc>"); 11259662Slinton puts("gripe - send mail to the person in charge of dbx"); 11269662Slinton puts("quit - exit dbx"); 11279662Slinton } 11289662Slinton 11299662Slinton /* 11309662Slinton * Divert output to the given file name. 11319662Slinton * Cannot redirect to an existing file. 11329662Slinton */ 11339662Slinton 11349662Slinton private int so_fd; 11359662Slinton private Boolean notstdout; 11369662Slinton 11379662Slinton public setout(filename) 11389662Slinton String filename; 11399662Slinton { 11409662Slinton File f; 11419662Slinton 11429662Slinton f = fopen(filename, "r"); 11439662Slinton if (f != nil) { 11449662Slinton fclose(f); 11459662Slinton error("%s: file already exists", filename); 11469662Slinton } else { 11479662Slinton so_fd = dup(1); 11489662Slinton close(1); 11499662Slinton if (creat(filename, 0666) == nil) { 11509662Slinton unsetout(); 11519662Slinton error("can't create %s", filename); 11529662Slinton } 11539662Slinton notstdout = true; 11549662Slinton } 11559662Slinton } 11569662Slinton 11579662Slinton /* 11589662Slinton * Revert output to standard output. 11599662Slinton */ 11609662Slinton 11619662Slinton public unsetout() 11629662Slinton { 11639662Slinton fflush(stdout); 11649662Slinton close(1); 11659662Slinton if (dup(so_fd) != 1) { 11669662Slinton panic("standard out dup failed"); 11679662Slinton } 11689662Slinton close(so_fd); 11699662Slinton notstdout = false; 11709662Slinton } 11719662Slinton 11729662Slinton /* 11739662Slinton * Determine is standard output is currently being redirected 11749662Slinton * to a file (as far as we know). 11759662Slinton */ 11769662Slinton 11779662Slinton public Boolean isredirected() 11789662Slinton { 11799662Slinton return notstdout; 11809662Slinton } 1181