xref: /csrg-svn/old/dbx/eval.c (revision 16608)
19662Slinton /* Copyright (c) 1982 Regents of the University of California */
29662Slinton 
3*16608Ssam static char sccsid[] = "@(#)eval.c 1.10 8/17/83";
49662Slinton 
5*16608Ssam static char rcsid[] = "$Header: eval.c,v 1.3 84/03/27 10:20:23 linton Exp $";
6*16608Ssam 
79662Slinton /*
89662Slinton  * Tree evaluation.
99662Slinton  */
109662Slinton 
119662Slinton #include "defs.h"
129662Slinton #include "tree.h"
139662Slinton #include "operators.h"
149662Slinton #include "eval.h"
159662Slinton #include "events.h"
169662Slinton #include "symbols.h"
179662Slinton #include "scanner.h"
189662Slinton #include "source.h"
199662Slinton #include "object.h"
209662Slinton #include "mappings.h"
219662Slinton #include "process.h"
22*16608Ssam #include "runtime.h"
239662Slinton #include "machine.h"
249662Slinton #include <signal.h>
259662Slinton 
269662Slinton #ifndef public
279662Slinton 
289662Slinton #include "machine.h"
299662Slinton 
3012538Scsvaf #define STACKSIZE 20000
319662Slinton 
329662Slinton typedef Char Stack;
339662Slinton 
349662Slinton #define push(type, value) { \
359662Slinton     ((type *) (sp += sizeof(type)))[-1] = (value); \
369662Slinton }
379662Slinton 
389662Slinton #define pop(type) ( \
399662Slinton     (*((type *) (sp -= sizeof(type)))) \
409662Slinton )
419662Slinton 
42*16608Ssam #define popn(n, dest) { \
43*16608Ssam     sp -= n; \
44*16608Ssam     bcopy(sp, dest, n); \
45*16608Ssam }
46*16608Ssam 
479662Slinton #define alignstack() { \
489662Slinton     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
499662Slinton }
509662Slinton 
519662Slinton #endif
529662Slinton 
539662Slinton public Stack stack[STACKSIZE];
549662Slinton public Stack *sp = &stack[0];
5514674Slinton public Boolean useInstLoc = false;
569662Slinton 
579662Slinton #define chksp() \
589662Slinton { \
599662Slinton     if (sp < &stack[0]) { \
609662Slinton 	panic("stack underflow"); \
619662Slinton     } \
629662Slinton }
639662Slinton 
649662Slinton #define poparg(n, r, fr) { \
659662Slinton     eval(p->value.arg[n]); \
669662Slinton     if (isreal(p->op)) { \
67*16608Ssam 	if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
68*16608Ssam 	    fr = pop(float); \
69*16608Ssam 	} else { \
70*16608Ssam 	    fr = pop(double); \
71*16608Ssam 	} \
729662Slinton     } else if (isint(p->op)) { \
739662Slinton 	r = popsmall(p->value.arg[n]->nodetype); \
749662Slinton     } \
759662Slinton }
769662Slinton 
779662Slinton #define Boolrep char	/* underlying representation type for booleans */
789662Slinton 
799662Slinton /*
809662Slinton  * Evaluate a parse tree leaving the value on the top of the stack.
819662Slinton  */
829662Slinton 
839662Slinton public eval(p)
849662Slinton register Node p;
859662Slinton {
869662Slinton     long r0, r1;
879662Slinton     double fr0, fr1;
889662Slinton     Address addr;
899662Slinton     long i, n;
909662Slinton     int len;
919662Slinton     Symbol s, f;
929662Slinton     Node n1, n2;
939662Slinton     Boolean b;
949662Slinton     File file;
959662Slinton 
969662Slinton     checkref(p);
9713846Slinton     if (debug_flag[2]) {
9813846Slinton 	fprintf(stderr," evaluating %s \n",showoperator(p->op));
9912538Scsvaf     }
1009662Slinton     switch (degree(p->op)) {
1019662Slinton 	case BINARY:
1029662Slinton 	    poparg(1, r1, fr1);
1039662Slinton 	    poparg(0, r0, fr0);
1049662Slinton 	    break;
1059662Slinton 
1069662Slinton 	case UNARY:
1079662Slinton 	    poparg(0, r0, fr0);
1089662Slinton 	    break;
1099662Slinton 
1109662Slinton 	default:
1119662Slinton 	    /* do nothing */;
1129662Slinton     }
1139662Slinton     switch (p->op) {
1149662Slinton 	case O_SYM:
1159662Slinton 	    s = p->value.sym;
1169662Slinton 	    if (s == retaddrsym) {
1179662Slinton 		push(long, return_addr());
1189662Slinton 	    } else {
1199662Slinton 		if (isvariable(s)) {
1209662Slinton 		    if (s != program and not isactive(container(s))) {
1219662Slinton 			error("\"%s\" is not active", symname(s));
1229662Slinton 		    }
1239662Slinton 		    push(long, address(s, nil));
1249662Slinton 		} else if (isblock(s)) {
1259662Slinton 		    push(Symbol, s);
1269662Slinton 		} else {
1279662Slinton 		    error("can't evaluate a %s", classname(s));
1289662Slinton 		}
1299662Slinton 	    }
1309662Slinton 	    break;
1319662Slinton 
1329662Slinton 	case O_LCON:
1339662Slinton 	    r0 = p->value.lcon;
1349662Slinton 	    pushsmall(p->nodetype, r0);
1359662Slinton 	    break;
1369662Slinton 
1379662Slinton 	case O_FCON:
1389662Slinton 	    push(double, p->value.fcon);
1399662Slinton 	    break;
1409662Slinton 
1419662Slinton 	case O_SCON:
1429662Slinton 	    len = size(p->nodetype);
1439662Slinton 	    mov(p->value.scon, sp, len);
1449662Slinton 	    sp += len;
1459662Slinton 	    break;
1469662Slinton 
1479662Slinton 	case O_INDEX:
1489662Slinton 	    n = pop(long);
1499662Slinton 	    i = evalindex(p->value.arg[0]->nodetype,
1509662Slinton 		popsmall(p->value.arg[1]->nodetype));
1519662Slinton 	    push(long, n + i*size(p->nodetype));
1529662Slinton 	    break;
1539662Slinton 
1549662Slinton 	case O_DOT:
1559662Slinton 	    s = p->value.arg[1]->value.sym;
1569662Slinton 	    n = lval(p->value.arg[0]);
1579662Slinton 	    push(long, n + (s->symvalue.field.offset div 8));
1589662Slinton 	    break;
1599662Slinton 
1609662Slinton 	/*
1619662Slinton 	 * Get the value of the expression addressed by the top of the stack.
1629662Slinton 	 * Push the result back on the stack.
1639662Slinton 	 */
1649662Slinton 
1659662Slinton 	case O_INDIR:
1669662Slinton 	case O_RVAL:
1679662Slinton 	    addr = pop(long);
1689662Slinton 	    if (addr == 0) {
1699662Slinton 		error("reference through nil pointer");
1709662Slinton 	    }
1719662Slinton 	    if (p->op == O_INDIR) {
1729662Slinton 		len = sizeof(long);
1739662Slinton 	    } else {
1749662Slinton 		len = size(p->nodetype);
1759662Slinton 	    }
1769662Slinton 	    rpush(addr, len);
1779662Slinton 	    break;
1789662Slinton 
17911175Slinton 	/*
18011175Slinton 	 * Effectively, we want to pop n bytes off for the evaluated subtree
18111175Slinton 	 * and push len bytes on for the new type of the same tree.
18211175Slinton 	 */
18311175Slinton 	case O_TYPERENAME:
18411175Slinton 	    n = size(p->value.arg[0]->nodetype);
18511175Slinton 	    len = size(p->nodetype);
18611175Slinton 	    sp = sp - n + len;
18711175Slinton 	    break;
18811175Slinton 
1899662Slinton 	case O_COMMA:
1909662Slinton 	    break;
1919662Slinton 
1929662Slinton 	case O_ITOF:
1939662Slinton 	    push(double, (double) r0);
1949662Slinton 	    break;
1959662Slinton 
1969662Slinton 	case O_ADD:
1979662Slinton 	    push(long, r0+r1);
1989662Slinton 	    break;
1999662Slinton 
2009662Slinton 	case O_ADDF:
2019662Slinton 	    push(double, fr0+fr1);
2029662Slinton 	    break;
2039662Slinton 
2049662Slinton 	case O_SUB:
2059662Slinton 	    push(long, r0-r1);
2069662Slinton 	    break;
2079662Slinton 
2089662Slinton 	case O_SUBF:
2099662Slinton 	    push(double, fr0-fr1);
2109662Slinton 	    break;
2119662Slinton 
2129662Slinton 	case O_NEG:
2139662Slinton 	    push(long, -r0);
2149662Slinton 	    break;
2159662Slinton 
2169662Slinton 	case O_NEGF:
2179662Slinton 	    push(double, -fr0);
2189662Slinton 	    break;
2199662Slinton 
2209662Slinton 	case O_MUL:
2219662Slinton 	    push(long, r0*r1);
2229662Slinton 	    break;
2239662Slinton 
2249662Slinton 	case O_MULF:
2259662Slinton 	    push(double, fr0*fr1);
2269662Slinton 	    break;
2279662Slinton 
2289662Slinton 	case O_DIVF:
2299662Slinton 	    if (fr1 == 0) {
2309662Slinton 		error("error: division by 0");
2319662Slinton 	    }
2329662Slinton 	    push(double, fr0 / fr1);
2339662Slinton 	    break;
2349662Slinton 
2359662Slinton 	case O_DIV:
2369662Slinton 	    if (r1 == 0) {
2379662Slinton 		error("error: div by 0");
2389662Slinton 	    }
2399662Slinton 	    push(long, r0 div r1);
2409662Slinton 	    break;
2419662Slinton 
2429662Slinton 	case O_MOD:
2439662Slinton 	    if (r1 == 0) {
2449662Slinton 		error("error: mod by 0");
2459662Slinton 	    }
2469662Slinton 	    push(long, r0 mod r1);
2479662Slinton 	    break;
2489662Slinton 
2499662Slinton 	case O_LT:
2509662Slinton 	    push(Boolrep, r0 < r1);
2519662Slinton 	    break;
2529662Slinton 
2539662Slinton 	case O_LTF:
2549662Slinton 	    push(Boolrep, fr0 < fr1);
2559662Slinton 	    break;
2569662Slinton 
2579662Slinton 	case O_LE:
2589662Slinton 	    push(Boolrep, r0 <= r1);
2599662Slinton 	    break;
2609662Slinton 
2619662Slinton 	case O_LEF:
2629662Slinton 	    push(Boolrep, fr0 <= fr1);
2639662Slinton 	    break;
2649662Slinton 
2659662Slinton 	case O_GT:
2669662Slinton 	    push(Boolrep, r0 > r1);
2679662Slinton 	    break;
2689662Slinton 
2699662Slinton 	case O_GTF:
2709662Slinton 	    push(Boolrep, fr0 > fr1);
2719662Slinton 	    break;
2729662Slinton 
2739662Slinton 	case O_EQ:
2749662Slinton 	    push(Boolrep, r0 == r1);
2759662Slinton 	    break;
2769662Slinton 
2779662Slinton 	case O_EQF:
2789662Slinton 	    push(Boolrep, fr0 == fr1);
2799662Slinton 	    break;
2809662Slinton 
2819662Slinton 	case O_NE:
2829662Slinton 	    push(Boolrep, r0 != r1);
2839662Slinton 	    break;
2849662Slinton 
2859662Slinton 	case O_NEF:
2869662Slinton 	    push(Boolrep, fr0 != fr1);
2879662Slinton 	    break;
2889662Slinton 
2899662Slinton 	case O_AND:
2909662Slinton 	    push(Boolrep, r0 and r1);
2919662Slinton 	    break;
2929662Slinton 
2939662Slinton 	case O_OR:
2949662Slinton 	    push(Boolrep, r0 or r1);
2959662Slinton 	    break;
2969662Slinton 
2979662Slinton 	case O_ASSIGN:
2989662Slinton 	    assign(p->value.arg[0], p->value.arg[1]);
2999662Slinton 	    break;
3009662Slinton 
3019662Slinton 	case O_CHFILE:
3029662Slinton 	    if (p->value.scon == nil) {
3039662Slinton 		printf("%s\n", cursource);
3049662Slinton 	    } else {
3059662Slinton 		file = opensource(p->value.scon);
3069662Slinton 		if (file == nil) {
3079662Slinton 		    error("can't read \"%s\"", p->value.scon);
3089662Slinton 		} else {
3099662Slinton 		    fclose(file);
3109662Slinton 		    setsource(p->value.scon);
3119662Slinton 		}
3129662Slinton 	    }
3139662Slinton 	    break;
3149662Slinton 
3159662Slinton 	case O_CONT:
31611871Slinton 	    cont(p->value.lcon);
3179662Slinton 	    printnews();
3189662Slinton 	    break;
3199662Slinton 
3209662Slinton 	case O_LIST:
3219662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
3229662Slinton 		f = p->value.arg[0]->value.sym;
3239662Slinton 		addr = firstline(f);
3249662Slinton 		if (addr == NOADDR) {
3259662Slinton 		    error("no source lines for \"%s\"", symname(f));
3269662Slinton 		}
3279662Slinton 		setsource(srcfilename(addr));
3289662Slinton 		r0 = srcline(addr) - 5;
3299662Slinton 		r1 = r0 + 10;
3309662Slinton 		if (r0 < 1) {
3319662Slinton 		    r0 = 1;
3329662Slinton 		}
3339662Slinton 	    } else {
3349662Slinton 		eval(p->value.arg[0]);
3359662Slinton 		r0 = pop(long);
3369662Slinton 		eval(p->value.arg[1]);
3379662Slinton 		r1 = pop(long);
3389662Slinton 	    }
3399662Slinton 	    printlines((Lineno) r0, (Lineno) r1);
3409662Slinton 	    break;
3419662Slinton 
3429662Slinton 	case O_FUNC:
3439662Slinton 	    if (p->value.arg[0] == nil) {
3449662Slinton 		printname(stdout, curfunc);
3459662Slinton 		putchar('\n');
3469662Slinton 	    } else {
34711871Slinton 		s = p->value.arg[0]->value.sym;
348*16608Ssam 		if (isroutine(s)) {
349*16608Ssam 		    setcurfunc(s);
350*16608Ssam 		} else {
351*16608Ssam 		    find(f, s->name) where isroutine(f) endfind(f);
352*16608Ssam 		    if (f == nil) {
353*16608Ssam 			error("%s is not a procedure or function", symname(s));
354*16608Ssam 		    }
355*16608Ssam 		    setcurfunc(f);
35611771Slinton 		}
3579662Slinton 		addr = codeloc(curfunc);
3589662Slinton 		if (addr != NOADDR) {
3599662Slinton 		    setsource(srcfilename(addr));
3609662Slinton 		    cursrcline = srcline(addr) - 5;
3619662Slinton 		    if (cursrcline < 1) {
3629662Slinton 			cursrcline = 1;
3639662Slinton 		    }
3649662Slinton 		}
3659662Slinton 	    }
3669662Slinton 	    break;
3679662Slinton 
3689662Slinton 	case O_EXAMINE:
3699662Slinton 	    eval(p->value.examine.beginaddr);
3709662Slinton 	    r0 = pop(long);
3719662Slinton 	    if (p->value.examine.endaddr == nil) {
3729662Slinton 		n = p->value.examine.count;
37311175Slinton 		if (n == 0) {
37411175Slinton 		    printvalue(r0, p->value.examine.mode);
37511175Slinton 		} else if (streq(p->value.examine.mode, "i")) {
3769662Slinton 		    printninst(n, (Address) r0);
3779662Slinton 		} else {
3789662Slinton 		    printndata(n, (Address) r0, p->value.examine.mode);
3799662Slinton 		}
3809662Slinton 	    } else {
3819662Slinton 		eval(p->value.examine.endaddr);
3829662Slinton 		r1 = pop(long);
3839662Slinton 		if (streq(p->value.examine.mode, "i")) {
3849662Slinton 		    printinst((Address)r0, (Address)r1);
3859662Slinton 		} else {
3869662Slinton 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
3879662Slinton 		}
3889662Slinton 	    }
3899662Slinton 	    break;
3909662Slinton 
3919662Slinton 	case O_PRINT:
3929662Slinton 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
3939662Slinton 		eval(n1->value.arg[0]);
3949662Slinton 		printval(n1->value.arg[0]->nodetype);
3959662Slinton 		putchar(' ');
3969662Slinton 	    }
3979662Slinton 	    putchar('\n');
3989662Slinton 	    break;
3999662Slinton 
4009662Slinton 	case O_PSYM:
4019662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4029662Slinton 		psym(p->value.arg[0]->value.sym);
4039662Slinton 	    } else {
4049662Slinton 		psym(p->value.arg[0]->nodetype);
4059662Slinton 	    }
4069662Slinton 	    break;
4079662Slinton 
4089662Slinton 	case O_QLINE:
4099662Slinton 	    eval(p->value.arg[1]);
4109662Slinton 	    break;
4119662Slinton 
4129662Slinton 	case O_STEP:
4139662Slinton 	    b = inst_tracing;
4149662Slinton 	    inst_tracing = (Boolean) (not p->value.step.source);
4159662Slinton 	    if (p->value.step.skipcalls) {
4169662Slinton 		next();
4179662Slinton 	    } else {
4189662Slinton 		stepc();
4199662Slinton 	    }
4209662Slinton 	    inst_tracing = b;
42114674Slinton 	    useInstLoc = (Boolean) (not p->value.step.source);
4229662Slinton 	    printnews();
4239662Slinton 	    break;
4249662Slinton 
4259662Slinton 	case O_WHATIS:
4269662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4279662Slinton 		printdecl(p->value.arg[0]->value.sym);
4289662Slinton 	    } else {
4299662Slinton 		printdecl(p->value.arg[0]->nodetype);
4309662Slinton 	    }
4319662Slinton 	    break;
4329662Slinton 
4339662Slinton 	case O_WHERE:
4349662Slinton 	    wherecmd();
4359662Slinton 	    break;
4369662Slinton 
4379662Slinton 	case O_WHEREIS:
43812538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
43912538Scsvaf 		printwhereis(stdout,p->value.arg[0]->value.sym);
44012538Scsvaf 	    } else {
44112538Scsvaf 		printwhereis(stdout,p->value.arg[0]->nodetype);
44212538Scsvaf 	    }
4439662Slinton 	    break;
4449662Slinton 
4459662Slinton 	case O_WHICH:
44612538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
44712538Scsvaf 		printwhich(stdout,p->value.arg[0]->value.sym);
44812538Scsvaf 	    } else {
44912538Scsvaf 		printwhich(stdout,p->value.arg[0]->nodetype);
45012538Scsvaf 	    }
4519662Slinton 	    putchar('\n');
4529662Slinton 	    break;
4539662Slinton 
4549662Slinton 	case O_ALIAS:
4559662Slinton 	    n1 = p->value.arg[0];
4569662Slinton 	    n2 = p->value.arg[1];
4579662Slinton 	    if (n1 == nil) {
4589662Slinton 		print_alias(nil);
4599662Slinton 	    } else if (n2 == nil) {
4609662Slinton 		print_alias(n1->value.name);
4619662Slinton 	    } else {
4629662Slinton 		enter_alias(n1->value.name, n2->value.name);
4639662Slinton 	    }
4649662Slinton 	    break;
4659662Slinton 
4669662Slinton 	case O_CALL:
4679662Slinton 	    callproc(p->value.arg[0], p->value.arg[1]);
4689662Slinton 	    break;
4699662Slinton 
4709662Slinton 	case O_CATCH:
4719662Slinton 	    psigtrace(process, p->value.lcon, true);
4729662Slinton 	    break;
4739662Slinton 
4749662Slinton 	case O_EDIT:
4759662Slinton 	    edit(p->value.scon);
4769662Slinton 	    break;
4779662Slinton 
47812538Scsvaf         case O_DEBUG:
47912538Scsvaf             debug(p);
48012538Scsvaf 	    break;
48112538Scsvaf 
482*16608Ssam 	case O_DOWN:
483*16608Ssam 	    checkref(p->value.arg[0]);
484*16608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
485*16608Ssam 	    down(p->value.arg[0]->value.lcon);
486*16608Ssam 	    break;
487*16608Ssam 
4889662Slinton 	case O_DUMP:
4899662Slinton 	    dump();
4909662Slinton 	    break;
4919662Slinton 
4929662Slinton 	case O_GRIPE:
4939662Slinton 	    gripe();
4949662Slinton 	    break;
4959662Slinton 
4969662Slinton 	case O_HELP:
4979662Slinton 	    help();
4989662Slinton 	    break;
4999662Slinton 
5009662Slinton 	case O_IGNORE:
5019662Slinton 	    psigtrace(process, p->value.lcon, false);
5029662Slinton 	    break;
5039662Slinton 
504*16608Ssam 	case O_RETURN:
505*16608Ssam 	    if (p->value.arg[0] == nil) {
506*16608Ssam 		rtnfunc(nil);
507*16608Ssam 	    } else {
508*16608Ssam 		assert(p->value.arg[0]->op == O_SYM);
509*16608Ssam 		rtnfunc(p->value.arg[0]->value.sym);
510*16608Ssam 	    }
511*16608Ssam 	    break;
512*16608Ssam 
5139662Slinton 	case O_RUN:
5149662Slinton 	    run();
5159662Slinton 	    break;
5169662Slinton 
5179662Slinton 	case O_SOURCE:
5189662Slinton 	    setinput(p->value.scon);
5199662Slinton 	    break;
5209662Slinton 
5219662Slinton 	case O_STATUS:
5229662Slinton 	    status();
5239662Slinton 	    break;
5249662Slinton 
5259662Slinton 	case O_TRACE:
5269662Slinton 	case O_TRACEI:
5279662Slinton 	    trace(p);
5289662Slinton 	    break;
5299662Slinton 
5309662Slinton 	case O_STOP:
5319662Slinton 	case O_STOPI:
5329662Slinton 	    stop(p);
5339662Slinton 	    break;
5349662Slinton 
535*16608Ssam 	case O_UP:
536*16608Ssam 	    checkref(p->value.arg[0]);
537*16608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
538*16608Ssam 	    up(p->value.arg[0]->value.lcon);
539*16608Ssam 	    break;
540*16608Ssam 
5419662Slinton 	case O_ADDEVENT:
5429662Slinton 	    addevent(p->value.event.cond, p->value.event.actions);
5439662Slinton 	    break;
5449662Slinton 
5459662Slinton 	case O_DELETE:
546*16608Ssam 	    n1 = p->value.arg[0];
547*16608Ssam 	    while (n1->op == O_COMMA) {
548*16608Ssam 		n2 = n1->value.arg[0];
549*16608Ssam 		assert(n2->op == O_LCON);
550*16608Ssam 		if (not delevent((unsigned int) n2->value.lcon)) {
551*16608Ssam 		    error("unknown event %ld", n2->value.lcon);
552*16608Ssam 		}
553*16608Ssam 		n1 = n1->value.arg[1];
554*16608Ssam 	    }
555*16608Ssam 	    assert(n1->op == O_LCON);
556*16608Ssam 	    if (not delevent((unsigned int) n1->value.lcon)) {
557*16608Ssam 		error("unknown event %ld", n1->value.lcon);
558*16608Ssam 	    }
5599662Slinton 	    break;
5609662Slinton 
5619662Slinton 	case O_ENDX:
5629662Slinton 	    endprogram();
5639662Slinton 	    break;
5649662Slinton 
5659662Slinton 	case O_IF:
5669662Slinton 	    if (cond(p->value.event.cond)) {
5679662Slinton 		evalcmdlist(p->value.event.actions);
5689662Slinton 	    }
5699662Slinton 	    break;
5709662Slinton 
5719662Slinton 	case O_ONCE:
5729662Slinton 	    event_once(p->value.event.cond, p->value.event.actions);
5739662Slinton 	    break;
5749662Slinton 
5759662Slinton 	case O_PRINTCALL:
5769662Slinton 	    printcall(p->value.sym, whatblock(return_addr()));
5779662Slinton 	    break;
5789662Slinton 
5799662Slinton 	case O_PRINTIFCHANGED:
5809662Slinton 	    printifchanged(p->value.arg[0]);
5819662Slinton 	    break;
5829662Slinton 
5839662Slinton 	case O_PRINTRTN:
5849662Slinton 	    printrtn(p->value.sym);
5859662Slinton 	    break;
5869662Slinton 
5879662Slinton 	case O_PRINTSRCPOS:
5889662Slinton 	    getsrcpos();
5899662Slinton 	    if (p->value.arg[0] == nil) {
5909662Slinton 		printsrcpos();
5919662Slinton 		putchar('\n');
5929662Slinton 		printlines(curline, curline);
5939662Slinton 	    } else if (p->value.arg[0]->op == O_QLINE) {
5949662Slinton 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
5959662Slinton 		    printf("tracei: ");
5969662Slinton 		    printinst(pc, pc);
5979662Slinton 		} else {
5989662Slinton 		    printf("trace:  ");
5999662Slinton 		    printlines(curline, curline);
6009662Slinton 		}
6019662Slinton 	    } else {
6029662Slinton 		printsrcpos();
6039662Slinton 		printf(": ");
6049662Slinton 		eval(p->value.arg[0]);
6059662Slinton 		prtree(stdout, p->value.arg[0]);
6069662Slinton 		printf(" = ");
6079662Slinton 		printval(p->value.arg[0]->nodetype);
6089662Slinton 		putchar('\n');
6099662Slinton 	    }
6109662Slinton 	    break;
6119662Slinton 
6129662Slinton 	case O_PROCRTN:
6139662Slinton 	    procreturn(p->value.sym);
6149662Slinton 	    break;
6159662Slinton 
6169662Slinton 	case O_STOPIFCHANGED:
6179662Slinton 	    stopifchanged(p->value.arg[0]);
6189662Slinton 	    break;
6199662Slinton 
6209662Slinton 	case O_STOPX:
6219662Slinton 	    isstopped = true;
6229662Slinton 	    break;
6239662Slinton 
6249662Slinton 	case O_TRACEON:
6259662Slinton 	    traceon(p->value.trace.inst, p->value.trace.event,
6269662Slinton 		p->value.trace.actions);
6279662Slinton 	    break;
6289662Slinton 
6299662Slinton 	case O_TRACEOFF:
6309662Slinton 	    traceoff(p->value.lcon);
6319662Slinton 	    break;
6329662Slinton 
6339662Slinton 	default:
6349662Slinton 	    panic("eval: bad op %d", p->op);
6359662Slinton     }
63612538Scsvaf  if(debug_flag[2]) {
63712538Scsvaf 	fprintf(stderr," evaluated %s \n",showoperator(p->op));
63812538Scsvaf  }
63912538Scsvaf 
6409662Slinton }
6419662Slinton 
6429662Slinton /*
6439662Slinton  * Evaluate a list of commands.
6449662Slinton  */
6459662Slinton 
6469662Slinton public evalcmdlist(cl)
6479662Slinton Cmdlist cl;
6489662Slinton {
6499662Slinton     Command c;
6509662Slinton 
6519662Slinton     foreach (Command, c, cl)
6529662Slinton 	evalcmd(c);
6539662Slinton     endfor
6549662Slinton }
6559662Slinton 
6569662Slinton /*
6579662Slinton  * Push "len" bytes onto the expression stack from address "addr"
6589662Slinton  * in the process.  If there isn't room on the stack, print an error message.
6599662Slinton  */
6609662Slinton 
6619662Slinton public rpush(addr, len)
6629662Slinton Address addr;
6639662Slinton int len;
6649662Slinton {
6659662Slinton     if (not canpush(len)) {
6669662Slinton 	error("expression too large to evaluate");
6679662Slinton     } else {
6689662Slinton 	chksp();
6699662Slinton 	dread(sp, addr, len);
6709662Slinton 	sp += len;
6719662Slinton     }
6729662Slinton }
6739662Slinton 
6749662Slinton /*
6759662Slinton  * Check if the stack has n bytes available.
6769662Slinton  */
6779662Slinton 
6789662Slinton public Boolean canpush(n)
6799662Slinton Integer n;
6809662Slinton {
6819662Slinton     return (Boolean) (sp + n < &stack[STACKSIZE]);
6829662Slinton }
6839662Slinton 
6849662Slinton /*
6859662Slinton  * Push a small scalar of the given type onto the stack.
6869662Slinton  */
6879662Slinton 
6889662Slinton public pushsmall(t, v)
6899662Slinton Symbol t;
6909662Slinton long v;
6919662Slinton {
6929662Slinton     register Integer s;
6939662Slinton 
6949662Slinton     s = size(t);
6959662Slinton     switch (s) {
6969662Slinton 	case sizeof(char):
6979662Slinton 	    push(char, v);
6989662Slinton 	    break;
6999662Slinton 
7009662Slinton 	case sizeof(short):
7019662Slinton 	    push(short, v);
7029662Slinton 	    break;
7039662Slinton 
7049662Slinton 	case sizeof(long):
7059662Slinton 	    push(long, v);
7069662Slinton 	    break;
7079662Slinton 
7089662Slinton 	default:
7099662Slinton 	    panic("bad size %d in popsmall", s);
7109662Slinton     }
7119662Slinton }
7129662Slinton 
7139662Slinton /*
7149662Slinton  * Pop an item of the given type which is assumed to be no larger
7159662Slinton  * than a long and return it expanded into a long.
7169662Slinton  */
7179662Slinton 
7189662Slinton public long popsmall(t)
7199662Slinton Symbol t;
7209662Slinton {
7219662Slinton     long r;
7229662Slinton 
7239662Slinton     switch (size(t)) {
7249662Slinton 	case sizeof(char):
7259662Slinton 	    r = (long) pop(char);
7269662Slinton 	    break;
7279662Slinton 
7289662Slinton 	case sizeof(short):
7299662Slinton 	    r = (long) pop(short);
7309662Slinton 	    break;
7319662Slinton 
7329662Slinton 	case sizeof(long):
7339662Slinton 	    r = pop(long);
7349662Slinton 	    break;
7359662Slinton 
7369662Slinton 	default:
7379662Slinton 	    panic("popsmall: size is %d", size(t));
7389662Slinton     }
7399662Slinton     return r;
7409662Slinton }
7419662Slinton 
7429662Slinton /*
7439662Slinton  * Evaluate a conditional expression.
7449662Slinton  */
7459662Slinton 
7469662Slinton public Boolean cond(p)
7479662Slinton Node p;
7489662Slinton {
7499662Slinton     register Boolean b;
7509662Slinton 
7519662Slinton     if (p == nil) {
7529662Slinton 	b = true;
7539662Slinton     } else {
7549662Slinton 	eval(p);
75513846Slinton 	b = (Boolean) pop(Boolrep);
7569662Slinton     }
7579662Slinton     return b;
7589662Slinton }
7599662Slinton 
7609662Slinton /*
7619662Slinton  * Return the address corresponding to a given tree.
7629662Slinton  */
7639662Slinton 
7649662Slinton public Address lval(p)
7659662Slinton Node p;
7669662Slinton {
7679662Slinton     if (p->op == O_RVAL) {
7689662Slinton 	eval(p->value.arg[0]);
7699662Slinton     } else {
7709662Slinton 	eval(p);
7719662Slinton     }
7729662Slinton     return (Address) (pop(long));
7739662Slinton }
7749662Slinton 
7759662Slinton /*
7769662Slinton  * Process a trace command, translating into the appropriate events
7779662Slinton  * and associated actions.
7789662Slinton  */
7799662Slinton 
7809662Slinton public trace(p)
7819662Slinton Node p;
7829662Slinton {
7839662Slinton     Node exp, place, cond;
7849662Slinton     Node left;
7859662Slinton 
7869662Slinton     exp = p->value.arg[0];
7879662Slinton     place = p->value.arg[1];
7889662Slinton     cond = p->value.arg[2];
7899662Slinton     if (exp == nil) {
7909662Slinton 	traceall(p->op, place, cond);
79111771Slinton     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
7929662Slinton 	traceinst(p->op, exp, cond);
7939662Slinton     } else if (place != nil and place->op == O_QLINE) {
7949662Slinton 	traceat(p->op, exp, place, cond);
7959662Slinton     } else {
7969861Slinton 	left = exp;
7979861Slinton 	if (left->op == O_RVAL or left->op == O_CALL) {
7989861Slinton 	    left = left->value.arg[0];
7999861Slinton 	}
8009662Slinton 	if (left->op == O_SYM and isblock(left->value.sym)) {
8019662Slinton 	    traceproc(p->op, left->value.sym, place, cond);
8029662Slinton 	} else {
8039662Slinton 	    tracedata(p->op, exp, place, cond);
8049662Slinton 	}
8059662Slinton     }
8069662Slinton }
8079662Slinton 
8089662Slinton /*
8099662Slinton  * Set a breakpoint that will turn on tracing.
8109662Slinton  */
8119662Slinton 
8129662Slinton private traceall(op, place, cond)
8139662Slinton Operator op;
8149662Slinton Node place;
8159662Slinton Node cond;
8169662Slinton {
8179662Slinton     Symbol s;
8189662Slinton     Node event;
8199662Slinton     Command action;
8209662Slinton 
8219662Slinton     if (place == nil) {
8229662Slinton 	s = program;
8239662Slinton     } else {
8249662Slinton 	s = place->value.sym;
8259662Slinton     }
8269662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
8279662Slinton     action = build(O_PRINTSRCPOS,
8289662Slinton 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
8299662Slinton     if (cond != nil) {
8309662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8319662Slinton     }
8329662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
8339662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
83411871Slinton     if (isstdin()) {
83511871Slinton 	printevent(action->value.trace.event);
83611871Slinton     }
8379662Slinton }
8389662Slinton 
8399662Slinton /*
8409662Slinton  * Set up the appropriate breakpoint for tracing an instruction.
8419662Slinton  */
8429662Slinton 
8439662Slinton private traceinst(op, exp, cond)
8449662Slinton Operator op;
8459662Slinton Node exp;
8469662Slinton Node cond;
8479662Slinton {
84811771Slinton     Node event, wh;
8499662Slinton     Command action;
85011871Slinton     Event e;
8519662Slinton 
85211771Slinton     if (exp->op == O_LCON) {
85311771Slinton 	wh = build(O_QLINE, build(O_SCON, cursource), exp);
85411771Slinton     } else {
85511771Slinton 	wh = exp;
85611771Slinton     }
8579662Slinton     if (op == O_TRACEI) {
85811771Slinton 	event = build(O_EQ, build(O_SYM, pcsym), wh);
8599662Slinton     } else {
86011771Slinton 	event = build(O_EQ, build(O_SYM, linesym), wh);
8619662Slinton     }
86211771Slinton     action = build(O_PRINTSRCPOS, wh);
8639662Slinton     if (cond) {
8649662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8659662Slinton     }
86611871Slinton     e = addevent(event, buildcmdlist(action));
86711871Slinton     if (isstdin()) {
86811871Slinton 	printevent(e);
86911871Slinton     }
8709662Slinton }
8719662Slinton 
8729662Slinton /*
8739662Slinton  * Set a breakpoint to print an expression at a given line or address.
8749662Slinton  */
8759662Slinton 
8769662Slinton private traceat(op, exp, place, cond)
8779662Slinton Operator op;
8789662Slinton Node exp;
8799662Slinton Node place;
8809662Slinton Node cond;
8819662Slinton {
8829662Slinton     Node event;
8839662Slinton     Command action;
88411871Slinton     Event e;
8859662Slinton 
8869662Slinton     if (op == O_TRACEI) {
8879662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
8889662Slinton     } else {
8899662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
8909662Slinton     }
8919662Slinton     action = build(O_PRINTSRCPOS, exp);
8929662Slinton     if (cond != nil) {
8939662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8949662Slinton     }
89511871Slinton     e = addevent(event, buildcmdlist(action));
89611871Slinton     if (isstdin()) {
89711871Slinton 	printevent(e);
89811871Slinton     }
8999662Slinton }
9009662Slinton 
9019662Slinton /*
9029662Slinton  * Construct event for tracing a procedure.
9039662Slinton  *
9049662Slinton  * What we want here is
9059662Slinton  *
9069662Slinton  * 	when $proc = p do
9079662Slinton  *	    if <condition> then
9089662Slinton  *	        printcall;
9099662Slinton  *	        once $pc = $retaddr do
9109662Slinton  *	            printrtn;
9119662Slinton  *	        end;
9129662Slinton  *	    end if;
9139662Slinton  *	end;
9149662Slinton  *
9159662Slinton  * Note that "once" is like "when" except that the event
9169662Slinton  * deletes itself as part of its associated action.
9179662Slinton  */
9189662Slinton 
9199662Slinton private traceproc(op, p, place, cond)
9209662Slinton Operator op;
9219662Slinton Symbol p;
9229662Slinton Node place;
9239662Slinton Node cond;
9249662Slinton {
9259662Slinton     Node event;
9269662Slinton     Command action;
9279662Slinton     Cmdlist actionlist;
92811871Slinton     Event e;
9299662Slinton 
9309662Slinton     action = build(O_PRINTCALL, p);
9319662Slinton     actionlist = list_alloc();
9329662Slinton     cmdlist_append(action, actionlist);
9339662Slinton     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
9349662Slinton     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
9359662Slinton     cmdlist_append(action, actionlist);
9369662Slinton     if (cond != nil) {
9379662Slinton 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
9389662Slinton     }
9399662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
94011871Slinton     e = addevent(event, actionlist);
94111871Slinton     if (isstdin()) {
94211871Slinton 	printevent(e);
94311871Slinton     }
9449662Slinton }
9459662Slinton 
9469662Slinton /*
9479662Slinton  * Set up breakpoint for tracing data.
9489662Slinton  */
9499662Slinton 
9509662Slinton private tracedata(op, exp, place, cond)
9519662Slinton Operator op;
9529662Slinton Node exp;
9539662Slinton Node place;
9549662Slinton Node cond;
9559662Slinton {
9569662Slinton     Symbol p;
9579662Slinton     Node event;
9589662Slinton     Command action;
9599662Slinton 
9609662Slinton     p = (place == nil) ? tcontainer(exp) : place->value.sym;
9619662Slinton     if (p == nil) {
9629662Slinton 	p = program;
9639662Slinton     }
9649662Slinton     action = build(O_PRINTIFCHANGED, exp);
9659662Slinton     if (cond != nil) {
9669662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9679662Slinton     }
9689662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
9699662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
9709662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
97111871Slinton     if (isstdin()) {
97211871Slinton 	printevent(action->value.trace.event);
97311871Slinton     }
9749662Slinton }
9759662Slinton 
9769662Slinton /*
9779662Slinton  * Setting and unsetting of stops.
9789662Slinton  */
9799662Slinton 
9809662Slinton public stop(p)
9819662Slinton Node p;
9829662Slinton {
98313846Slinton     Node exp, place, cond, t;
9849662Slinton     Symbol s;
9859662Slinton     Command action;
98611871Slinton     Event e;
9879662Slinton 
9889662Slinton     exp = p->value.arg[0];
9899662Slinton     place = p->value.arg[1];
9909662Slinton     cond = p->value.arg[2];
9919662Slinton     if (exp != nil) {
9929662Slinton 	stopvar(p->op, exp, place, cond);
99313846Slinton     } else {
99413846Slinton 	action = build(O_STOPX);
99513846Slinton 	if (cond != nil) {
99613846Slinton 	    action = build(O_IF, cond, buildcmdlist(action));
99711871Slinton 	}
998*16608Ssam 	if (place == nil or place->op == O_SYM) {
999*16608Ssam 	    if (place == nil) {
1000*16608Ssam 		s = program;
1001*16608Ssam 	    } else {
1002*16608Ssam 		s = place->value.sym;
1003*16608Ssam 	    }
100413846Slinton 	    t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
100513846Slinton 	    if (cond != nil) {
100613846Slinton 		action = build(O_TRACEON, (p->op == O_STOPI),
100713846Slinton 		    buildcmdlist(action));
100813846Slinton 		e = addevent(t, buildcmdlist(action));
100913846Slinton 		action->value.trace.event = e;
101013846Slinton 	    } else {
101113846Slinton 		e = addevent(t, buildcmdlist(action));
101213846Slinton 	    }
101313846Slinton 	    if (isstdin()) {
101413846Slinton 		printevent(e);
101513846Slinton 	    }
101613846Slinton 	} else {
101713846Slinton 	    stopinst(p->op, place, cond, action);
101813846Slinton 	}
10199662Slinton     }
10209662Slinton }
10219662Slinton 
102213846Slinton private stopinst(op, place, cond, action)
10239662Slinton Operator op;
10249662Slinton Node place;
10259662Slinton Node cond;
102613846Slinton Command action;
10279662Slinton {
10289662Slinton     Node event;
102911871Slinton     Event e;
10309662Slinton 
10319662Slinton     if (op == O_STOP) {
10329662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
10339662Slinton     } else {
10349662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
10359662Slinton     }
103613846Slinton     e = addevent(event, buildcmdlist(action));
103711871Slinton     if (isstdin()) {
103811871Slinton 	printevent(e);
103911871Slinton     }
10409662Slinton }
10419662Slinton 
10429662Slinton /*
10439662Slinton  * Implement stopping on assignment to a variable by adding it to
10449662Slinton  * the variable list.
10459662Slinton  */
10469662Slinton 
10479662Slinton private stopvar(op, exp, place, cond)
10489662Slinton Operator op;
10499662Slinton Node exp;
10509662Slinton Node place;
10519662Slinton Node cond;
10529662Slinton {
10539662Slinton     Symbol p;
10549662Slinton     Node event;
10559662Slinton     Command action;
10569662Slinton 
105714445Slinton     if (place == nil) {
105814445Slinton 	if (exp->op == O_LCON) {
105914445Slinton 	    p = program;
106014445Slinton 	} else {
106114445Slinton 	    p = tcontainer(exp);
106214445Slinton 	    if (p == nil) {
106314445Slinton 		p = program;
106414445Slinton 	    }
106514445Slinton 	}
106614445Slinton     } else {
106714445Slinton 	p = place->value.sym;
10689662Slinton     }
106914445Slinton     action = build(O_STOPIFCHANGED, exp);
107014445Slinton     if (cond != nil) {
107114445Slinton 	action = build(O_IF, cond, buildcmdlist(action));
107214445Slinton     }
10739662Slinton     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
10749662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
10759662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
107611871Slinton     if (isstdin()) {
107711871Slinton 	printevent(action->value.trace.event);
107811871Slinton     }
10799662Slinton }
10809662Slinton 
10819662Slinton /*
10829662Slinton  * Assign the value of an expression to a variable (or term).
10839662Slinton  */
10849662Slinton 
10859662Slinton public assign(var, exp)
10869662Slinton Node var;
10879662Slinton Node exp;
10889662Slinton {
10899662Slinton     Address addr;
1090*16608Ssam     integer varsize, expsize;
10919662Slinton     char cvalue;
10929662Slinton     short svalue;
10939662Slinton     long lvalue;
1094*16608Ssam     float fvalue;
10959662Slinton 
10969662Slinton     if (not compatible(var->nodetype, exp->nodetype)) {
10979662Slinton 	error("incompatible types");
10989662Slinton     }
10999662Slinton     addr = lval(var);
1100*16608Ssam     varsize = size(var->nodetype);
1101*16608Ssam     expsize = size(exp->nodetype);
11029662Slinton     eval(exp);
1103*16608Ssam     if (varsize == sizeof(float) and expsize == sizeof(double)) {
1104*16608Ssam 	fvalue = (float) pop(double);
1105*16608Ssam 	dwrite(&fvalue, addr, sizeof(fvalue));
1106*16608Ssam     } else {
1107*16608Ssam 	if (varsize < sizeof(long)) {
1108*16608Ssam 	    lvalue = 0;
1109*16608Ssam 	    popn(expsize, &lvalue);
1110*16608Ssam 	    switch (varsize) {
1111*16608Ssam 		case sizeof(char):
1112*16608Ssam 		    cvalue = lvalue;
1113*16608Ssam 		    dwrite(&cvalue, addr, sizeof(cvalue));
1114*16608Ssam 		    break;
11159662Slinton 
1116*16608Ssam 		case sizeof(short):
1117*16608Ssam 		    svalue = lvalue;
1118*16608Ssam 		    dwrite(&svalue, addr, sizeof(svalue));
1119*16608Ssam 		    break;
11209662Slinton 
1121*16608Ssam 		default:
1122*16608Ssam 		    panic("bad size %d", varsize);
1123*16608Ssam 	    }
1124*16608Ssam 	} else {
1125*16608Ssam 	    if (expsize <= varsize) {
1126*16608Ssam 		sp -= expsize;
1127*16608Ssam 		dwrite(sp, addr, expsize);
1128*16608Ssam 	    } else {
1129*16608Ssam 		sp -= expsize;
1130*16608Ssam 		dwrite(sp, addr, varsize);
1131*16608Ssam 	    }
11329662Slinton 	}
11339662Slinton     }
11349662Slinton }
11359662Slinton 
11369662Slinton /*
11379662Slinton  * Send some nasty mail to the current support person.
11389662Slinton  */
11399662Slinton 
11409662Slinton public gripe()
11419662Slinton {
11429662Slinton     typedef Operation();
11439662Slinton     Operation *old;
114414445Slinton     int pid, status;
1145*16608Ssam     extern int versionNumber;
1146*16608Ssam     char subject[100];
114714445Slinton     char *maintainer = "linton@berkeley";
11489662Slinton 
11499662Slinton     puts("Type control-D to end your message.  Be sure to include");
11509662Slinton     puts("your name and the name of the file you are debugging.");
11519662Slinton     putchar('\n');
11529662Slinton     old = signal(SIGINT, SIG_DFL);
1153*16608Ssam     sprintf(subject, "dbx (version %d) gripe", versionNumber);
1154*16608Ssam     pid = back("Mail", stdin, stdout, "-s", subject, maintainer, nil);
115514445Slinton     signal(SIGINT, SIG_IGN);
115614445Slinton     pwait(pid, &status);
11579662Slinton     signal(SIGINT, old);
115814445Slinton     if (status == 0) {
115914445Slinton 	puts("Thank you.");
116014445Slinton     } else {
116114445Slinton 	puts("\nMail not sent.");
116214445Slinton     }
11639662Slinton }
11649662Slinton 
11659662Slinton /*
11669662Slinton  * Give the user some help.
11679662Slinton  */
11689662Slinton 
11699662Slinton public help()
11709662Slinton {
11719662Slinton     puts("run                    - begin execution of the program");
1172*16608Ssam     puts("print <exp>            - print the value of the expression");
1173*16608Ssam     puts("where                  - print currently active procedures");
1174*16608Ssam     puts("stop at <line>         - suspend execution at the line");
1175*16608Ssam     puts("stop in <proc>         - suspend execution when <proc> is called");
11769662Slinton     puts("cont                   - continue execution");
11779662Slinton     puts("step                   - single step one line");
11789662Slinton     puts("next                   - step to next line (skip over calls)");
11799662Slinton     puts("trace <line#>          - trace execution of the line");
11809662Slinton     puts("trace <proc>           - trace calls to the procedure");
11819662Slinton     puts("trace <var>            - trace changes to the variable");
11829662Slinton     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
11839662Slinton     puts("status                 - print trace/stop's in effect");
11849662Slinton     puts("delete <number>        - remove trace or stop of given number");
1185*16608Ssam     puts("call <proc>            - call a procedure in program");
11869662Slinton     puts("whatis <name>          - print the declaration of the name");
11879662Slinton     puts("list <line>, <line>    - list source lines");
11889662Slinton     puts("gripe                  - send mail to the person in charge of dbx");
11899662Slinton     puts("quit                   - exit dbx");
11909662Slinton }
11919662Slinton 
11929662Slinton /*
11939662Slinton  * Divert output to the given file name.
11949662Slinton  * Cannot redirect to an existing file.
11959662Slinton  */
11969662Slinton 
11979662Slinton private int so_fd;
11989662Slinton private Boolean notstdout;
11999662Slinton 
12009662Slinton public setout(filename)
12019662Slinton String filename;
12029662Slinton {
12039662Slinton     File f;
12049662Slinton 
12059662Slinton     f = fopen(filename, "r");
12069662Slinton     if (f != nil) {
12079662Slinton 	fclose(f);
12089662Slinton 	error("%s: file already exists", filename);
12099662Slinton     } else {
12109662Slinton 	so_fd = dup(1);
12119662Slinton 	close(1);
12129662Slinton 	if (creat(filename, 0666) == nil) {
12139662Slinton 	    unsetout();
12149662Slinton 	    error("can't create %s", filename);
12159662Slinton 	}
12169662Slinton 	notstdout = true;
12179662Slinton     }
12189662Slinton }
12199662Slinton 
12209662Slinton /*
12219662Slinton  * Revert output to standard output.
12229662Slinton  */
12239662Slinton 
12249662Slinton public unsetout()
12259662Slinton {
12269662Slinton     fflush(stdout);
12279662Slinton     close(1);
12289662Slinton     if (dup(so_fd) != 1) {
12299662Slinton 	panic("standard out dup failed");
12309662Slinton     }
12319662Slinton     close(so_fd);
12329662Slinton     notstdout = false;
12339662Slinton }
12349662Slinton 
12359662Slinton /*
12369662Slinton  * Determine is standard output is currently being redirected
12379662Slinton  * to a file (as far as we know).
12389662Slinton  */
12399662Slinton 
12409662Slinton public Boolean isredirected()
12419662Slinton {
12429662Slinton     return notstdout;
12439662Slinton }
1244