1*21601Sdist /* 2*21601Sdist * Copyright (c) 1983 Regents of the University of California. 3*21601Sdist * All rights reserved. The Berkeley software License Agreement 4*21601Sdist * specifies the terms and conditions for redistribution. 5*21601Sdist */ 69662Slinton 7*21601Sdist #ifndef lint 8*21601Sdist static char sccsid[] = "@(#)eval.c 5.1 (Berkeley) 05/31/85"; 9*21601Sdist #endif not lint 109662Slinton 1118217Slinton static char rcsid[] = "$Header: eval.c,v 1.5 84/12/26 10:39:08 linton Exp $"; 1218217Slinton 139662Slinton /* 149662Slinton * Tree evaluation. 159662Slinton */ 169662Slinton 179662Slinton #include "defs.h" 189662Slinton #include "tree.h" 199662Slinton #include "operators.h" 2018217Slinton #include "debug.h" 219662Slinton #include "eval.h" 229662Slinton #include "events.h" 239662Slinton #include "symbols.h" 249662Slinton #include "scanner.h" 259662Slinton #include "source.h" 269662Slinton #include "object.h" 279662Slinton #include "mappings.h" 289662Slinton #include "process.h" 2916608Ssam #include "runtime.h" 309662Slinton #include "machine.h" 319662Slinton #include <signal.h> 329662Slinton 339662Slinton #ifndef public 349662Slinton 359662Slinton #include "machine.h" 369662Slinton 3712538Scsvaf #define STACKSIZE 20000 389662Slinton 399662Slinton typedef Char Stack; 409662Slinton 419662Slinton #define push(type, value) { \ 429662Slinton ((type *) (sp += sizeof(type)))[-1] = (value); \ 439662Slinton } 449662Slinton 459662Slinton #define pop(type) ( \ 469662Slinton (*((type *) (sp -= sizeof(type)))) \ 479662Slinton ) 489662Slinton 4916608Ssam #define popn(n, dest) { \ 5016608Ssam sp -= n; \ 5116608Ssam bcopy(sp, dest, n); \ 5216608Ssam } 5316608Ssam 549662Slinton #define alignstack() { \ 559662Slinton sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \ 569662Slinton } 579662Slinton 589662Slinton #endif 599662Slinton 609662Slinton public Stack stack[STACKSIZE]; 619662Slinton public Stack *sp = &stack[0]; 6214674Slinton public Boolean useInstLoc = false; 639662Slinton 649662Slinton #define chksp() \ 659662Slinton { \ 669662Slinton if (sp < &stack[0]) { \ 679662Slinton panic("stack underflow"); \ 689662Slinton } \ 699662Slinton } 709662Slinton 719662Slinton #define poparg(n, r, fr) { \ 729662Slinton eval(p->value.arg[n]); \ 739662Slinton if (isreal(p->op)) { \ 7416608Ssam if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \ 7516608Ssam fr = pop(float); \ 7616608Ssam } else { \ 7716608Ssam fr = pop(double); \ 7816608Ssam } \ 799662Slinton } else if (isint(p->op)) { \ 809662Slinton r = popsmall(p->value.arg[n]->nodetype); \ 819662Slinton } \ 829662Slinton } 839662Slinton 849662Slinton #define Boolrep char /* underlying representation type for booleans */ 859662Slinton 869662Slinton /* 8718217Slinton * Command-level evaluation. 8818217Slinton */ 8918217Slinton 9018217Slinton public Node topnode; 9118217Slinton 9218217Slinton public topeval (p) 9318217Slinton Node p; 9418217Slinton { 9518217Slinton if (traceeval) { 9618217Slinton fprintf(stderr, "topeval("); 9718217Slinton prtree(stderr, p); 9818217Slinton fprintf(stderr, ")\n"); 9918217Slinton fflush(stderr); 10018217Slinton } 10118217Slinton topnode = p; 10218217Slinton eval(p); 10318217Slinton } 10418217Slinton 10518217Slinton /* 1069662Slinton * Evaluate a parse tree leaving the value on the top of the stack. 1079662Slinton */ 1089662Slinton 1099662Slinton public eval(p) 1109662Slinton register Node p; 1119662Slinton { 1129662Slinton long r0, r1; 1139662Slinton double fr0, fr1; 1149662Slinton Address addr; 1159662Slinton long i, n; 1169662Slinton int len; 11718217Slinton Symbol s; 1189662Slinton Node n1, n2; 11918217Slinton boolean b; 1209662Slinton File file; 12118217Slinton String str; 1229662Slinton 1239662Slinton checkref(p); 12418217Slinton if (traceeval) { 12518217Slinton fprintf(stderr, "begin eval %s\n", opname(p->op)); 12612538Scsvaf } 1279662Slinton switch (degree(p->op)) { 1289662Slinton case BINARY: 1299662Slinton poparg(1, r1, fr1); 1309662Slinton poparg(0, r0, fr0); 1319662Slinton break; 1329662Slinton 1339662Slinton case UNARY: 1349662Slinton poparg(0, r0, fr0); 1359662Slinton break; 1369662Slinton 1379662Slinton default: 1389662Slinton /* do nothing */; 1399662Slinton } 1409662Slinton switch (p->op) { 1419662Slinton case O_SYM: 1429662Slinton s = p->value.sym; 1439662Slinton if (s == retaddrsym) { 1449662Slinton push(long, return_addr()); 14518217Slinton } else if (isvariable(s)) { 14618217Slinton if (s != program and not isactive(container(s))) { 14718217Slinton error("\"%s\" is not active", symname(s)); 14818217Slinton } 14918217Slinton if (isvarparam(s) and not isopenarray(s)) { 15018217Slinton rpush(address(s, nil), sizeof(Address)); 1519662Slinton } else { 15218217Slinton push(Address, address(s, nil)); 1539662Slinton } 15418217Slinton } else if (isblock(s)) { 15518217Slinton push(Symbol, s); 15618217Slinton } else if (isconst(s)) { 15718217Slinton eval(constval(s)); 15818217Slinton } else { 15918217Slinton error("can't evaluate a %s", classname(s)); 1609662Slinton } 1619662Slinton break; 1629662Slinton 1639662Slinton case O_LCON: 16418217Slinton case O_CCON: 1659662Slinton r0 = p->value.lcon; 1669662Slinton pushsmall(p->nodetype, r0); 1679662Slinton break; 1689662Slinton 1699662Slinton case O_FCON: 1709662Slinton push(double, p->value.fcon); 1719662Slinton break; 1729662Slinton 1739662Slinton case O_SCON: 1749662Slinton len = size(p->nodetype); 1759662Slinton mov(p->value.scon, sp, len); 1769662Slinton sp += len; 1779662Slinton break; 1789662Slinton 1799662Slinton case O_INDEX: 18018217Slinton s = p->value.arg[0]->nodetype; 18118217Slinton p->value.arg[0]->nodetype = t_addr; 18218217Slinton eval(p->value.arg[0]); 18318217Slinton p->value.arg[0]->nodetype = s; 18418217Slinton n = pop(Address); 18518217Slinton eval(p->value.arg[1]); 18618217Slinton evalindex(s, n, popsmall(p->value.arg[1]->nodetype)); 1879662Slinton break; 1889662Slinton 1899662Slinton case O_DOT: 1909662Slinton s = p->value.arg[1]->value.sym; 19118217Slinton eval(p->value.arg[0]); 19218217Slinton n = pop(long); 1939662Slinton push(long, n + (s->symvalue.field.offset div 8)); 1949662Slinton break; 1959662Slinton 1969662Slinton /* 1979662Slinton * Get the value of the expression addressed by the top of the stack. 1989662Slinton * Push the result back on the stack. 1999662Slinton */ 2009662Slinton 2019662Slinton case O_INDIR: 2029662Slinton case O_RVAL: 2039662Slinton addr = pop(long); 2049662Slinton if (addr == 0) { 2059662Slinton error("reference through nil pointer"); 2069662Slinton } 20718217Slinton len = size(p->nodetype); 2089662Slinton rpush(addr, len); 2099662Slinton break; 2109662Slinton 21111175Slinton /* 21218217Slinton * Move the stack pointer so that the top of the stack has 21318217Slinton * something corresponding to the size of the current node type. 21418217Slinton * If this new type is bigger than the subtree (len > 0), 21518217Slinton * then the stack is padded with nulls. If it's smaller, 21618217Slinton * the stack is just dropped by the appropriate amount. 21711175Slinton */ 21811175Slinton case O_TYPERENAME: 21918217Slinton len = size(p->nodetype) - size(p->value.arg[0]->nodetype); 22018217Slinton if (len > 0) { 22118217Slinton for (n = 0; n < len; n++) { 22218217Slinton *sp++ = '\0'; 22318217Slinton } 22418217Slinton } else if (len < 0) { 22518217Slinton sp += len; 22618217Slinton } 22711175Slinton break; 22811175Slinton 2299662Slinton case O_COMMA: 23018217Slinton eval(p->value.arg[0]); 23118217Slinton if (p->value.arg[1] != nil) { 23218217Slinton eval(p->value.arg[1]); 23318217Slinton } 2349662Slinton break; 2359662Slinton 2369662Slinton case O_ITOF: 2379662Slinton push(double, (double) r0); 2389662Slinton break; 2399662Slinton 2409662Slinton case O_ADD: 2419662Slinton push(long, r0+r1); 2429662Slinton break; 2439662Slinton 2449662Slinton case O_ADDF: 2459662Slinton push(double, fr0+fr1); 2469662Slinton break; 2479662Slinton 2489662Slinton case O_SUB: 2499662Slinton push(long, r0-r1); 2509662Slinton break; 2519662Slinton 2529662Slinton case O_SUBF: 2539662Slinton push(double, fr0-fr1); 2549662Slinton break; 2559662Slinton 2569662Slinton case O_NEG: 2579662Slinton push(long, -r0); 2589662Slinton break; 2599662Slinton 2609662Slinton case O_NEGF: 2619662Slinton push(double, -fr0); 2629662Slinton break; 2639662Slinton 2649662Slinton case O_MUL: 2659662Slinton push(long, r0*r1); 2669662Slinton break; 2679662Slinton 2689662Slinton case O_MULF: 2699662Slinton push(double, fr0*fr1); 2709662Slinton break; 2719662Slinton 2729662Slinton case O_DIVF: 2739662Slinton if (fr1 == 0) { 2749662Slinton error("error: division by 0"); 2759662Slinton } 2769662Slinton push(double, fr0 / fr1); 2779662Slinton break; 2789662Slinton 2799662Slinton case O_DIV: 2809662Slinton if (r1 == 0) { 2819662Slinton error("error: div by 0"); 2829662Slinton } 2839662Slinton push(long, r0 div r1); 2849662Slinton break; 2859662Slinton 2869662Slinton case O_MOD: 2879662Slinton if (r1 == 0) { 2889662Slinton error("error: mod by 0"); 2899662Slinton } 2909662Slinton push(long, r0 mod r1); 2919662Slinton break; 2929662Slinton 2939662Slinton case O_LT: 2949662Slinton push(Boolrep, r0 < r1); 2959662Slinton break; 2969662Slinton 2979662Slinton case O_LTF: 2989662Slinton push(Boolrep, fr0 < fr1); 2999662Slinton break; 3009662Slinton 3019662Slinton case O_LE: 3029662Slinton push(Boolrep, r0 <= r1); 3039662Slinton break; 3049662Slinton 3059662Slinton case O_LEF: 3069662Slinton push(Boolrep, fr0 <= fr1); 3079662Slinton break; 3089662Slinton 3099662Slinton case O_GT: 3109662Slinton push(Boolrep, r0 > r1); 3119662Slinton break; 3129662Slinton 3139662Slinton case O_GTF: 3149662Slinton push(Boolrep, fr0 > fr1); 3159662Slinton break; 3169662Slinton 3179662Slinton case O_EQ: 3189662Slinton push(Boolrep, r0 == r1); 3199662Slinton break; 3209662Slinton 3219662Slinton case O_EQF: 3229662Slinton push(Boolrep, fr0 == fr1); 3239662Slinton break; 3249662Slinton 3259662Slinton case O_NE: 3269662Slinton push(Boolrep, r0 != r1); 3279662Slinton break; 3289662Slinton 3299662Slinton case O_NEF: 3309662Slinton push(Boolrep, fr0 != fr1); 3319662Slinton break; 3329662Slinton 3339662Slinton case O_AND: 3349662Slinton push(Boolrep, r0 and r1); 3359662Slinton break; 3369662Slinton 3379662Slinton case O_OR: 3389662Slinton push(Boolrep, r0 or r1); 3399662Slinton break; 3409662Slinton 3419662Slinton case O_ASSIGN: 3429662Slinton assign(p->value.arg[0], p->value.arg[1]); 3439662Slinton break; 3449662Slinton 3459662Slinton case O_CHFILE: 3469662Slinton if (p->value.scon == nil) { 3479662Slinton printf("%s\n", cursource); 3489662Slinton } else { 3499662Slinton file = opensource(p->value.scon); 3509662Slinton if (file == nil) { 3519662Slinton error("can't read \"%s\"", p->value.scon); 3529662Slinton } else { 3539662Slinton fclose(file); 3549662Slinton setsource(p->value.scon); 3559662Slinton } 3569662Slinton } 3579662Slinton break; 3589662Slinton 3599662Slinton case O_CONT: 36011871Slinton cont(p->value.lcon); 3619662Slinton printnews(); 3629662Slinton break; 3639662Slinton 3649662Slinton case O_LIST: 36518217Slinton list(p); 3669662Slinton break; 3679662Slinton 3689662Slinton case O_FUNC: 36918217Slinton func(p->value.arg[0]); 3709662Slinton break; 3719662Slinton 3729662Slinton case O_EXAMINE: 3739662Slinton eval(p->value.examine.beginaddr); 3749662Slinton r0 = pop(long); 3759662Slinton if (p->value.examine.endaddr == nil) { 3769662Slinton n = p->value.examine.count; 37711175Slinton if (n == 0) { 37811175Slinton printvalue(r0, p->value.examine.mode); 37911175Slinton } else if (streq(p->value.examine.mode, "i")) { 3809662Slinton printninst(n, (Address) r0); 3819662Slinton } else { 3829662Slinton printndata(n, (Address) r0, p->value.examine.mode); 3839662Slinton } 3849662Slinton } else { 3859662Slinton eval(p->value.examine.endaddr); 3869662Slinton r1 = pop(long); 3879662Slinton if (streq(p->value.examine.mode, "i")) { 3889662Slinton printinst((Address)r0, (Address)r1); 3899662Slinton } else { 3909662Slinton printdata((Address)r0, (Address)r1, p->value.examine.mode); 3919662Slinton } 3929662Slinton } 3939662Slinton break; 3949662Slinton 3959662Slinton case O_PRINT: 3969662Slinton for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) { 3979662Slinton eval(n1->value.arg[0]); 3989662Slinton printval(n1->value.arg[0]->nodetype); 3999662Slinton putchar(' '); 4009662Slinton } 4019662Slinton putchar('\n'); 4029662Slinton break; 4039662Slinton 4049662Slinton case O_PSYM: 4059662Slinton if (p->value.arg[0]->op == O_SYM) { 4069662Slinton psym(p->value.arg[0]->value.sym); 4079662Slinton } else { 4089662Slinton psym(p->value.arg[0]->nodetype); 4099662Slinton } 4109662Slinton break; 4119662Slinton 4129662Slinton case O_QLINE: 4139662Slinton eval(p->value.arg[1]); 4149662Slinton break; 4159662Slinton 4169662Slinton case O_STEP: 4179662Slinton b = inst_tracing; 4189662Slinton inst_tracing = (Boolean) (not p->value.step.source); 4199662Slinton if (p->value.step.skipcalls) { 4209662Slinton next(); 4219662Slinton } else { 4229662Slinton stepc(); 4239662Slinton } 4249662Slinton inst_tracing = b; 42514674Slinton useInstLoc = (Boolean) (not p->value.step.source); 4269662Slinton printnews(); 4279662Slinton break; 4289662Slinton 4299662Slinton case O_WHATIS: 4309662Slinton if (p->value.arg[0]->op == O_SYM) { 4319662Slinton printdecl(p->value.arg[0]->value.sym); 4329662Slinton } else { 4339662Slinton printdecl(p->value.arg[0]->nodetype); 4349662Slinton } 4359662Slinton break; 4369662Slinton 4379662Slinton case O_WHERE: 4389662Slinton wherecmd(); 4399662Slinton break; 4409662Slinton 4419662Slinton case O_WHEREIS: 44212538Scsvaf if (p->value.arg[0]->op == O_SYM) { 44318217Slinton printwhereis(stdout, p->value.arg[0]->value.sym); 44412538Scsvaf } else { 44518217Slinton printwhereis(stdout, p->value.arg[0]->nodetype); 44612538Scsvaf } 4479662Slinton break; 4489662Slinton 4499662Slinton case O_WHICH: 45012538Scsvaf if (p->value.arg[0]->op == O_SYM) { 45118217Slinton printwhich(stdout, p->value.arg[0]->value.sym); 45212538Scsvaf } else { 45318217Slinton printwhich(stdout, p->value.arg[0]->nodetype); 45412538Scsvaf } 4559662Slinton putchar('\n'); 4569662Slinton break; 4579662Slinton 4589662Slinton case O_ALIAS: 4599662Slinton n1 = p->value.arg[0]; 4609662Slinton n2 = p->value.arg[1]; 46118217Slinton if (n2 == nil) { 46218217Slinton if (n1 == nil) { 46318217Slinton alias(nil, nil, nil); 46418217Slinton } else { 46518217Slinton alias(n1->value.name, nil, nil); 46618217Slinton } 46718217Slinton } else if (n2->op == O_NAME) { 46818217Slinton str = ident(n2->value.name); 46918217Slinton alias(n1->value.name, nil, strdup(str)); 4709662Slinton } else { 47118217Slinton if (n1->op == O_COMMA) { 47218217Slinton alias( 47318217Slinton n1->value.arg[0]->value.name, 47418217Slinton (List) n1->value.arg[1], 47518217Slinton n2->value.scon 47618217Slinton ); 47718217Slinton } else { 47818217Slinton alias(n1->value.name, nil, n2->value.scon); 47918217Slinton } 4809662Slinton } 4819662Slinton break; 4829662Slinton 48318217Slinton case O_UNALIAS: 48418217Slinton unalias(p->value.arg[0]->value.name); 48518217Slinton break; 48618217Slinton 48718217Slinton case O_CALLPROC: 48818217Slinton callproc(p, false); 48918217Slinton break; 49018217Slinton 4919662Slinton case O_CALL: 49218217Slinton callproc(p, true); 4939662Slinton break; 4949662Slinton 4959662Slinton case O_CATCH: 49618217Slinton if (p->value.lcon == 0) { 49718217Slinton printsigscaught(process); 49818217Slinton } else { 49918217Slinton psigtrace(process, p->value.lcon, true); 50018217Slinton } 5019662Slinton break; 5029662Slinton 5039662Slinton case O_EDIT: 5049662Slinton edit(p->value.scon); 5059662Slinton break; 5069662Slinton 50712538Scsvaf case O_DEBUG: 50812538Scsvaf debug(p); 50912538Scsvaf break; 51012538Scsvaf 51116608Ssam case O_DOWN: 51216608Ssam checkref(p->value.arg[0]); 51316608Ssam assert(p->value.arg[0]->op == O_LCON); 51416608Ssam down(p->value.arg[0]->value.lcon); 51516608Ssam break; 51616608Ssam 5179662Slinton case O_DUMP: 51818217Slinton if (p->value.arg[0] == nil) { 51918217Slinton dumpall(); 52018217Slinton } else { 52118217Slinton s = p->value.arg[0]->value.sym; 52218217Slinton if (s == curfunc) { 52318217Slinton dump(nil); 52418217Slinton } else { 52518217Slinton dump(s); 52618217Slinton } 52718217Slinton } 5289662Slinton break; 5299662Slinton 5309662Slinton case O_GRIPE: 5319662Slinton gripe(); 5329662Slinton break; 5339662Slinton 5349662Slinton case O_HELP: 5359662Slinton help(); 5369662Slinton break; 5379662Slinton 5389662Slinton case O_IGNORE: 53918217Slinton if (p->value.lcon == 0) { 54018217Slinton printsigsignored(process); 54118217Slinton } else { 54218217Slinton psigtrace(process, p->value.lcon, false); 54318217Slinton } 5449662Slinton break; 5459662Slinton 54616608Ssam case O_RETURN: 54716608Ssam if (p->value.arg[0] == nil) { 54816608Ssam rtnfunc(nil); 54916608Ssam } else { 55016608Ssam assert(p->value.arg[0]->op == O_SYM); 55116608Ssam rtnfunc(p->value.arg[0]->value.sym); 55216608Ssam } 55316608Ssam break; 55416608Ssam 5559662Slinton case O_RUN: 5569662Slinton run(); 5579662Slinton break; 5589662Slinton 55918217Slinton case O_SET: 56018217Slinton set(p->value.arg[0], p->value.arg[1]); 56118217Slinton break; 56218217Slinton 56318217Slinton case O_SEARCH: 56418217Slinton search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon); 56518217Slinton break; 56618217Slinton 5679662Slinton case O_SOURCE: 5689662Slinton setinput(p->value.scon); 5699662Slinton break; 5709662Slinton 5719662Slinton case O_STATUS: 5729662Slinton status(); 5739662Slinton break; 5749662Slinton 5759662Slinton case O_TRACE: 5769662Slinton case O_TRACEI: 5779662Slinton trace(p); 5789662Slinton break; 5799662Slinton 5809662Slinton case O_STOP: 5819662Slinton case O_STOPI: 5829662Slinton stop(p); 5839662Slinton break; 5849662Slinton 58518217Slinton case O_UNSET: 58618217Slinton undefvar(p->value.arg[0]->value.name); 58718217Slinton break; 58818217Slinton 58916608Ssam case O_UP: 59016608Ssam checkref(p->value.arg[0]); 59116608Ssam assert(p->value.arg[0]->op == O_LCON); 59216608Ssam up(p->value.arg[0]->value.lcon); 59316608Ssam break; 59416608Ssam 5959662Slinton case O_ADDEVENT: 5969662Slinton addevent(p->value.event.cond, p->value.event.actions); 5979662Slinton break; 5989662Slinton 5999662Slinton case O_DELETE: 60016608Ssam n1 = p->value.arg[0]; 60116608Ssam while (n1->op == O_COMMA) { 60216608Ssam n2 = n1->value.arg[0]; 60316608Ssam assert(n2->op == O_LCON); 60416608Ssam if (not delevent((unsigned int) n2->value.lcon)) { 60516608Ssam error("unknown event %ld", n2->value.lcon); 60616608Ssam } 60716608Ssam n1 = n1->value.arg[1]; 60816608Ssam } 60916608Ssam assert(n1->op == O_LCON); 61016608Ssam if (not delevent((unsigned int) n1->value.lcon)) { 61116608Ssam error("unknown event %ld", n1->value.lcon); 61216608Ssam } 6139662Slinton break; 6149662Slinton 6159662Slinton case O_ENDX: 6169662Slinton endprogram(); 6179662Slinton break; 6189662Slinton 6199662Slinton case O_IF: 6209662Slinton if (cond(p->value.event.cond)) { 6219662Slinton evalcmdlist(p->value.event.actions); 6229662Slinton } 6239662Slinton break; 6249662Slinton 6259662Slinton case O_ONCE: 6269662Slinton event_once(p->value.event.cond, p->value.event.actions); 6279662Slinton break; 6289662Slinton 6299662Slinton case O_PRINTCALL: 6309662Slinton printcall(p->value.sym, whatblock(return_addr())); 6319662Slinton break; 6329662Slinton 6339662Slinton case O_PRINTIFCHANGED: 6349662Slinton printifchanged(p->value.arg[0]); 6359662Slinton break; 6369662Slinton 6379662Slinton case O_PRINTRTN: 6389662Slinton printrtn(p->value.sym); 6399662Slinton break; 6409662Slinton 6419662Slinton case O_PRINTSRCPOS: 6429662Slinton getsrcpos(); 6439662Slinton if (p->value.arg[0] == nil) { 6449662Slinton printsrcpos(); 6459662Slinton putchar('\n'); 6469662Slinton printlines(curline, curline); 6479662Slinton } else if (p->value.arg[0]->op == O_QLINE) { 6489662Slinton if (p->value.arg[0]->value.arg[1]->value.lcon == 0) { 6499662Slinton printf("tracei: "); 6509662Slinton printinst(pc, pc); 6519662Slinton } else { 65218217Slinton if (canReadSource()) { 65318217Slinton printf("trace: "); 65418217Slinton printlines(curline, curline); 65518217Slinton } 6569662Slinton } 6579662Slinton } else { 6589662Slinton printsrcpos(); 6599662Slinton printf(": "); 6609662Slinton eval(p->value.arg[0]); 6619662Slinton prtree(stdout, p->value.arg[0]); 6629662Slinton printf(" = "); 6639662Slinton printval(p->value.arg[0]->nodetype); 6649662Slinton putchar('\n'); 6659662Slinton } 6669662Slinton break; 6679662Slinton 6689662Slinton case O_PROCRTN: 6699662Slinton procreturn(p->value.sym); 6709662Slinton break; 6719662Slinton 6729662Slinton case O_STOPIFCHANGED: 6739662Slinton stopifchanged(p->value.arg[0]); 6749662Slinton break; 6759662Slinton 6769662Slinton case O_STOPX: 6779662Slinton isstopped = true; 6789662Slinton break; 6799662Slinton 6809662Slinton case O_TRACEON: 6819662Slinton traceon(p->value.trace.inst, p->value.trace.event, 6829662Slinton p->value.trace.actions); 6839662Slinton break; 6849662Slinton 6859662Slinton case O_TRACEOFF: 6869662Slinton traceoff(p->value.lcon); 6879662Slinton break; 6889662Slinton 6899662Slinton default: 6909662Slinton panic("eval: bad op %d", p->op); 6919662Slinton } 69218217Slinton if (traceeval) { 69318217Slinton fprintf(stderr, "end eval %s\n", opname(p->op)); 69418217Slinton } 6959662Slinton } 6969662Slinton 6979662Slinton /* 6989662Slinton * Evaluate a list of commands. 6999662Slinton */ 7009662Slinton 7019662Slinton public evalcmdlist(cl) 7029662Slinton Cmdlist cl; 7039662Slinton { 7049662Slinton Command c; 7059662Slinton 7069662Slinton foreach (Command, c, cl) 7079662Slinton evalcmd(c); 7089662Slinton endfor 7099662Slinton } 7109662Slinton 7119662Slinton /* 7129662Slinton * Push "len" bytes onto the expression stack from address "addr" 7139662Slinton * in the process. If there isn't room on the stack, print an error message. 7149662Slinton */ 7159662Slinton 7169662Slinton public rpush(addr, len) 7179662Slinton Address addr; 7189662Slinton int len; 7199662Slinton { 7209662Slinton if (not canpush(len)) { 7219662Slinton error("expression too large to evaluate"); 7229662Slinton } else { 7239662Slinton chksp(); 7249662Slinton dread(sp, addr, len); 7259662Slinton sp += len; 7269662Slinton } 7279662Slinton } 7289662Slinton 7299662Slinton /* 7309662Slinton * Check if the stack has n bytes available. 7319662Slinton */ 7329662Slinton 7339662Slinton public Boolean canpush(n) 7349662Slinton Integer n; 7359662Slinton { 7369662Slinton return (Boolean) (sp + n < &stack[STACKSIZE]); 7379662Slinton } 7389662Slinton 7399662Slinton /* 7409662Slinton * Push a small scalar of the given type onto the stack. 7419662Slinton */ 7429662Slinton 7439662Slinton public pushsmall(t, v) 7449662Slinton Symbol t; 7459662Slinton long v; 7469662Slinton { 7479662Slinton register Integer s; 7489662Slinton 7499662Slinton s = size(t); 7509662Slinton switch (s) { 7519662Slinton case sizeof(char): 7529662Slinton push(char, v); 7539662Slinton break; 7549662Slinton 7559662Slinton case sizeof(short): 7569662Slinton push(short, v); 7579662Slinton break; 7589662Slinton 7599662Slinton case sizeof(long): 7609662Slinton push(long, v); 7619662Slinton break; 7629662Slinton 7639662Slinton default: 7649662Slinton panic("bad size %d in popsmall", s); 7659662Slinton } 7669662Slinton } 7679662Slinton 7689662Slinton /* 7699662Slinton * Pop an item of the given type which is assumed to be no larger 7709662Slinton * than a long and return it expanded into a long. 7719662Slinton */ 7729662Slinton 7739662Slinton public long popsmall(t) 7749662Slinton Symbol t; 7759662Slinton { 77618217Slinton register integer n; 7779662Slinton long r; 7789662Slinton 77918217Slinton n = size(t); 78018217Slinton if (n == sizeof(char)) { 78118217Slinton if (t->class == RANGE and t->symvalue.rangev.lower >= 0) { 78218217Slinton r = (long) pop(unsigned char); 78318217Slinton } else { 7849662Slinton r = (long) pop(char); 78518217Slinton } 78618217Slinton } else if (n == sizeof(short)) { 78718217Slinton if (t->class == RANGE and t->symvalue.rangev.lower >= 0) { 78818217Slinton r = (long) pop(unsigned short); 78918217Slinton } else { 7909662Slinton r = (long) pop(short); 79118217Slinton } 79218217Slinton } else if (n == sizeof(long)) { 79318217Slinton r = pop(long); 79418217Slinton } else { 79518217Slinton error("[internal error: size %d in popsmall]", n); 7969662Slinton } 7979662Slinton return r; 7989662Slinton } 7999662Slinton 8009662Slinton /* 8019662Slinton * Evaluate a conditional expression. 8029662Slinton */ 8039662Slinton 8049662Slinton public Boolean cond(p) 8059662Slinton Node p; 8069662Slinton { 8079662Slinton register Boolean b; 8089662Slinton 8099662Slinton if (p == nil) { 8109662Slinton b = true; 8119662Slinton } else { 8129662Slinton eval(p); 81313846Slinton b = (Boolean) pop(Boolrep); 8149662Slinton } 8159662Slinton return b; 8169662Slinton } 8179662Slinton 8189662Slinton /* 8199662Slinton * Return the address corresponding to a given tree. 8209662Slinton */ 8219662Slinton 8229662Slinton public Address lval(p) 8239662Slinton Node p; 8249662Slinton { 8259662Slinton if (p->op == O_RVAL) { 8269662Slinton eval(p->value.arg[0]); 8279662Slinton } else { 8289662Slinton eval(p); 8299662Slinton } 8309662Slinton return (Address) (pop(long)); 8319662Slinton } 8329662Slinton 8339662Slinton /* 8349662Slinton * Process a trace command, translating into the appropriate events 8359662Slinton * and associated actions. 8369662Slinton */ 8379662Slinton 8389662Slinton public trace(p) 8399662Slinton Node p; 8409662Slinton { 8419662Slinton Node exp, place, cond; 8429662Slinton Node left; 8439662Slinton 8449662Slinton exp = p->value.arg[0]; 8459662Slinton place = p->value.arg[1]; 8469662Slinton cond = p->value.arg[2]; 8479662Slinton if (exp == nil) { 8489662Slinton traceall(p->op, place, cond); 84911771Slinton } else if (exp->op == O_QLINE or exp->op == O_LCON) { 8509662Slinton traceinst(p->op, exp, cond); 8519662Slinton } else if (place != nil and place->op == O_QLINE) { 8529662Slinton traceat(p->op, exp, place, cond); 8539662Slinton } else { 8549861Slinton left = exp; 8559861Slinton if (left->op == O_RVAL or left->op == O_CALL) { 8569861Slinton left = left->value.arg[0]; 8579861Slinton } 8589662Slinton if (left->op == O_SYM and isblock(left->value.sym)) { 8599662Slinton traceproc(p->op, left->value.sym, place, cond); 8609662Slinton } else { 8619662Slinton tracedata(p->op, exp, place, cond); 8629662Slinton } 8639662Slinton } 8649662Slinton } 8659662Slinton 8669662Slinton /* 8679662Slinton * Set a breakpoint that will turn on tracing. 8689662Slinton */ 8699662Slinton 8709662Slinton private traceall(op, place, cond) 8719662Slinton Operator op; 8729662Slinton Node place; 8739662Slinton Node cond; 8749662Slinton { 8759662Slinton Symbol s; 8769662Slinton Node event; 8779662Slinton Command action; 8789662Slinton 8799662Slinton if (place == nil) { 8809662Slinton s = program; 8819662Slinton } else { 8829662Slinton s = place->value.sym; 8839662Slinton } 8849662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 8859662Slinton action = build(O_PRINTSRCPOS, 8869662Slinton build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0))); 8879662Slinton if (cond != nil) { 8889662Slinton action = build(O_IF, cond, buildcmdlist(action)); 8899662Slinton } 8909662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 8919662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 89211871Slinton if (isstdin()) { 89311871Slinton printevent(action->value.trace.event); 89411871Slinton } 8959662Slinton } 8969662Slinton 8979662Slinton /* 8989662Slinton * Set up the appropriate breakpoint for tracing an instruction. 8999662Slinton */ 9009662Slinton 9019662Slinton private traceinst(op, exp, cond) 9029662Slinton Operator op; 9039662Slinton Node exp; 9049662Slinton Node cond; 9059662Slinton { 90611771Slinton Node event, wh; 9079662Slinton Command action; 90811871Slinton Event e; 9099662Slinton 91011771Slinton if (exp->op == O_LCON) { 91118217Slinton wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp); 91211771Slinton } else { 91311771Slinton wh = exp; 91411771Slinton } 9159662Slinton if (op == O_TRACEI) { 91611771Slinton event = build(O_EQ, build(O_SYM, pcsym), wh); 9179662Slinton } else { 91811771Slinton event = build(O_EQ, build(O_SYM, linesym), wh); 9199662Slinton } 92011771Slinton action = build(O_PRINTSRCPOS, wh); 9219662Slinton if (cond) { 9229662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9239662Slinton } 92411871Slinton e = addevent(event, buildcmdlist(action)); 92511871Slinton if (isstdin()) { 92611871Slinton printevent(e); 92711871Slinton } 9289662Slinton } 9299662Slinton 9309662Slinton /* 9319662Slinton * Set a breakpoint to print an expression at a given line or address. 9329662Slinton */ 9339662Slinton 9349662Slinton private traceat(op, exp, place, cond) 9359662Slinton Operator op; 9369662Slinton Node exp; 9379662Slinton Node place; 9389662Slinton Node cond; 9399662Slinton { 9409662Slinton Node event; 9419662Slinton Command action; 94211871Slinton Event e; 9439662Slinton 9449662Slinton if (op == O_TRACEI) { 9459662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 9469662Slinton } else { 9479662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 9489662Slinton } 9499662Slinton action = build(O_PRINTSRCPOS, exp); 9509662Slinton if (cond != nil) { 9519662Slinton action = build(O_IF, cond, buildcmdlist(action)); 9529662Slinton } 95311871Slinton e = addevent(event, buildcmdlist(action)); 95411871Slinton if (isstdin()) { 95511871Slinton printevent(e); 95611871Slinton } 9579662Slinton } 9589662Slinton 9599662Slinton /* 9609662Slinton * Construct event for tracing a procedure. 9619662Slinton * 9629662Slinton * What we want here is 9639662Slinton * 9649662Slinton * when $proc = p do 9659662Slinton * if <condition> then 9669662Slinton * printcall; 9679662Slinton * once $pc = $retaddr do 9689662Slinton * printrtn; 9699662Slinton * end; 9709662Slinton * end if; 9719662Slinton * end; 9729662Slinton * 9739662Slinton * Note that "once" is like "when" except that the event 9749662Slinton * deletes itself as part of its associated action. 9759662Slinton */ 9769662Slinton 9779662Slinton private traceproc(op, p, place, cond) 9789662Slinton Operator op; 9799662Slinton Symbol p; 9809662Slinton Node place; 9819662Slinton Node cond; 9829662Slinton { 9839662Slinton Node event; 9849662Slinton Command action; 9859662Slinton Cmdlist actionlist; 98611871Slinton Event e; 9879662Slinton 9889662Slinton action = build(O_PRINTCALL, p); 9899662Slinton actionlist = list_alloc(); 9909662Slinton cmdlist_append(action, actionlist); 9919662Slinton event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)); 9929662Slinton action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p))); 9939662Slinton cmdlist_append(action, actionlist); 9949662Slinton if (cond != nil) { 9959662Slinton actionlist = buildcmdlist(build(O_IF, cond, actionlist)); 9969662Slinton } 9979662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 99811871Slinton e = addevent(event, actionlist); 99911871Slinton if (isstdin()) { 100011871Slinton printevent(e); 100111871Slinton } 10029662Slinton } 10039662Slinton 10049662Slinton /* 10059662Slinton * Set up breakpoint for tracing data. 10069662Slinton */ 10079662Slinton 10089662Slinton private tracedata(op, exp, place, cond) 10099662Slinton Operator op; 10109662Slinton Node exp; 10119662Slinton Node place; 10129662Slinton Node cond; 10139662Slinton { 10149662Slinton Symbol p; 10159662Slinton Node event; 10169662Slinton Command action; 10179662Slinton 10189662Slinton p = (place == nil) ? tcontainer(exp) : place->value.sym; 10199662Slinton if (p == nil) { 10209662Slinton p = program; 10219662Slinton } 10229662Slinton action = build(O_PRINTIFCHANGED, exp); 10239662Slinton if (cond != nil) { 10249662Slinton action = build(O_IF, cond, buildcmdlist(action)); 10259662Slinton } 10269662Slinton action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action)); 10279662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 10289662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 102911871Slinton if (isstdin()) { 103011871Slinton printevent(action->value.trace.event); 103111871Slinton } 10329662Slinton } 10339662Slinton 10349662Slinton /* 10359662Slinton * Setting and unsetting of stops. 10369662Slinton */ 10379662Slinton 10389662Slinton public stop(p) 10399662Slinton Node p; 10409662Slinton { 104113846Slinton Node exp, place, cond, t; 10429662Slinton Symbol s; 10439662Slinton Command action; 104411871Slinton Event e; 10459662Slinton 10469662Slinton exp = p->value.arg[0]; 10479662Slinton place = p->value.arg[1]; 10489662Slinton cond = p->value.arg[2]; 10499662Slinton if (exp != nil) { 10509662Slinton stopvar(p->op, exp, place, cond); 105113846Slinton } else { 105213846Slinton action = build(O_STOPX); 105313846Slinton if (cond != nil) { 105413846Slinton action = build(O_IF, cond, buildcmdlist(action)); 105511871Slinton } 105616608Ssam if (place == nil or place->op == O_SYM) { 105716608Ssam if (place == nil) { 105816608Ssam s = program; 105916608Ssam } else { 106016608Ssam s = place->value.sym; 106116608Ssam } 106213846Slinton t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s)); 106313846Slinton if (cond != nil) { 106413846Slinton action = build(O_TRACEON, (p->op == O_STOPI), 106513846Slinton buildcmdlist(action)); 106613846Slinton e = addevent(t, buildcmdlist(action)); 106713846Slinton action->value.trace.event = e; 106813846Slinton } else { 106913846Slinton e = addevent(t, buildcmdlist(action)); 107013846Slinton } 107113846Slinton if (isstdin()) { 107213846Slinton printevent(e); 107313846Slinton } 107413846Slinton } else { 107513846Slinton stopinst(p->op, place, cond, action); 107613846Slinton } 10779662Slinton } 10789662Slinton } 10799662Slinton 108013846Slinton private stopinst(op, place, cond, action) 10819662Slinton Operator op; 10829662Slinton Node place; 10839662Slinton Node cond; 108413846Slinton Command action; 10859662Slinton { 10869662Slinton Node event; 108711871Slinton Event e; 10889662Slinton 10899662Slinton if (op == O_STOP) { 10909662Slinton event = build(O_EQ, build(O_SYM, linesym), place); 10919662Slinton } else { 10929662Slinton event = build(O_EQ, build(O_SYM, pcsym), place); 10939662Slinton } 109413846Slinton e = addevent(event, buildcmdlist(action)); 109511871Slinton if (isstdin()) { 109611871Slinton printevent(e); 109711871Slinton } 10989662Slinton } 10999662Slinton 11009662Slinton /* 11019662Slinton * Implement stopping on assignment to a variable by adding it to 11029662Slinton * the variable list. 11039662Slinton */ 11049662Slinton 11059662Slinton private stopvar(op, exp, place, cond) 11069662Slinton Operator op; 11079662Slinton Node exp; 11089662Slinton Node place; 11099662Slinton Node cond; 11109662Slinton { 11119662Slinton Symbol p; 11129662Slinton Node event; 11139662Slinton Command action; 11149662Slinton 111514445Slinton if (place == nil) { 111614445Slinton if (exp->op == O_LCON) { 111714445Slinton p = program; 111814445Slinton } else { 111914445Slinton p = tcontainer(exp); 112014445Slinton if (p == nil) { 112114445Slinton p = program; 112214445Slinton } 112314445Slinton } 112414445Slinton } else { 112514445Slinton p = place->value.sym; 11269662Slinton } 112714445Slinton action = build(O_STOPIFCHANGED, exp); 112814445Slinton if (cond != nil) { 112914445Slinton action = build(O_IF, cond, buildcmdlist(action)); 113014445Slinton } 11319662Slinton action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action)); 11329662Slinton event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p)); 11339662Slinton action->value.trace.event = addevent(event, buildcmdlist(action)); 113411871Slinton if (isstdin()) { 113511871Slinton printevent(action->value.trace.event); 113611871Slinton } 11379662Slinton } 11389662Slinton 11399662Slinton /* 11409662Slinton * Assign the value of an expression to a variable (or term). 11419662Slinton */ 11429662Slinton 11439662Slinton public assign(var, exp) 11449662Slinton Node var; 11459662Slinton Node exp; 11469662Slinton { 11479662Slinton Address addr; 114816608Ssam integer varsize, expsize; 11499662Slinton char cvalue; 11509662Slinton short svalue; 11519662Slinton long lvalue; 115216608Ssam float fvalue; 11539662Slinton 115418217Slinton if (var->op == O_SYM and regnum(var->value.sym) != -1) { 115518217Slinton eval(exp); 115618217Slinton setreg(regnum(var->value.sym), pop(Address)); 115716608Ssam } else { 115818217Slinton addr = lval(var); 115918217Slinton varsize = size(var->nodetype); 116018217Slinton expsize = size(exp->nodetype); 116118217Slinton eval(exp); 116218217Slinton if (varsize == sizeof(float) and expsize == sizeof(double)) { 116318217Slinton fvalue = (float) pop(double); 116418217Slinton dwrite(&fvalue, addr, sizeof(fvalue)); 116518217Slinton } else { 116618217Slinton if (varsize < sizeof(long)) { 116718217Slinton lvalue = 0; 116818217Slinton popn(expsize, &lvalue); 116918217Slinton if (varsize == sizeof(char)) { 117016608Ssam cvalue = lvalue; 117116608Ssam dwrite(&cvalue, addr, sizeof(cvalue)); 117218217Slinton } else if (varsize == sizeof(short)) { 117316608Ssam svalue = lvalue; 117416608Ssam dwrite(&svalue, addr, sizeof(svalue)); 117518217Slinton } else { 117618217Slinton error("[internal error: bad size %d in assign]", varsize); 117718217Slinton } 117818217Slinton } else { 117918217Slinton if (expsize <= varsize) { 118018217Slinton sp -= expsize; 118118217Slinton dwrite(sp, addr, expsize); 118218217Slinton } else { 118318217Slinton sp -= expsize; 118418217Slinton dwrite(sp, addr, varsize); 118518217Slinton } 118618217Slinton } 118718217Slinton } 118818217Slinton } 118918217Slinton } 11909662Slinton 119118217Slinton /* 119218217Slinton * Set a debugger variable. 119318217Slinton */ 119418217Slinton 119518217Slinton private set (var, exp) 119618217Slinton Node var, exp; 119718217Slinton { 119818217Slinton Symbol t; 119918217Slinton 120018217Slinton if (var == nil) { 120118217Slinton defvar(nil, nil); 120218217Slinton } else if (exp == nil) { 120318217Slinton defvar(var->value.name, nil); 120418217Slinton } else if (var->value.name == identname("$frame", true)) { 120518217Slinton t = exp->nodetype; 120618217Slinton if (not compatible(t, t_int) and not compatible(t, t_addr)) { 120718217Slinton error("$frame must be an address"); 120818217Slinton } 120918217Slinton eval(exp); 121018217Slinton getnewregs(pop(Address)); 121118217Slinton } else { 121218217Slinton defvar(var->value.name, unrval(exp)); 121318217Slinton } 121418217Slinton } 121518217Slinton 121618217Slinton /* 121718217Slinton * Execute a list command. 121818217Slinton */ 121918217Slinton 122018217Slinton private list (p) 122118217Slinton Node p; 122218217Slinton { 122318217Slinton Symbol f; 122418217Slinton Address addr; 122518217Slinton Lineno line, l1, l2; 122618217Slinton 122718217Slinton if (p->value.arg[0]->op == O_SYM) { 122818217Slinton f = p->value.arg[0]->value.sym; 122918217Slinton addr = firstline(f); 123018217Slinton if (addr == NOADDR) { 123118217Slinton error("no source lines for \"%s\"", symname(f)); 123218217Slinton } 123318217Slinton setsource(srcfilename(addr)); 123418217Slinton line = srcline(addr); 123518217Slinton getsrcwindow(line, &l1, &l2); 123618217Slinton } else { 123718217Slinton eval(p->value.arg[0]); 123818217Slinton l1 = (Lineno) (pop(long)); 123918217Slinton eval(p->value.arg[1]); 124018217Slinton l2 = (Lineno) (pop(long)); 124118217Slinton } 124218217Slinton printlines(l1, l2); 124318217Slinton } 124418217Slinton 124518217Slinton /* 124618217Slinton * Execute a func command. 124718217Slinton */ 124818217Slinton 124918217Slinton private func (p) 125018217Slinton Node p; 125118217Slinton { 125218217Slinton Symbol s, f; 125318217Slinton Address addr; 125418217Slinton 125518217Slinton if (p == nil) { 125618217Slinton printname(stdout, curfunc); 125718217Slinton putchar('\n'); 125818217Slinton } else { 125918217Slinton s = p->value.sym; 126018217Slinton if (isroutine(s)) { 126118217Slinton setcurfunc(s); 126216608Ssam } else { 126318217Slinton find(f, s->name) where isroutine(f) endfind(f); 126418217Slinton if (f == nil) { 126518217Slinton error("%s is not a procedure or function", symname(s)); 126616608Ssam } 126718217Slinton setcurfunc(f); 12689662Slinton } 126918217Slinton addr = codeloc(curfunc); 127018217Slinton if (addr != NOADDR) { 127118217Slinton setsource(srcfilename(addr)); 127218217Slinton cursrcline = srcline(addr); 127318217Slinton } 12749662Slinton } 12759662Slinton } 12769662Slinton 12779662Slinton /* 127818217Slinton * Send a message to the current support person. 12799662Slinton */ 12809662Slinton 12819662Slinton public gripe() 12829662Slinton { 12839662Slinton typedef Operation(); 12849662Slinton Operation *old; 128514445Slinton int pid, status; 128616608Ssam extern int versionNumber; 128716608Ssam char subject[100]; 12889662Slinton 12899662Slinton puts("Type control-D to end your message. Be sure to include"); 12909662Slinton puts("your name and the name of the file you are debugging."); 12919662Slinton putchar('\n'); 12929662Slinton old = signal(SIGINT, SIG_DFL); 129318217Slinton sprintf(subject, "dbx (version 3.%d) gripe", versionNumber); 129418217Slinton pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil); 129514445Slinton signal(SIGINT, SIG_IGN); 129614445Slinton pwait(pid, &status); 12979662Slinton signal(SIGINT, old); 129814445Slinton if (status == 0) { 129914445Slinton puts("Thank you."); 130014445Slinton } else { 130114445Slinton puts("\nMail not sent."); 130214445Slinton } 13039662Slinton } 13049662Slinton 13059662Slinton /* 13069662Slinton * Give the user some help. 13079662Slinton */ 13089662Slinton 13099662Slinton public help() 13109662Slinton { 13119662Slinton puts("run - begin execution of the program"); 131216608Ssam puts("print <exp> - print the value of the expression"); 131316608Ssam puts("where - print currently active procedures"); 131416608Ssam puts("stop at <line> - suspend execution at the line"); 131516608Ssam puts("stop in <proc> - suspend execution when <proc> is called"); 13169662Slinton puts("cont - continue execution"); 13179662Slinton puts("step - single step one line"); 13189662Slinton puts("next - step to next line (skip over calls)"); 13199662Slinton puts("trace <line#> - trace execution of the line"); 13209662Slinton puts("trace <proc> - trace calls to the procedure"); 13219662Slinton puts("trace <var> - trace changes to the variable"); 13229662Slinton puts("trace <exp> at <line#> - print <exp> when <line> is reached"); 13239662Slinton puts("status - print trace/stop's in effect"); 13249662Slinton puts("delete <number> - remove trace or stop of given number"); 132516608Ssam puts("call <proc> - call a procedure in program"); 13269662Slinton puts("whatis <name> - print the declaration of the name"); 13279662Slinton puts("list <line>, <line> - list source lines"); 13289662Slinton puts("gripe - send mail to the person in charge of dbx"); 13299662Slinton puts("quit - exit dbx"); 13309662Slinton } 13319662Slinton 13329662Slinton /* 13339662Slinton * Divert output to the given file name. 13349662Slinton * Cannot redirect to an existing file. 13359662Slinton */ 13369662Slinton 13379662Slinton private int so_fd; 13389662Slinton private Boolean notstdout; 13399662Slinton 13409662Slinton public setout(filename) 13419662Slinton String filename; 13429662Slinton { 13439662Slinton File f; 13449662Slinton 13459662Slinton f = fopen(filename, "r"); 13469662Slinton if (f != nil) { 13479662Slinton fclose(f); 13489662Slinton error("%s: file already exists", filename); 13499662Slinton } else { 13509662Slinton so_fd = dup(1); 13519662Slinton close(1); 13529662Slinton if (creat(filename, 0666) == nil) { 13539662Slinton unsetout(); 13549662Slinton error("can't create %s", filename); 13559662Slinton } 13569662Slinton notstdout = true; 13579662Slinton } 13589662Slinton } 13599662Slinton 13609662Slinton /* 13619662Slinton * Revert output to standard output. 13629662Slinton */ 13639662Slinton 13649662Slinton public unsetout() 13659662Slinton { 13669662Slinton fflush(stdout); 13679662Slinton close(1); 13689662Slinton if (dup(so_fd) != 1) { 13699662Slinton panic("standard out dup failed"); 13709662Slinton } 13719662Slinton close(so_fd); 13729662Slinton notstdout = false; 13739662Slinton } 13749662Slinton 13759662Slinton /* 13769662Slinton * Determine is standard output is currently being redirected 13779662Slinton * to a file (as far as we know). 13789662Slinton */ 13799662Slinton 13809662Slinton public Boolean isredirected() 13819662Slinton { 13829662Slinton return notstdout; 13839662Slinton } 1384