19662Slinton /* Copyright (c) 1982 Regents of the University of California */ 29662Slinton 3*18217Slinton static char sccsid[] = "@(#)eval.c 1.15 (Berkeley) 03/01/85"; 49662Slinton 5*18217Slinton static char rcsid[] = "$Header: eval.c,v 1.5 84/12/26 10:39:08 linton Exp $"; 6*18217Slinton 79662Slinton /* 89662Slinton * Tree evaluation. 99662Slinton */ 109662Slinton 119662Slinton #include "defs.h" 129662Slinton #include "tree.h" 139662Slinton #include "operators.h" 14*18217Slinton #include "debug.h" 159662Slinton #include "eval.h" 169662Slinton #include "events.h" 179662Slinton #include "symbols.h" 189662Slinton #include "scanner.h" 199662Slinton #include "source.h" 209662Slinton #include "object.h" 219662Slinton #include "mappings.h" 229662Slinton #include "process.h" 2316608Ssam #include "runtime.h" 249662Slinton #include "machine.h" 259662Slinton #include <signal.h> 269662Slinton 279662Slinton #ifndef public 289662Slinton 299662Slinton #include "machine.h" 309662Slinton 3112538Scsvaf #define STACKSIZE 20000 329662Slinton 339662Slinton typedef Char Stack; 349662Slinton 359662Slinton #define push(type, value) { \ 369662Slinton ((type *) (sp += sizeof(type)))[-1] = (value); \ 379662Slinton } 389662Slinton 399662Slinton #define pop(type) ( \ 409662Slinton (*((type *) (sp -= sizeof(type)))) \ 419662Slinton ) 429662Slinton 4316608Ssam #define popn(n, dest) { \ 4416608Ssam sp -= n; \ 4516608Ssam bcopy(sp, dest, n); \ 4616608Ssam } 4716608Ssam 489662Slinton #define alignstack() { \ 499662Slinton sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \ 509662Slinton } 519662Slinton 529662Slinton #endif 539662Slinton 549662Slinton public Stack stack[STACKSIZE]; 559662Slinton public Stack *sp = &stack[0]; 5614674Slinton public Boolean useInstLoc = false; 579662Slinton 589662Slinton #define chksp() \ 599662Slinton { \ 609662Slinton if (sp < &stack[0]) { \ 619662Slinton panic("stack underflow"); \ 629662Slinton } \ 639662Slinton } 649662Slinton 659662Slinton #define poparg(n, r, fr) { \ 669662Slinton eval(p->value.arg[n]); \ 679662Slinton if (isreal(p->op)) { \ 6816608Ssam if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \ 6916608Ssam fr = pop(float); \ 7016608Ssam } else { \ 7116608Ssam fr = pop(double); \ 7216608Ssam } \ 739662Slinton } else if (isint(p->op)) { \ 749662Slinton r = popsmall(p->value.arg[n]->nodetype); \ 759662Slinton } \ 769662Slinton } 779662Slinton 789662Slinton #define Boolrep char /* underlying representation type for booleans */ 799662Slinton 809662Slinton /* 81*18217Slinton * Command-level evaluation. 82*18217Slinton */ 83*18217Slinton 84*18217Slinton public Node topnode; 85*18217Slinton 86*18217Slinton public topeval (p) 87*18217Slinton Node p; 88*18217Slinton { 89*18217Slinton if (traceeval) { 90*18217Slinton fprintf(stderr, "topeval("); 91*18217Slinton prtree(stderr, p); 92*18217Slinton fprintf(stderr, ")\n"); 93*18217Slinton fflush(stderr); 94*18217Slinton } 95*18217Slinton topnode = p; 96*18217Slinton eval(p); 97*18217Slinton } 98*18217Slinton 99*18217Slinton /* 1009662Slinton * Evaluate a parse tree leaving the value on the top of the stack. 1019662Slinton */ 1029662Slinton 1039662Slinton public eval(p) 1049662Slinton register Node p; 1059662Slinton { 1069662Slinton long r0, r1; 1079662Slinton double fr0, fr1; 1089662Slinton Address addr; 1099662Slinton long i, n; 1109662Slinton int len; 111*18217Slinton Symbol s; 1129662Slinton Node n1, n2; 113*18217Slinton boolean b; 1149662Slinton File file; 115*18217Slinton String str; 1169662Slinton 1179662Slinton checkref(p); 118*18217Slinton if (traceeval) { 119*18217Slinton fprintf(stderr, "begin eval %s\n", opname(p->op)); 12012538Scsvaf } 1219662Slinton switch (degree(p->op)) { 1229662Slinton case BINARY: 1239662Slinton poparg(1, r1, fr1); 1249662Slinton poparg(0, r0, fr0); 1259662Slinton break; 1269662Slinton 1279662Slinton case UNARY: 1289662Slinton poparg(0, r0, fr0); 1299662Slinton break; 1309662Slinton 1319662Slinton default: 1329662Slinton /* do nothing */; 1339662Slinton } 1349662Slinton switch (p->op) { 1359662Slinton case O_SYM: 1369662Slinton s = p->value.sym; 1379662Slinton if (s == retaddrsym) { 1389662Slinton push(long, return_addr()); 139*18217Slinton } else if (isvariable(s)) { 140*18217Slinton if (s != program and not isactive(container(s))) { 141*18217Slinton error("\"%s\" is not active", symname(s)); 142*18217Slinton } 143*18217Slinton if (isvarparam(s) and not isopenarray(s)) { 144*18217Slinton rpush(address(s, nil), sizeof(Address)); 1459662Slinton } else { 146*18217Slinton push(Address, address(s, nil)); 1479662Slinton } 148*18217Slinton } else if (isblock(s)) { 149*18217Slinton push(Symbol, s); 150*18217Slinton } else if (isconst(s)) { 151*18217Slinton eval(constval(s)); 152*18217Slinton } else { 153*18217Slinton error("can't evaluate a %s", classname(s)); 1549662Slinton } 1559662Slinton break; 1569662Slinton 1579662Slinton case O_LCON: 158*18217Slinton case O_CCON: 1599662Slinton r0 = p->value.lcon; 1609662Slinton pushsmall(p->nodetype, r0); 1619662Slinton break; 1629662Slinton 1639662Slinton case O_FCON: 1649662Slinton push(double, p->value.fcon); 1659662Slinton break; 1669662Slinton 1679662Slinton case O_SCON: 1689662Slinton len = size(p->nodetype); 1699662Slinton mov(p->value.scon, sp, len); 1709662Slinton sp += len; 1719662Slinton break; 1729662Slinton 1739662Slinton case O_INDEX: 174*18217Slinton s = p->value.arg[0]->nodetype; 175*18217Slinton p->value.arg[0]->nodetype = t_addr; 176*18217Slinton eval(p->value.arg[0]); 177*18217Slinton p->value.arg[0]->nodetype = s; 178*18217Slinton n = pop(Address); 179*18217Slinton eval(p->value.arg[1]); 180*18217Slinton evalindex(s, n, popsmall(p->value.arg[1]->nodetype)); 1819662Slinton break; 1829662Slinton 1839662Slinton case O_DOT: 1849662Slinton s = p->value.arg[1]->value.sym; 185*18217Slinton eval(p->value.arg[0]); 186*18217Slinton n = pop(long); 1879662Slinton push(long, n + (s->symvalue.field.offset div 8)); 1889662Slinton break; 1899662Slinton 1909662Slinton /* 1919662Slinton * Get the value of the expression addressed by the top of the stack. 1929662Slinton * Push the result back on the stack. 1939662Slinton */ 1949662Slinton 1959662Slinton case O_INDIR: 1969662Slinton case O_RVAL: 1979662Slinton addr = pop(long); 1989662Slinton if (addr == 0) { 1999662Slinton error("reference through nil pointer"); 2009662Slinton } 201*18217Slinton len = size(p->nodetype); 2029662Slinton rpush(addr, len); 2039662Slinton break; 2049662Slinton 20511175Slinton /* 206*18217Slinton * Move the stack pointer so that the top of the stack has 207*18217Slinton * something corresponding to the size of the current node type. 208*18217Slinton * If this new type is bigger than the subtree (len > 0), 209*18217Slinton * then the stack is padded with nulls. If it's smaller, 210*18217Slinton * the stack is just dropped by the appropriate amount. 21111175Slinton */ 21211175Slinton case O_TYPERENAME: 213*18217Slinton len = size(p->nodetype) - size(p->value.arg[0]->nodetype); 214*18217Slinton if (len > 0) { 215*18217Slinton for (n = 0; n < len; n++) { 216*18217Slinton *sp++ = '\0'; 217*18217Slinton } 218*18217Slinton } else if (len < 0) { 219*18217Slinton sp += len; 220*18217Slinton } 22111175Slinton break; 22211175Slinton 2239662Slinton case O_COMMA: 224*18217Slinton eval(p->value.arg[0]); 225*18217Slinton if (p->value.arg[1] != nil) { 226*18217Slinton eval(p->value.arg[1]); 227*18217Slinton } 2289662Slinton break; 2299662Slinton 2309662Slinton case O_ITOF: 2319662Slinton push(double, (double) r0); 2329662Slinton break; 2339662Slinton 2349662Slinton case O_ADD: 2359662Slinton push(long, r0+r1); 2369662Slinton break; 2379662Slinton 2389662Slinton case O_ADDF: 2399662Slinton push(double, fr0+fr1); 2409662Slinton break; 2419662Slinton 2429662Slinton case O_SUB: 2439662Slinton push(long, r0-r1); 2449662Slinton break; 2459662Slinton 2469662Slinton case O_SUBF: 2479662Slinton push(double, fr0-fr1); 2489662Slinton break; 2499662Slinton 2509662Slinton case O_NEG: 2519662Slinton push(long, -r0); 2529662Slinton break; 2539662Slinton 2549662Slinton case O_NEGF: 2559662Slinton push(double, -fr0); 2569662Slinton break; 2579662Slinton 2589662Slinton case O_MUL: 2599662Slinton push(long, r0*r1); 2609662Slinton break; 2619662Slinton 2629662Slinton case O_MULF: 2639662Slinton push(double, fr0*fr1); 2649662Slinton break; 2659662Slinton 2669662Slinton case O_DIVF: 2679662Slinton if (fr1 == 0) { 2689662Slinton error("error: division by 0"); 2699662Slinton } 2709662Slinton push(double, fr0 / fr1); 2719662Slinton break; 2729662Slinton 2739662Slinton case O_DIV: 2749662Slinton if (r1 == 0) { 2759662Slinton error("error: div by 0"); 2769662Slinton } 2779662Slinton push(long, r0 div r1); 2789662Slinton break; 2799662Slinton 2809662Slinton case O_MOD: 2819662Slinton if (r1 == 0) { 2829662Slinton error("error: mod by 0"); 2839662Slinton } 2849662Slinton push(long, r0 mod r1); 2859662Slinton break; 2869662Slinton 2879662Slinton case O_LT: 2889662Slinton push(Boolrep, r0 < r1); 2899662Slinton break; 2909662Slinton 2919662Slinton case O_LTF: 2929662Slinton push(Boolrep, fr0 < fr1); 2939662Slinton break; 2949662Slinton 2959662Slinton case O_LE: 2969662Slinton push(Boolrep, r0 <= r1); 2979662Slinton break; 2989662Slinton 2999662Slinton case O_LEF: 3009662Slinton push(Boolrep, fr0 <= fr1); 3019662Slinton break; 3029662Slinton 3039662Slinton case O_GT: 3049662Slinton push(Boolrep, r0 > r1); 3059662Slinton break; 3069662Slinton 3079662Slinton case O_GTF: 3089662Slinton push(Boolrep, fr0 > fr1); 3099662Slinton break; 3109662Slinton 3119662Slinton case O_EQ: 3129662Slinton push(Boolrep, r0 == r1); 3139662Slinton break; 3149662Slinton 3159662Slinton case O_EQF: 3169662Slinton push(Boolrep, fr0 == fr1); 3179662Slinton break; 3189662Slinton 3199662Slinton case O_NE: 3209662Slinton push(Boolrep, r0 != r1); 3219662Slinton break; 3229662Slinton 3239662Slinton case O_NEF: 3249662Slinton push(Boolrep, fr0 != fr1); 3259662Slinton break; 3269662Slinton 3279662Slinton case O_AND: 3289662Slinton push(Boolrep, r0 and r1); 3299662Slinton break; 3309662Slinton 3319662Slinton case O_OR: 3329662Slinton push(Boolrep, r0 or r1); 3339662Slinton break; 3349662Slinton 3359662Slinton case O_ASSIGN: 3369662Slinton assign(p->value.arg[0], p->value.arg[1]); 3379662Slinton break; 3389662Slinton 3399662Slinton case O_CHFILE: 3409662Slinton if (p->value.scon == nil) { 3419662Slinton printf("%s\n", cursource); 3429662Slinton } else { 3439662Slinton file = opensource(p->value.scon); 3449662Slinton if (file == nil) { 3459662Slinton error("can't read \"%s\"", p->value.scon); 3469662Slinton } else { 3479662Slinton fclose(file); 3489662Slinton setsource(p->value.scon); 3499662Slinton } 3509662Slinton } 3519662Slinton break; 3529662Slinton 3539662Slinton case O_CONT: 35411871Slinton cont(p->value.lcon); 3559662Slinton printnews(); 3569662Slinton break; 3579662Slinton 3589662Slinton case O_LIST: 359*18217Slinton list(p); 3609662Slinton break; 3619662Slinton 3629662Slinton case O_FUNC: 363*18217Slinton func(p->value.arg[0]); 3649662Slinton break; 3659662Slinton 3669662Slinton case O_EXAMINE: 3679662Slinton eval(p->value.examine.beginaddr); 3689662Slinton r0 = pop(long); 3699662Slinton if (p->value.examine.endaddr == nil) { 3709662Slinton n = p->value.examine.count; 37111175Slinton if (n == 0) { 37211175Slinton printvalue(r0, p->value.examine.mode); 37311175Slinton } else if (streq(p->value.examine.mode, "i")) { 3749662Slinton printninst(n, (Address) r0); 3759662Slinton } else { 3769662Slinton printndata(n, (Address) r0, p->value.examine.mode); 3779662Slinton } 3789662Slinton } else { 3799662Slinton eval(p->value.examine.endaddr); 3809662Slinton r1 = pop(long); 3819662Slinton if (streq(p->value.examine.mode, "i")) { 3829662Slinton printinst((Address)r0, (Address)r1); 3839662Slinton } else { 3849662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 3859662Slinton } 3869662Slinton } 3879662Slinton break; 3889662Slinton 3899662Slinton case O_PRINT: 3909662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 3919662Slinton eval(n1->value.arg[0]); 3929662Slinton printval(n1->value.arg[0]->nodetype); 3939662Slinton putchar(' '); 3949662Slinton } 3959662Slinton putchar('\n'); 3969662Slinton break; 3979662Slinton 3989662Slinton case O_PSYM: 3999662Slinton if (p->value.arg[0]->op == O_SYM) { 4009662Slinton psym(p->value.arg[0]->value.sym); 4019662Slinton } else { 4029662Slinton psym(p->value.arg[0]->nodetype); 4039662Slinton } 4049662Slinton break; 4059662Slinton 4069662Slinton case O_QLINE: 4079662Slinton eval(p->value.arg[1]); 4089662Slinton break; 4099662Slinton 4109662Slinton case O_STEP: 4119662Slinton b = inst_tracing; 4129662Slinton inst_tracing = (Boolean) (not p->value.step.source); 4139662Slinton if (p->value.step.skipcalls) { 4149662Slinton next(); 4159662Slinton } else { 4169662Slinton stepc(); 4179662Slinton } 4189662Slinton inst_tracing = b; 41914674Slinton useInstLoc = (Boolean) (not p->value.step.source); 4209662Slinton printnews(); 4219662Slinton break; 4229662Slinton 4239662Slinton case O_WHATIS: 4249662Slinton if (p->value.arg[0]->op == O_SYM) { 4259662Slinton printdecl(p->value.arg[0]->value.sym); 4269662Slinton } else { 4279662Slinton printdecl(p->value.arg[0]->nodetype); 4289662Slinton } 4299662Slinton break; 4309662Slinton 4319662Slinton case O_WHERE: 4329662Slinton wherecmd(); 4339662Slinton break; 4349662Slinton 4359662Slinton case O_WHEREIS: 43612538Scsvaf if (p->value.arg[0]->op == O_SYM) { 437*18217Slinton printwhereis(stdout, p->value.arg[0]->value.sym); 43812538Scsvaf } else { 439*18217Slinton printwhereis(stdout, p->value.arg[0]->nodetype); 44012538Scsvaf } 4419662Slinton break; 4429662Slinton 4439662Slinton case O_WHICH: 44412538Scsvaf if (p->value.arg[0]->op == O_SYM) { 445*18217Slinton printwhich(stdout, p->value.arg[0]->value.sym); 44612538Scsvaf } else { 447*18217Slinton printwhich(stdout, p->value.arg[0]->nodetype); 44812538Scsvaf } 4499662Slinton putchar('\n'); 4509662Slinton break; 4519662Slinton 4529662Slinton case O_ALIAS: 4539662Slinton n1 = p->value.arg[0]; 4549662Slinton n2 = p->value.arg[1]; 455*18217Slinton if (n2 == nil) { 456*18217Slinton if (n1 == nil) { 457*18217Slinton alias(nil, nil, nil); 458*18217Slinton } else { 459*18217Slinton alias(n1->value.name, nil, nil); 460*18217Slinton } 461*18217Slinton } else if (n2->op == O_NAME) { 462*18217Slinton str = ident(n2->value.name); 463*18217Slinton alias(n1->value.name, nil, strdup(str)); 4649662Slinton } else { 465*18217Slinton if (n1->op == O_COMMA) { 466*18217Slinton alias( 467*18217Slinton n1->value.arg[0]->value.name, 468*18217Slinton (List) n1->value.arg[1], 469*18217Slinton n2->value.scon 470*18217Slinton ); 471*18217Slinton } else { 472*18217Slinton alias(n1->value.name, nil, n2->value.scon); 473*18217Slinton } 4749662Slinton } 4759662Slinton break; 4769662Slinton 477*18217Slinton case O_UNALIAS: 478*18217Slinton unalias(p->value.arg[0]->value.name); 479*18217Slinton break; 480*18217Slinton 481*18217Slinton case O_CALLPROC: 482*18217Slinton callproc(p, false); 483*18217Slinton break; 484*18217Slinton 4859662Slinton case O_CALL: 486*18217Slinton callproc(p, true); 4879662Slinton break; 4889662Slinton 4899662Slinton case O_CATCH: 490*18217Slinton if (p->value.lcon == 0) { 491*18217Slinton printsigscaught(process); 492*18217Slinton } else { 493*18217Slinton psigtrace(process, p->value.lcon, true); 494*18217Slinton } 4959662Slinton break; 4969662Slinton 4979662Slinton case O_EDIT: 4989662Slinton edit(p->value.scon); 4999662Slinton break; 5009662Slinton 50112538Scsvaf case O_DEBUG: 50212538Scsvaf debug(p); 50312538Scsvaf break; 50412538Scsvaf 50516608Ssam case O_DOWN: 50616608Ssam checkref(p->value.arg[0]); 50716608Ssam assert(p->value.arg[0]->op == O_LCON); 50816608Ssam down(p->value.arg[0]->value.lcon); 50916608Ssam break; 51016608Ssam 5119662Slinton case O_DUMP: 512*18217Slinton if (p->value.arg[0] == nil) { 513*18217Slinton dumpall(); 514*18217Slinton } else { 515*18217Slinton s = p->value.arg[0]->value.sym; 516*18217Slinton if (s == curfunc) { 517*18217Slinton dump(nil); 518*18217Slinton } else { 519*18217Slinton dump(s); 520*18217Slinton } 521*18217Slinton } 5229662Slinton break; 5239662Slinton 5249662Slinton case O_GRIPE: 5259662Slinton gripe(); 5269662Slinton break; 5279662Slinton 5289662Slinton case O_HELP: 5299662Slinton help(); 5309662Slinton break; 5319662Slinton 5329662Slinton case O_IGNORE: 533*18217Slinton if (p->value.lcon == 0) { 534*18217Slinton printsigsignored(process); 535*18217Slinton } else { 536*18217Slinton psigtrace(process, p->value.lcon, false); 537*18217Slinton } 5389662Slinton break; 5399662Slinton 54016608Ssam case O_RETURN: 54116608Ssam if (p->value.arg[0] == nil) { 54216608Ssam rtnfunc(nil); 54316608Ssam } else { 54416608Ssam assert(p->value.arg[0]->op == O_SYM); 54516608Ssam rtnfunc(p->value.arg[0]->value.sym); 54616608Ssam } 54716608Ssam break; 54816608Ssam 5499662Slinton case O_RUN: 5509662Slinton run(); 5519662Slinton break; 5529662Slinton 553*18217Slinton case O_SET: 554*18217Slinton set(p->value.arg[0], p->value.arg[1]); 555*18217Slinton break; 556*18217Slinton 557*18217Slinton case O_SEARCH: 558*18217Slinton search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon); 559*18217Slinton break; 560*18217Slinton 5619662Slinton case O_SOURCE: 5629662Slinton setinput(p->value.scon); 5639662Slinton break; 5649662Slinton 5659662Slinton case O_STATUS: 5669662Slinton status(); 5679662Slinton break; 5689662Slinton 5699662Slinton case O_TRACE: 5709662Slinton case O_TRACEI: 5719662Slinton trace(p); 5729662Slinton break; 5739662Slinton 5749662Slinton case O_STOP: 5759662Slinton case O_STOPI: 5769662Slinton stop(p); 5779662Slinton break; 5789662Slinton 579*18217Slinton case O_UNSET: 580*18217Slinton undefvar(p->value.arg[0]->value.name); 581*18217Slinton break; 582*18217Slinton 58316608Ssam case O_UP: 58416608Ssam checkref(p->value.arg[0]); 58516608Ssam assert(p->value.arg[0]->op == O_LCON); 58616608Ssam up(p->value.arg[0]->value.lcon); 58716608Ssam break; 58816608Ssam 5899662Slinton case O_ADDEVENT: 5909662Slinton addevent(p->value.event.cond, p->value.event.actions); 5919662Slinton break; 5929662Slinton 5939662Slinton case O_DELETE: 59416608Ssam n1 = p->value.arg[0]; 59516608Ssam while (n1->op == O_COMMA) { 59616608Ssam n2 = n1->value.arg[0]; 59716608Ssam assert(n2->op == O_LCON); 59816608Ssam if (not delevent((unsigned int) n2->value.lcon)) { 59916608Ssam error("unknown event %ld", n2->value.lcon); 60016608Ssam } 60116608Ssam n1 = n1->value.arg[1]; 60216608Ssam } 60316608Ssam assert(n1->op == O_LCON); 60416608Ssam if (not delevent((unsigned int) n1->value.lcon)) { 60516608Ssam error("unknown event %ld", n1->value.lcon); 60616608Ssam } 6079662Slinton break; 6089662Slinton 6099662Slinton case O_ENDX: 6109662Slinton endprogram(); 6119662Slinton break; 6129662Slinton 6139662Slinton case O_IF: 6149662Slinton if (cond(p->value.event.cond)) { 6159662Slinton evalcmdlist(p->value.event.actions); 6169662Slinton } 6179662Slinton break; 6189662Slinton 6199662Slinton case O_ONCE: 6209662Slinton event_once(p->value.event.cond, p->value.event.actions); 6219662Slinton break; 6229662Slinton 6239662Slinton case O_PRINTCALL: 6249662Slinton printcall(p->value.sym, whatblock(return_addr())); 6259662Slinton break; 6269662Slinton 6279662Slinton case O_PRINTIFCHANGED: 6289662Slinton printifchanged(p->value.arg[0]); 6299662Slinton break; 6309662Slinton 6319662Slinton case O_PRINTRTN: 6329662Slinton printrtn(p->value.sym); 6339662Slinton break; 6349662Slinton 6359662Slinton case O_PRINTSRCPOS: 6369662Slinton getsrcpos(); 6379662Slinton if (p->value.arg[0] == nil) { 6389662Slinton printsrcpos(); 6399662Slinton putchar('\n'); 6409662Slinton printlines(curline, curline); 6419662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 6429662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 6439662Slinton printf("tracei: "); 6449662Slinton printinst(pc, pc); 6459662Slinton } else { 646*18217Slinton if (canReadSource()) { 647*18217Slinton printf("trace: "); 648*18217Slinton printlines(curline, curline); 649*18217Slinton } 6509662Slinton } 6519662Slinton } else { 6529662Slinton printsrcpos(); 6539662Slinton printf(": "); 6549662Slinton eval(p->value.arg[0]); 6559662Slinton prtree(stdout, p->value.arg[0]); 6569662Slinton printf(" = "); 6579662Slinton printval(p->value.arg[0]->nodetype); 6589662Slinton putchar('\n'); 6599662Slinton } 6609662Slinton break; 6619662Slinton 6629662Slinton case O_PROCRTN: 6639662Slinton procreturn(p->value.sym); 6649662Slinton break; 6659662Slinton 6669662Slinton case O_STOPIFCHANGED: 6679662Slinton stopifchanged(p->value.arg[0]); 6689662Slinton break; 6699662Slinton 6709662Slinton case O_STOPX: 6719662Slinton isstopped = true; 6729662Slinton break; 6739662Slinton 6749662Slinton case O_TRACEON: 6759662Slinton traceon(p->value.trace.inst, p->value.trace.event, 6769662Slinton p->value.trace.actions); 6779662Slinton break; 6789662Slinton 6799662Slinton case O_TRACEOFF: 6809662Slinton traceoff(p->value.lcon); 6819662Slinton break; 6829662Slinton 6839662Slinton default: 6849662Slinton panic("eval: bad op %d", p->op); 6859662Slinton } 686*18217Slinton if (traceeval) { 687*18217Slinton fprintf(stderr, "end eval %s\n", opname(p->op)); 688*18217Slinton } 6899662Slinton } 6909662Slinton 6919662Slinton /* 6929662Slinton * Evaluate a list of commands. 6939662Slinton */ 6949662Slinton 6959662Slinton public evalcmdlist(cl) 6969662Slinton Cmdlist cl; 6979662Slinton { 6989662Slinton Command c; 6999662Slinton 7009662Slinton foreach (Command, c, cl) 7019662Slinton evalcmd(c); 7029662Slinton endfor 7039662Slinton } 7049662Slinton 7059662Slinton /* 7069662Slinton * Push "len" bytes onto the expression stack from address "addr" 7079662Slinton * in the process. If there isn't room on the stack, print an error message. 7089662Slinton */ 7099662Slinton 7109662Slinton public rpush(addr, len) 7119662Slinton Address addr; 7129662Slinton int len; 7139662Slinton { 7149662Slinton if (not canpush(len)) { 7159662Slinton error("expression too large to evaluate"); 7169662Slinton } else { 7179662Slinton chksp(); 7189662Slinton dread(sp, addr, len); 7199662Slinton sp += len; 7209662Slinton } 7219662Slinton } 7229662Slinton 7239662Slinton /* 7249662Slinton * Check if the stack has n bytes available. 7259662Slinton */ 7269662Slinton 7279662Slinton public Boolean canpush(n) 7289662Slinton Integer n; 7299662Slinton { 7309662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 7319662Slinton } 7329662Slinton 7339662Slinton /* 7349662Slinton * Push a small scalar of the given type onto the stack. 7359662Slinton */ 7369662Slinton 7379662Slinton public pushsmall(t, v) 7389662Slinton Symbol t; 7399662Slinton long v; 7409662Slinton { 7419662Slinton register Integer s; 7429662Slinton 7439662Slinton s = size(t); 7449662Slinton switch (s) { 7459662Slinton case sizeof(char): 7469662Slinton push(char, v); 7479662Slinton break; 7489662Slinton 7499662Slinton case sizeof(short): 7509662Slinton push(short, v); 7519662Slinton break; 7529662Slinton 7539662Slinton case sizeof(long): 7549662Slinton push(long, v); 7559662Slinton break; 7569662Slinton 7579662Slinton default: 7589662Slinton panic("bad size %d in popsmall", s); 7599662Slinton } 7609662Slinton } 7619662Slinton 7629662Slinton /* 7639662Slinton * Pop an item of the given type which is assumed to be no larger 7649662Slinton * than a long and return it expanded into a long. 7659662Slinton */ 7669662Slinton 7679662Slinton public long popsmall(t) 7689662Slinton Symbol t; 7699662Slinton { 770*18217Slinton register integer n; 7719662Slinton long r; 7729662Slinton 773*18217Slinton n = size(t); 774*18217Slinton if (n == sizeof(char)) { 775*18217Slinton if (t->class == RANGE and t->symvalue.rangev.lower >= 0) { 776*18217Slinton r = (long) pop(unsigned char); 777*18217Slinton } else { 7789662Slinton r = (long) pop(char); 779*18217Slinton } 780*18217Slinton } else if (n == sizeof(short)) { 781*18217Slinton if (t->class == RANGE and t->symvalue.rangev.lower >= 0) { 782*18217Slinton r = (long) pop(unsigned short); 783*18217Slinton } else { 7849662Slinton r = (long) pop(short); 785*18217Slinton } 786*18217Slinton } else if (n == sizeof(long)) { 787*18217Slinton r = pop(long); 788*18217Slinton } else { 789*18217Slinton error("[internal error: size %d in popsmall]", n); 7909662Slinton } 7919662Slinton return r; 7929662Slinton } 7939662Slinton 7949662Slinton /* 7959662Slinton * Evaluate a conditional expression. 7969662Slinton */ 7979662Slinton 7989662Slinton public Boolean cond(p) 7999662Slinton Node p; 8009662Slinton { 8019662Slinton register Boolean b; 8029662Slinton 8039662Slinton if (p == nil) { 8049662Slinton b = true; 8059662Slinton } else { 8069662Slinton eval(p); 80713846Slinton b = (Boolean) pop(Boolrep); 8089662Slinton } 8099662Slinton return b; 8109662Slinton } 8119662Slinton 8129662Slinton /* 8139662Slinton * Return the address corresponding to a given tree. 8149662Slinton */ 8159662Slinton 8169662Slinton public Address lval(p) 8179662Slinton Node p; 8189662Slinton { 8199662Slinton if (p->op == O_RVAL) { 8209662Slinton eval(p->value.arg[0]); 8219662Slinton } else { 8229662Slinton eval(p); 8239662Slinton } 8249662Slinton return (Address) (pop(long)); 8259662Slinton } 8269662Slinton 8279662Slinton /* 8289662Slinton * Process a trace command, translating into the appropriate events 8299662Slinton * and associated actions. 8309662Slinton */ 8319662Slinton 8329662Slinton public trace(p) 8339662Slinton Node p; 8349662Slinton { 8359662Slinton Node exp, place, cond; 8369662Slinton Node left; 8379662Slinton 8389662Slinton exp = p->value.arg[0]; 8399662Slinton place = p->value.arg[1]; 8409662Slinton cond = p->value.arg[2]; 8419662Slinton if (exp == nil) { 8429662Slinton traceall(p->op, place, cond); 84311771Slinton } else if (exp->op == O_QLINE or exp->op == O_LCON) { 8449662Slinton traceinst(p->op, exp, cond); 8459662Slinton } else if (place != nil and place->op == O_QLINE) { 8469662Slinton traceat(p->op, exp, place, cond); 8479662Slinton } else { 8489861Slinton left = exp; 8499861Slinton if (left->op == O_RVAL or left->op == O_CALL) { 8509861Slinton left = left->value.arg[0]; 8519861Slinton } 8529662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 8539662Slinton traceproc(p->op, left->value.sym, place, cond); 8549662Slinton } else { 8559662Slinton tracedata(p->op, exp, place, cond); 8569662Slinton } 8579662Slinton } 8589662Slinton } 8599662Slinton 8609662Slinton /* 8619662Slinton * Set a breakpoint that will turn on tracing. 8629662Slinton */ 8639662Slinton 8649662Slinton private traceall(op, place, cond) 8659662Slinton Operator op; 8669662Slinton Node place; 8679662Slinton Node cond; 8689662Slinton { 8699662Slinton Symbol s; 8709662Slinton Node event; 8719662Slinton Command action; 8729662Slinton 8739662Slinton if (place == nil) { 8749662Slinton s = program; 8759662Slinton } else { 8769662Slinton s = place->value.sym; 8779662Slinton } 8789662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 8799662Slinton action = build(O_PRINTSRCPOS, 8809662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 8819662Slinton if (cond != nil) { 8829662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8839662Slinton } 8849662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 8859662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 88611871Slinton if (isstdin()) { 88711871Slinton printevent(action->value.trace.event); 88811871Slinton } 8899662Slinton } 8909662Slinton 8919662Slinton /* 8929662Slinton * Set up the appropriate breakpoint for tracing an instruction. 8939662Slinton */ 8949662Slinton 8959662Slinton private traceinst(op, exp, cond) 8969662Slinton Operator op; 8979662Slinton Node exp; 8989662Slinton Node cond; 8999662Slinton { 90011771Slinton Node event, wh; 9019662Slinton Command action; 90211871Slinton Event e; 9039662Slinton 90411771Slinton if (exp->op == O_LCON) { 905*18217Slinton wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp); 90611771Slinton } else { 90711771Slinton wh = exp; 90811771Slinton } 9099662Slinton if (op == O_TRACEI) { 91011771Slinton event = build(O_EQ, build(O_SYM, pcsym), wh); 9119662Slinton } else { 91211771Slinton event = build(O_EQ, build(O_SYM, linesym), wh); 9139662Slinton } 91411771Slinton action = build(O_PRINTSRCPOS, wh); 9159662Slinton if (cond) { 9169662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9179662Slinton } 91811871Slinton e = addevent(event, buildcmdlist(action)); 91911871Slinton if (isstdin()) { 92011871Slinton printevent(e); 92111871Slinton } 9229662Slinton } 9239662Slinton 9249662Slinton /* 9259662Slinton * Set a breakpoint to print an expression at a given line or address. 9269662Slinton */ 9279662Slinton 9289662Slinton private traceat(op, exp, place, cond) 9299662Slinton Operator op; 9309662Slinton Node exp; 9319662Slinton Node place; 9329662Slinton Node cond; 9339662Slinton { 9349662Slinton Node event; 9359662Slinton Command action; 93611871Slinton Event e; 9379662Slinton 9389662Slinton if (op == O_TRACEI) { 9399662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 9409662Slinton } else { 9419662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 9429662Slinton } 9439662Slinton action = build(O_PRINTSRCPOS, exp); 9449662Slinton if (cond != nil) { 9459662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9469662Slinton } 94711871Slinton e = addevent(event, buildcmdlist(action)); 94811871Slinton if (isstdin()) { 94911871Slinton printevent(e); 95011871Slinton } 9519662Slinton } 9529662Slinton 9539662Slinton /* 9549662Slinton * Construct event for tracing a procedure. 9559662Slinton * 9569662Slinton * What we want here is 9579662Slinton * 9589662Slinton * when $proc = p do 9599662Slinton * if <condition> then 9609662Slinton * printcall; 9619662Slinton * once $pc = $retaddr do 9629662Slinton * printrtn; 9639662Slinton * end; 9649662Slinton * end if; 9659662Slinton * end; 9669662Slinton * 9679662Slinton * Note that "once" is like "when" except that the event 9689662Slinton * deletes itself as part of its associated action. 9699662Slinton */ 9709662Slinton 9719662Slinton private traceproc(op, p, place, cond) 9729662Slinton Operator op; 9739662Slinton Symbol p; 9749662Slinton Node place; 9759662Slinton Node cond; 9769662Slinton { 9779662Slinton Node event; 9789662Slinton Command action; 9799662Slinton Cmdlist actionlist; 98011871Slinton Event e; 9819662Slinton 9829662Slinton action = build(O_PRINTCALL, p); 9839662Slinton actionlist = list_alloc(); 9849662Slinton cmdlist_append(action, actionlist); 9859662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 9869662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 9879662Slinton cmdlist_append(action, actionlist); 9889662Slinton if (cond != nil) { 9899662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 9909662Slinton } 9919662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 99211871Slinton e = addevent(event, actionlist); 99311871Slinton if (isstdin()) { 99411871Slinton printevent(e); 99511871Slinton } 9969662Slinton } 9979662Slinton 9989662Slinton /* 9999662Slinton * Set up breakpoint for tracing data. 10009662Slinton */ 10019662Slinton 10029662Slinton private tracedata(op, exp, place, cond) 10039662Slinton Operator op; 10049662Slinton Node exp; 10059662Slinton Node place; 10069662Slinton Node cond; 10079662Slinton { 10089662Slinton Symbol p; 10099662Slinton Node event; 10109662Slinton Command action; 10119662Slinton 10129662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 10139662Slinton if (p == nil) { 10149662Slinton p = program; 10159662Slinton } 10169662Slinton action = build(O_PRINTIFCHANGED, exp); 10179662Slinton if (cond != nil) { 10189662Slinton action = build(O_IF, cond, buildcmdlist(action)); 10199662Slinton } 10209662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 10219662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 10229662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 102311871Slinton if (isstdin()) { 102411871Slinton printevent(action->value.trace.event); 102511871Slinton } 10269662Slinton } 10279662Slinton 10289662Slinton /* 10299662Slinton * Setting and unsetting of stops. 10309662Slinton */ 10319662Slinton 10329662Slinton public stop(p) 10339662Slinton Node p; 10349662Slinton { 103513846Slinton Node exp, place, cond, t; 10369662Slinton Symbol s; 10379662Slinton Command action; 103811871Slinton Event e; 10399662Slinton 10409662Slinton exp = p->value.arg[0]; 10419662Slinton place = p->value.arg[1]; 10429662Slinton cond = p->value.arg[2]; 10439662Slinton if (exp != nil) { 10449662Slinton stopvar(p->op, exp, place, cond); 104513846Slinton } else { 104613846Slinton action = build(O_STOPX); 104713846Slinton if (cond != nil) { 104813846Slinton action = build(O_IF, cond, buildcmdlist(action)); 104911871Slinton } 105016608Ssam if (place == nil or place->op == O_SYM) { 105116608Ssam if (place == nil) { 105216608Ssam s = program; 105316608Ssam } else { 105416608Ssam s = place->value.sym; 105516608Ssam } 105613846Slinton t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 105713846Slinton if (cond != nil) { 105813846Slinton action = build(O_TRACEON, (p->op == O_STOPI), 105913846Slinton buildcmdlist(action)); 106013846Slinton e = addevent(t, buildcmdlist(action)); 106113846Slinton action->value.trace.event = e; 106213846Slinton } else { 106313846Slinton e = addevent(t, buildcmdlist(action)); 106413846Slinton } 106513846Slinton if (isstdin()) { 106613846Slinton printevent(e); 106713846Slinton } 106813846Slinton } else { 106913846Slinton stopinst(p->op, place, cond, action); 107013846Slinton } 10719662Slinton } 10729662Slinton } 10739662Slinton 107413846Slinton private stopinst(op, place, cond, action) 10759662Slinton Operator op; 10769662Slinton Node place; 10779662Slinton Node cond; 107813846Slinton Command action; 10799662Slinton { 10809662Slinton Node event; 108111871Slinton Event e; 10829662Slinton 10839662Slinton if (op == O_STOP) { 10849662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 10859662Slinton } else { 10869662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 10879662Slinton } 108813846Slinton e = addevent(event, buildcmdlist(action)); 108911871Slinton if (isstdin()) { 109011871Slinton printevent(e); 109111871Slinton } 10929662Slinton } 10939662Slinton 10949662Slinton /* 10959662Slinton * Implement stopping on assignment to a variable by adding it to 10969662Slinton * the variable list. 10979662Slinton */ 10989662Slinton 10999662Slinton private stopvar(op, exp, place, cond) 11009662Slinton Operator op; 11019662Slinton Node exp; 11029662Slinton Node place; 11039662Slinton Node cond; 11049662Slinton { 11059662Slinton Symbol p; 11069662Slinton Node event; 11079662Slinton Command action; 11089662Slinton 110914445Slinton if (place == nil) { 111014445Slinton if (exp->op == O_LCON) { 111114445Slinton p = program; 111214445Slinton } else { 111314445Slinton p = tcontainer(exp); 111414445Slinton if (p == nil) { 111514445Slinton p = program; 111614445Slinton } 111714445Slinton } 111814445Slinton } else { 111914445Slinton p = place->value.sym; 11209662Slinton } 112114445Slinton action = build(O_STOPIFCHANGED, exp); 112214445Slinton if (cond != nil) { 112314445Slinton action = build(O_IF, cond, buildcmdlist(action)); 112414445Slinton } 11259662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 11269662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 11279662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 112811871Slinton if (isstdin()) { 112911871Slinton printevent(action->value.trace.event); 113011871Slinton } 11319662Slinton } 11329662Slinton 11339662Slinton /* 11349662Slinton * Assign the value of an expression to a variable (or term). 11359662Slinton */ 11369662Slinton 11379662Slinton public assign(var, exp) 11389662Slinton Node var; 11399662Slinton Node exp; 11409662Slinton { 11419662Slinton Address addr; 114216608Ssam integer varsize, expsize; 11439662Slinton char cvalue; 11449662Slinton short svalue; 11459662Slinton long lvalue; 114616608Ssam float fvalue; 11479662Slinton 1148*18217Slinton if (var->op == O_SYM and regnum(var->value.sym) != -1) { 1149*18217Slinton eval(exp); 1150*18217Slinton setreg(regnum(var->value.sym), pop(Address)); 115116608Ssam } else { 1152*18217Slinton addr = lval(var); 1153*18217Slinton varsize = size(var->nodetype); 1154*18217Slinton expsize = size(exp->nodetype); 1155*18217Slinton eval(exp); 1156*18217Slinton if (varsize == sizeof(float) and expsize == sizeof(double)) { 1157*18217Slinton fvalue = (float) pop(double); 1158*18217Slinton dwrite(&fvalue, addr, sizeof(fvalue)); 1159*18217Slinton } else { 1160*18217Slinton if (varsize < sizeof(long)) { 1161*18217Slinton lvalue = 0; 1162*18217Slinton popn(expsize, &lvalue); 1163*18217Slinton if (varsize == sizeof(char)) { 116416608Ssam cvalue = lvalue; 116516608Ssam dwrite(&cvalue, addr, sizeof(cvalue)); 1166*18217Slinton } else if (varsize == sizeof(short)) { 116716608Ssam svalue = lvalue; 116816608Ssam dwrite(&svalue, addr, sizeof(svalue)); 1169*18217Slinton } else { 1170*18217Slinton error("[internal error: bad size %d in assign]", varsize); 1171*18217Slinton } 1172*18217Slinton } else { 1173*18217Slinton if (expsize <= varsize) { 1174*18217Slinton sp -= expsize; 1175*18217Slinton dwrite(sp, addr, expsize); 1176*18217Slinton } else { 1177*18217Slinton sp -= expsize; 1178*18217Slinton dwrite(sp, addr, varsize); 1179*18217Slinton } 1180*18217Slinton } 1181*18217Slinton } 1182*18217Slinton } 1183*18217Slinton } 11849662Slinton 1185*18217Slinton /* 1186*18217Slinton * Set a debugger variable. 1187*18217Slinton */ 1188*18217Slinton 1189*18217Slinton private set (var, exp) 1190*18217Slinton Node var, exp; 1191*18217Slinton { 1192*18217Slinton Symbol t; 1193*18217Slinton 1194*18217Slinton if (var == nil) { 1195*18217Slinton defvar(nil, nil); 1196*18217Slinton } else if (exp == nil) { 1197*18217Slinton defvar(var->value.name, nil); 1198*18217Slinton } else if (var->value.name == identname("$frame", true)) { 1199*18217Slinton t = exp->nodetype; 1200*18217Slinton if (not compatible(t, t_int) and not compatible(t, t_addr)) { 1201*18217Slinton error("$frame must be an address"); 1202*18217Slinton } 1203*18217Slinton eval(exp); 1204*18217Slinton getnewregs(pop(Address)); 1205*18217Slinton } else { 1206*18217Slinton defvar(var->value.name, unrval(exp)); 1207*18217Slinton } 1208*18217Slinton } 1209*18217Slinton 1210*18217Slinton /* 1211*18217Slinton * Execute a list command. 1212*18217Slinton */ 1213*18217Slinton 1214*18217Slinton private list (p) 1215*18217Slinton Node p; 1216*18217Slinton { 1217*18217Slinton Symbol f; 1218*18217Slinton Address addr; 1219*18217Slinton Lineno line, l1, l2; 1220*18217Slinton 1221*18217Slinton if (p->value.arg[0]->op == O_SYM) { 1222*18217Slinton f = p->value.arg[0]->value.sym; 1223*18217Slinton addr = firstline(f); 1224*18217Slinton if (addr == NOADDR) { 1225*18217Slinton error("no source lines for \"%s\"", symname(f)); 1226*18217Slinton } 1227*18217Slinton setsource(srcfilename(addr)); 1228*18217Slinton line = srcline(addr); 1229*18217Slinton getsrcwindow(line, &l1, &l2); 1230*18217Slinton } else { 1231*18217Slinton eval(p->value.arg[0]); 1232*18217Slinton l1 = (Lineno) (pop(long)); 1233*18217Slinton eval(p->value.arg[1]); 1234*18217Slinton l2 = (Lineno) (pop(long)); 1235*18217Slinton } 1236*18217Slinton printlines(l1, l2); 1237*18217Slinton } 1238*18217Slinton 1239*18217Slinton /* 1240*18217Slinton * Execute a func command. 1241*18217Slinton */ 1242*18217Slinton 1243*18217Slinton private func (p) 1244*18217Slinton Node p; 1245*18217Slinton { 1246*18217Slinton Symbol s, f; 1247*18217Slinton Address addr; 1248*18217Slinton 1249*18217Slinton if (p == nil) { 1250*18217Slinton printname(stdout, curfunc); 1251*18217Slinton putchar('\n'); 1252*18217Slinton } else { 1253*18217Slinton s = p->value.sym; 1254*18217Slinton if (isroutine(s)) { 1255*18217Slinton setcurfunc(s); 125616608Ssam } else { 1257*18217Slinton find(f, s->name) where isroutine(f) endfind(f); 1258*18217Slinton if (f == nil) { 1259*18217Slinton error("%s is not a procedure or function", symname(s)); 126016608Ssam } 1261*18217Slinton setcurfunc(f); 12629662Slinton } 1263*18217Slinton addr = codeloc(curfunc); 1264*18217Slinton if (addr != NOADDR) { 1265*18217Slinton setsource(srcfilename(addr)); 1266*18217Slinton cursrcline = srcline(addr); 1267*18217Slinton } 12689662Slinton } 12699662Slinton } 12709662Slinton 12719662Slinton /* 1272*18217Slinton * Send a message to the current support person. 12739662Slinton */ 12749662Slinton 12759662Slinton public gripe() 12769662Slinton { 12779662Slinton typedef Operation(); 12789662Slinton Operation *old; 127914445Slinton int pid, status; 128016608Ssam extern int versionNumber; 128116608Ssam char subject[100]; 12829662Slinton 12839662Slinton puts("Type control-D to end your message. Be sure to include"); 12849662Slinton puts("your name and the name of the file you are debugging."); 12859662Slinton putchar('\n'); 12869662Slinton old = signal(SIGINT, SIG_DFL); 1287*18217Slinton sprintf(subject, "dbx (version 3.%d) gripe", versionNumber); 1288*18217Slinton pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil); 128914445Slinton signal(SIGINT, SIG_IGN); 129014445Slinton pwait(pid, &status); 12919662Slinton signal(SIGINT, old); 129214445Slinton if (status == 0) { 129314445Slinton puts("Thank you."); 129414445Slinton } else { 129514445Slinton puts("\nMail not sent."); 129614445Slinton } 12979662Slinton } 12989662Slinton 12999662Slinton /* 13009662Slinton * Give the user some help. 13019662Slinton */ 13029662Slinton 13039662Slinton public help() 13049662Slinton { 13059662Slinton puts("run - begin execution of the program"); 130616608Ssam puts("print <exp> - print the value of the expression"); 130716608Ssam puts("where - print currently active procedures"); 130816608Ssam puts("stop at <line> - suspend execution at the line"); 130916608Ssam puts("stop in <proc> - suspend execution when <proc> is called"); 13109662Slinton puts("cont - continue execution"); 13119662Slinton puts("step - single step one line"); 13129662Slinton puts("next - step to next line (skip over calls)"); 13139662Slinton puts("trace <line#> - trace execution of the line"); 13149662Slinton puts("trace <proc> - trace calls to the procedure"); 13159662Slinton puts("trace <var> - trace changes to the variable"); 13169662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 13179662Slinton puts("status - print trace/stop's in effect"); 13189662Slinton puts("delete <number> - remove trace or stop of given number"); 131916608Ssam puts("call <proc> - call a procedure in program"); 13209662Slinton puts("whatis <name> - print the declaration of the name"); 13219662Slinton puts("list <line>, <line> - list source lines"); 13229662Slinton puts("gripe - send mail to the person in charge of dbx"); 13239662Slinton puts("quit - exit dbx"); 13249662Slinton } 13259662Slinton 13269662Slinton /* 13279662Slinton * Divert output to the given file name. 13289662Slinton * Cannot redirect to an existing file. 13299662Slinton */ 13309662Slinton 13319662Slinton private int so_fd; 13329662Slinton private Boolean notstdout; 13339662Slinton 13349662Slinton public setout(filename) 13359662Slinton String filename; 13369662Slinton { 13379662Slinton File f; 13389662Slinton 13399662Slinton f = fopen(filename, "r"); 13409662Slinton if (f != nil) { 13419662Slinton fclose(f); 13429662Slinton error("%s: file already exists", filename); 13439662Slinton } else { 13449662Slinton so_fd = dup(1); 13459662Slinton close(1); 13469662Slinton if (creat(filename, 0666) == nil) { 13479662Slinton unsetout(); 13489662Slinton error("can't create %s", filename); 13499662Slinton } 13509662Slinton notstdout = true; 13519662Slinton } 13529662Slinton } 13539662Slinton 13549662Slinton /* 13559662Slinton * Revert output to standard output. 13569662Slinton */ 13579662Slinton 13589662Slinton public unsetout() 13599662Slinton { 13609662Slinton fflush(stdout); 13619662Slinton close(1); 13629662Slinton if (dup(so_fd) != 1) { 13639662Slinton panic("standard out dup failed"); 13649662Slinton } 13659662Slinton close(so_fd); 13669662Slinton notstdout = false; 13679662Slinton } 13689662Slinton 13699662Slinton /* 13709662Slinton * Determine is standard output is currently being redirected 13719662Slinton * to a file (as far as we know). 13729662Slinton */ 13739662Slinton 13749662Slinton public Boolean isredirected() 13759662Slinton { 13769662Slinton return notstdout; 13779662Slinton } 1378