xref: /csrg-svn/old/dbx/eval.c (revision 38105)
121601Sdist /*
2*38105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*38105Sbostic  * All rights reserved.
4*38105Sbostic  *
5*38105Sbostic  * Redistribution and use in source and binary forms are permitted
6*38105Sbostic  * provided that the above copyright notice and this paragraph are
7*38105Sbostic  * duplicated in all such forms and that any documentation,
8*38105Sbostic  * advertising materials, and other materials related to such
9*38105Sbostic  * distribution and use acknowledge that the software was developed
10*38105Sbostic  * by the University of California, Berkeley.  The name of the
11*38105Sbostic  * University may not be used to endorse or promote products derived
12*38105Sbostic  * from this software without specific prior written permission.
13*38105Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*38105Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*38105Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621601Sdist  */
179662Slinton 
1821601Sdist #ifndef lint
19*38105Sbostic static char sccsid[] = "@(#)eval.c	5.6 (Berkeley) 05/23/89";
20*38105Sbostic #endif /* not lint */
219662Slinton 
229662Slinton /*
239662Slinton  * Tree evaluation.
249662Slinton  */
259662Slinton 
269662Slinton #include "defs.h"
279662Slinton #include "tree.h"
289662Slinton #include "operators.h"
2918217Slinton #include "debug.h"
309662Slinton #include "eval.h"
319662Slinton #include "events.h"
329662Slinton #include "symbols.h"
339662Slinton #include "scanner.h"
349662Slinton #include "source.h"
359662Slinton #include "object.h"
369662Slinton #include "mappings.h"
379662Slinton #include "process.h"
3816608Ssam #include "runtime.h"
399662Slinton #include "machine.h"
409662Slinton #include <signal.h>
419662Slinton 
429662Slinton #ifndef public
439662Slinton 
449662Slinton #include "machine.h"
459662Slinton 
4612538Scsvaf #define STACKSIZE 20000
479662Slinton 
489662Slinton typedef Char Stack;
499662Slinton 
509662Slinton #define push(type, value) { \
519662Slinton     ((type *) (sp += sizeof(type)))[-1] = (value); \
529662Slinton }
539662Slinton 
549662Slinton #define pop(type) ( \
559662Slinton     (*((type *) (sp -= sizeof(type)))) \
569662Slinton )
579662Slinton 
5816608Ssam #define popn(n, dest) { \
5916608Ssam     sp -= n; \
6016608Ssam     bcopy(sp, dest, n); \
6116608Ssam }
6216608Ssam 
639662Slinton #define alignstack() { \
649662Slinton     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
659662Slinton }
669662Slinton 
679662Slinton #endif
689662Slinton 
699662Slinton public Stack stack[STACKSIZE];
709662Slinton public Stack *sp = &stack[0];
7114674Slinton public Boolean useInstLoc = false;
729662Slinton 
739662Slinton #define chksp() \
749662Slinton { \
759662Slinton     if (sp < &stack[0]) { \
769662Slinton 	panic("stack underflow"); \
779662Slinton     } \
789662Slinton }
799662Slinton 
809662Slinton #define poparg(n, r, fr) { \
819662Slinton     eval(p->value.arg[n]); \
829662Slinton     if (isreal(p->op)) { \
8316608Ssam 	if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
8416608Ssam 	    fr = pop(float); \
8516608Ssam 	} else { \
8616608Ssam 	    fr = pop(double); \
8716608Ssam 	} \
889662Slinton     } else if (isint(p->op)) { \
899662Slinton 	r = popsmall(p->value.arg[n]->nodetype); \
909662Slinton     } \
919662Slinton }
929662Slinton 
939662Slinton #define Boolrep char	/* underlying representation type for booleans */
949662Slinton 
959662Slinton /*
9618217Slinton  * Command-level evaluation.
9718217Slinton  */
9818217Slinton 
9918217Slinton public Node topnode;
10018217Slinton 
10118217Slinton public topeval (p)
10218217Slinton Node p;
10318217Slinton {
10418217Slinton     if (traceeval) {
10518217Slinton 	fprintf(stderr, "topeval(");
10618217Slinton 	prtree(stderr, p);
10718217Slinton 	fprintf(stderr, ")\n");
10818217Slinton 	fflush(stderr);
10918217Slinton     }
11018217Slinton     topnode = p;
11118217Slinton     eval(p);
11218217Slinton }
11318217Slinton 
11418217Slinton /*
1159662Slinton  * Evaluate a parse tree leaving the value on the top of the stack.
1169662Slinton  */
1179662Slinton 
1189662Slinton public eval(p)
1199662Slinton register Node p;
1209662Slinton {
1219662Slinton     long r0, r1;
1229662Slinton     double fr0, fr1;
1239662Slinton     Address addr;
1249662Slinton     long i, n;
1259662Slinton     int len;
12618217Slinton     Symbol s;
1279662Slinton     Node n1, n2;
12818217Slinton     boolean b;
1299662Slinton     File file;
13018217Slinton     String str;
1319662Slinton 
1329662Slinton     checkref(p);
13318217Slinton     if (traceeval) {
13418217Slinton 	fprintf(stderr, "begin eval %s\n", opname(p->op));
13512538Scsvaf     }
1369662Slinton     switch (degree(p->op)) {
1379662Slinton 	case BINARY:
1389662Slinton 	    poparg(1, r1, fr1);
1399662Slinton 	    poparg(0, r0, fr0);
1409662Slinton 	    break;
1419662Slinton 
1429662Slinton 	case UNARY:
1439662Slinton 	    poparg(0, r0, fr0);
1449662Slinton 	    break;
1459662Slinton 
1469662Slinton 	default:
1479662Slinton 	    /* do nothing */;
1489662Slinton     }
1499662Slinton     switch (p->op) {
1509662Slinton 	case O_SYM:
1519662Slinton 	    s = p->value.sym;
1529662Slinton 	    if (s == retaddrsym) {
1539662Slinton 		push(long, return_addr());
15418217Slinton 	    } else if (isvariable(s)) {
15518217Slinton 		if (s != program and not isactive(container(s))) {
15618217Slinton 		    error("\"%s\" is not active", symname(s));
15718217Slinton 		}
15818217Slinton 		if (isvarparam(s) and not isopenarray(s)) {
15918217Slinton 		    rpush(address(s, nil), sizeof(Address));
1609662Slinton 		} else {
16118217Slinton 		    push(Address, address(s, nil));
1629662Slinton 		}
16318217Slinton 	    } else if (isblock(s)) {
16418217Slinton 		push(Symbol, s);
16518217Slinton 	    } else if (isconst(s)) {
16618217Slinton 		eval(constval(s));
16718217Slinton 	    } else {
16818217Slinton 		error("can't evaluate a %s", classname(s));
1699662Slinton 	    }
1709662Slinton 	    break;
1719662Slinton 
1729662Slinton 	case O_LCON:
17318217Slinton 	case O_CCON:
1749662Slinton 	    r0 = p->value.lcon;
1759662Slinton 	    pushsmall(p->nodetype, r0);
1769662Slinton 	    break;
1779662Slinton 
1789662Slinton 	case O_FCON:
1799662Slinton 	    push(double, p->value.fcon);
1809662Slinton 	    break;
1819662Slinton 
1829662Slinton 	case O_SCON:
1839662Slinton 	    len = size(p->nodetype);
1849662Slinton 	    mov(p->value.scon, sp, len);
1859662Slinton 	    sp += len;
1869662Slinton 	    break;
1879662Slinton 
1889662Slinton 	case O_INDEX:
18918217Slinton 	    s = p->value.arg[0]->nodetype;
19018217Slinton 	    p->value.arg[0]->nodetype = t_addr;
19118217Slinton 	    eval(p->value.arg[0]);
19218217Slinton 	    p->value.arg[0]->nodetype = s;
19318217Slinton 	    n = pop(Address);
19418217Slinton 	    eval(p->value.arg[1]);
19518217Slinton 	    evalindex(s, n, popsmall(p->value.arg[1]->nodetype));
1969662Slinton 	    break;
1979662Slinton 
1989662Slinton 	case O_DOT:
1999662Slinton 	    s = p->value.arg[1]->value.sym;
20018217Slinton 	    eval(p->value.arg[0]);
20118217Slinton 	    n = pop(long);
2029662Slinton 	    push(long, n + (s->symvalue.field.offset div 8));
2039662Slinton 	    break;
2049662Slinton 
2059662Slinton 	/*
2069662Slinton 	 * Get the value of the expression addressed by the top of the stack.
2079662Slinton 	 * Push the result back on the stack.
2089662Slinton 	 */
2099662Slinton 
2109662Slinton 	case O_INDIR:
2119662Slinton 	case O_RVAL:
2129662Slinton 	    addr = pop(long);
2139662Slinton 	    if (addr == 0) {
2149662Slinton 		error("reference through nil pointer");
2159662Slinton 	    }
21618217Slinton 	    len = size(p->nodetype);
2179662Slinton 	    rpush(addr, len);
2189662Slinton 	    break;
2199662Slinton 
22011175Slinton 	case O_TYPERENAME:
22133315Sdonn 	    loophole(size(p->value.arg[0]->nodetype), size(p->nodetype));
22211175Slinton 	    break;
22311175Slinton 
2249662Slinton 	case O_COMMA:
22518217Slinton 	    eval(p->value.arg[0]);
22618217Slinton 	    if (p->value.arg[1] != nil) {
22718217Slinton 		eval(p->value.arg[1]);
22818217Slinton 	    }
2299662Slinton 	    break;
2309662Slinton 
2319662Slinton 	case O_ITOF:
2329662Slinton 	    push(double, (double) r0);
2339662Slinton 	    break;
2349662Slinton 
2359662Slinton 	case O_ADD:
2369662Slinton 	    push(long, r0+r1);
2379662Slinton 	    break;
2389662Slinton 
2399662Slinton 	case O_ADDF:
2409662Slinton 	    push(double, fr0+fr1);
2419662Slinton 	    break;
2429662Slinton 
2439662Slinton 	case O_SUB:
2449662Slinton 	    push(long, r0-r1);
2459662Slinton 	    break;
2469662Slinton 
2479662Slinton 	case O_SUBF:
2489662Slinton 	    push(double, fr0-fr1);
2499662Slinton 	    break;
2509662Slinton 
2519662Slinton 	case O_NEG:
2529662Slinton 	    push(long, -r0);
2539662Slinton 	    break;
2549662Slinton 
2559662Slinton 	case O_NEGF:
2569662Slinton 	    push(double, -fr0);
2579662Slinton 	    break;
2589662Slinton 
2599662Slinton 	case O_MUL:
2609662Slinton 	    push(long, r0*r1);
2619662Slinton 	    break;
2629662Slinton 
2639662Slinton 	case O_MULF:
2649662Slinton 	    push(double, fr0*fr1);
2659662Slinton 	    break;
2669662Slinton 
2679662Slinton 	case O_DIVF:
2689662Slinton 	    if (fr1 == 0) {
2699662Slinton 		error("error: division by 0");
2709662Slinton 	    }
2719662Slinton 	    push(double, fr0 / fr1);
2729662Slinton 	    break;
2739662Slinton 
2749662Slinton 	case O_DIV:
2759662Slinton 	    if (r1 == 0) {
2769662Slinton 		error("error: div by 0");
2779662Slinton 	    }
2789662Slinton 	    push(long, r0 div r1);
2799662Slinton 	    break;
2809662Slinton 
2819662Slinton 	case O_MOD:
2829662Slinton 	    if (r1 == 0) {
2839662Slinton 		error("error: mod by 0");
2849662Slinton 	    }
2859662Slinton 	    push(long, r0 mod r1);
2869662Slinton 	    break;
2879662Slinton 
2889662Slinton 	case O_LT:
2899662Slinton 	    push(Boolrep, r0 < r1);
2909662Slinton 	    break;
2919662Slinton 
2929662Slinton 	case O_LTF:
2939662Slinton 	    push(Boolrep, fr0 < fr1);
2949662Slinton 	    break;
2959662Slinton 
2969662Slinton 	case O_LE:
2979662Slinton 	    push(Boolrep, r0 <= r1);
2989662Slinton 	    break;
2999662Slinton 
3009662Slinton 	case O_LEF:
3019662Slinton 	    push(Boolrep, fr0 <= fr1);
3029662Slinton 	    break;
3039662Slinton 
3049662Slinton 	case O_GT:
3059662Slinton 	    push(Boolrep, r0 > r1);
3069662Slinton 	    break;
3079662Slinton 
3089662Slinton 	case O_GTF:
3099662Slinton 	    push(Boolrep, fr0 > fr1);
3109662Slinton 	    break;
3119662Slinton 
3129662Slinton 	case O_EQ:
3139662Slinton 	    push(Boolrep, r0 == r1);
3149662Slinton 	    break;
3159662Slinton 
3169662Slinton 	case O_EQF:
3179662Slinton 	    push(Boolrep, fr0 == fr1);
3189662Slinton 	    break;
3199662Slinton 
3209662Slinton 	case O_NE:
3219662Slinton 	    push(Boolrep, r0 != r1);
3229662Slinton 	    break;
3239662Slinton 
3249662Slinton 	case O_NEF:
3259662Slinton 	    push(Boolrep, fr0 != fr1);
3269662Slinton 	    break;
3279662Slinton 
3289662Slinton 	case O_AND:
3299662Slinton 	    push(Boolrep, r0 and r1);
3309662Slinton 	    break;
3319662Slinton 
3329662Slinton 	case O_OR:
3339662Slinton 	    push(Boolrep, r0 or r1);
3349662Slinton 	    break;
3359662Slinton 
3369662Slinton 	case O_ASSIGN:
3379662Slinton 	    assign(p->value.arg[0], p->value.arg[1]);
3389662Slinton 	    break;
3399662Slinton 
3409662Slinton 	case O_CHFILE:
3419662Slinton 	    if (p->value.scon == nil) {
3429662Slinton 		printf("%s\n", cursource);
3439662Slinton 	    } else {
3449662Slinton 		file = opensource(p->value.scon);
3459662Slinton 		if (file == nil) {
3469662Slinton 		    error("can't read \"%s\"", p->value.scon);
3479662Slinton 		} else {
3489662Slinton 		    fclose(file);
3499662Slinton 		    setsource(p->value.scon);
3509662Slinton 		}
3519662Slinton 	    }
3529662Slinton 	    break;
3539662Slinton 
3549662Slinton 	case O_CONT:
35511871Slinton 	    cont(p->value.lcon);
3569662Slinton 	    printnews();
3579662Slinton 	    break;
3589662Slinton 
3599662Slinton 	case O_LIST:
36018217Slinton 	    list(p);
3619662Slinton 	    break;
3629662Slinton 
3639662Slinton 	case O_FUNC:
36418217Slinton 	    func(p->value.arg[0]);
3659662Slinton 	    break;
3669662Slinton 
3679662Slinton 	case O_EXAMINE:
3689662Slinton 	    eval(p->value.examine.beginaddr);
3699662Slinton 	    r0 = pop(long);
3709662Slinton 	    if (p->value.examine.endaddr == nil) {
3719662Slinton 		n = p->value.examine.count;
37211175Slinton 		if (n == 0) {
37311175Slinton 		    printvalue(r0, p->value.examine.mode);
37411175Slinton 		} else if (streq(p->value.examine.mode, "i")) {
3759662Slinton 		    printninst(n, (Address) r0);
3769662Slinton 		} else {
3779662Slinton 		    printndata(n, (Address) r0, p->value.examine.mode);
3789662Slinton 		}
3799662Slinton 	    } else {
3809662Slinton 		eval(p->value.examine.endaddr);
3819662Slinton 		r1 = pop(long);
3829662Slinton 		if (streq(p->value.examine.mode, "i")) {
3839662Slinton 		    printinst((Address)r0, (Address)r1);
3849662Slinton 		} else {
3859662Slinton 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
3869662Slinton 		}
3879662Slinton 	    }
3889662Slinton 	    break;
3899662Slinton 
3909662Slinton 	case O_PRINT:
3919662Slinton 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
3929662Slinton 		eval(n1->value.arg[0]);
3939662Slinton 		printval(n1->value.arg[0]->nodetype);
3949662Slinton 		putchar(' ');
3959662Slinton 	    }
3969662Slinton 	    putchar('\n');
3979662Slinton 	    break;
3989662Slinton 
3999662Slinton 	case O_PSYM:
4009662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4019662Slinton 		psym(p->value.arg[0]->value.sym);
4029662Slinton 	    } else {
4039662Slinton 		psym(p->value.arg[0]->nodetype);
4049662Slinton 	    }
4059662Slinton 	    break;
4069662Slinton 
4079662Slinton 	case O_QLINE:
4089662Slinton 	    eval(p->value.arg[1]);
4099662Slinton 	    break;
4109662Slinton 
4119662Slinton 	case O_STEP:
4129662Slinton 	    b = inst_tracing;
4139662Slinton 	    inst_tracing = (Boolean) (not p->value.step.source);
4149662Slinton 	    if (p->value.step.skipcalls) {
4159662Slinton 		next();
4169662Slinton 	    } else {
4179662Slinton 		stepc();
4189662Slinton 	    }
4199662Slinton 	    inst_tracing = b;
42014674Slinton 	    useInstLoc = (Boolean) (not p->value.step.source);
4219662Slinton 	    printnews();
4229662Slinton 	    break;
4239662Slinton 
4249662Slinton 	case O_WHATIS:
4259662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4269662Slinton 		printdecl(p->value.arg[0]->value.sym);
4279662Slinton 	    } else {
4289662Slinton 		printdecl(p->value.arg[0]->nodetype);
4299662Slinton 	    }
4309662Slinton 	    break;
4319662Slinton 
4329662Slinton 	case O_WHERE:
4339662Slinton 	    wherecmd();
4349662Slinton 	    break;
4359662Slinton 
4369662Slinton 	case O_WHEREIS:
43712538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
43818217Slinton 		printwhereis(stdout, p->value.arg[0]->value.sym);
43912538Scsvaf 	    } else {
44018217Slinton 		printwhereis(stdout, p->value.arg[0]->nodetype);
44112538Scsvaf 	    }
4429662Slinton 	    break;
4439662Slinton 
4449662Slinton 	case O_WHICH:
44512538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
44618217Slinton 		printwhich(stdout, p->value.arg[0]->value.sym);
44712538Scsvaf 	    } else {
44818217Slinton 		printwhich(stdout, p->value.arg[0]->nodetype);
44912538Scsvaf 	    }
4509662Slinton 	    putchar('\n');
4519662Slinton 	    break;
4529662Slinton 
4539662Slinton 	case O_ALIAS:
4549662Slinton 	    n1 = p->value.arg[0];
4559662Slinton 	    n2 = p->value.arg[1];
45618217Slinton 	    if (n2 == nil) {
45718217Slinton 		if (n1 == nil) {
45818217Slinton 		    alias(nil, nil, nil);
45918217Slinton 		} else {
46018217Slinton 		    alias(n1->value.name, nil, nil);
46118217Slinton 		}
46218217Slinton 	    } else if (n2->op == O_NAME) {
46318217Slinton 		str = ident(n2->value.name);
46418217Slinton 		alias(n1->value.name, nil, strdup(str));
4659662Slinton 	    } else {
46618217Slinton 		if (n1->op == O_COMMA) {
46718217Slinton 		    alias(
46818217Slinton 			n1->value.arg[0]->value.name,
46918217Slinton 			(List) n1->value.arg[1],
47018217Slinton 			n2->value.scon
47118217Slinton 		    );
47218217Slinton 		} else {
47318217Slinton 		    alias(n1->value.name, nil, n2->value.scon);
47418217Slinton 		}
4759662Slinton 	    }
4769662Slinton 	    break;
4779662Slinton 
47818217Slinton 	case O_UNALIAS:
47918217Slinton 	    unalias(p->value.arg[0]->value.name);
48018217Slinton 	    break;
48118217Slinton 
48218217Slinton 	case O_CALLPROC:
48318217Slinton 	    callproc(p, false);
48418217Slinton 	    break;
48518217Slinton 
4869662Slinton 	case O_CALL:
48718217Slinton 	    callproc(p, true);
4889662Slinton 	    break;
4899662Slinton 
4909662Slinton 	case O_CATCH:
49118217Slinton 	    if (p->value.lcon == 0) {
49218217Slinton 		printsigscaught(process);
49318217Slinton 	    } else {
49418217Slinton 		psigtrace(process, p->value.lcon, true);
49518217Slinton 	    }
4969662Slinton 	    break;
4979662Slinton 
4989662Slinton 	case O_EDIT:
4999662Slinton 	    edit(p->value.scon);
5009662Slinton 	    break;
5019662Slinton 
50212538Scsvaf         case O_DEBUG:
50312538Scsvaf             debug(p);
50412538Scsvaf 	    break;
50512538Scsvaf 
50616608Ssam 	case O_DOWN:
50716608Ssam 	    checkref(p->value.arg[0]);
50816608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
50916608Ssam 	    down(p->value.arg[0]->value.lcon);
51016608Ssam 	    break;
51116608Ssam 
5129662Slinton 	case O_DUMP:
51318217Slinton 	    if (p->value.arg[0] == nil) {
51418217Slinton 		dumpall();
51518217Slinton 	    } else {
51618217Slinton 		s = p->value.arg[0]->value.sym;
51718217Slinton 		if (s == curfunc) {
51818217Slinton 		    dump(nil);
51918217Slinton 		} else {
52018217Slinton 		    dump(s);
52118217Slinton 		}
52218217Slinton 	    }
5239662Slinton 	    break;
5249662Slinton 
5259662Slinton 	case O_GRIPE:
5269662Slinton 	    gripe();
5279662Slinton 	    break;
5289662Slinton 
5299662Slinton 	case O_HELP:
5309662Slinton 	    help();
5319662Slinton 	    break;
5329662Slinton 
5339662Slinton 	case O_IGNORE:
53418217Slinton 	    if (p->value.lcon == 0) {
53518217Slinton 		printsigsignored(process);
53618217Slinton 	    } else {
53718217Slinton 		psigtrace(process, p->value.lcon, false);
53818217Slinton 	    }
5399662Slinton 	    break;
5409662Slinton 
54116608Ssam 	case O_RETURN:
54216608Ssam 	    if (p->value.arg[0] == nil) {
54316608Ssam 		rtnfunc(nil);
54416608Ssam 	    } else {
54516608Ssam 		assert(p->value.arg[0]->op == O_SYM);
54616608Ssam 		rtnfunc(p->value.arg[0]->value.sym);
54716608Ssam 	    }
54816608Ssam 	    break;
54916608Ssam 
5509662Slinton 	case O_RUN:
5519662Slinton 	    run();
5529662Slinton 	    break;
5539662Slinton 
55418217Slinton 	case O_SET:
55518217Slinton 	    set(p->value.arg[0], p->value.arg[1]);
55618217Slinton 	    break;
55718217Slinton 
55818217Slinton 	case O_SEARCH:
55918217Slinton 	    search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon);
56018217Slinton 	    break;
56118217Slinton 
5629662Slinton 	case O_SOURCE:
5639662Slinton 	    setinput(p->value.scon);
5649662Slinton 	    break;
5659662Slinton 
5669662Slinton 	case O_STATUS:
5679662Slinton 	    status();
5689662Slinton 	    break;
5699662Slinton 
5709662Slinton 	case O_TRACE:
5719662Slinton 	case O_TRACEI:
5729662Slinton 	    trace(p);
5739662Slinton 	    break;
5749662Slinton 
5759662Slinton 	case O_STOP:
5769662Slinton 	case O_STOPI:
5779662Slinton 	    stop(p);
5789662Slinton 	    break;
5799662Slinton 
58018217Slinton 	case O_UNSET:
58118217Slinton 	    undefvar(p->value.arg[0]->value.name);
58218217Slinton 	    break;
58318217Slinton 
58416608Ssam 	case O_UP:
58516608Ssam 	    checkref(p->value.arg[0]);
58616608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
58716608Ssam 	    up(p->value.arg[0]->value.lcon);
58816608Ssam 	    break;
58916608Ssam 
5909662Slinton 	case O_ADDEVENT:
5919662Slinton 	    addevent(p->value.event.cond, p->value.event.actions);
5929662Slinton 	    break;
5939662Slinton 
5949662Slinton 	case O_DELETE:
59516608Ssam 	    n1 = p->value.arg[0];
59616608Ssam 	    while (n1->op == O_COMMA) {
59716608Ssam 		n2 = n1->value.arg[0];
59816608Ssam 		assert(n2->op == O_LCON);
59916608Ssam 		if (not delevent((unsigned int) n2->value.lcon)) {
60016608Ssam 		    error("unknown event %ld", n2->value.lcon);
60116608Ssam 		}
60216608Ssam 		n1 = n1->value.arg[1];
60316608Ssam 	    }
60416608Ssam 	    assert(n1->op == O_LCON);
60516608Ssam 	    if (not delevent((unsigned int) n1->value.lcon)) {
60616608Ssam 		error("unknown event %ld", n1->value.lcon);
60716608Ssam 	    }
6089662Slinton 	    break;
6099662Slinton 
6109662Slinton 	case O_ENDX:
6119662Slinton 	    endprogram();
6129662Slinton 	    break;
6139662Slinton 
6149662Slinton 	case O_IF:
6159662Slinton 	    if (cond(p->value.event.cond)) {
6169662Slinton 		evalcmdlist(p->value.event.actions);
6179662Slinton 	    }
6189662Slinton 	    break;
6199662Slinton 
6209662Slinton 	case O_ONCE:
6219662Slinton 	    event_once(p->value.event.cond, p->value.event.actions);
6229662Slinton 	    break;
6239662Slinton 
6249662Slinton 	case O_PRINTCALL:
6259662Slinton 	    printcall(p->value.sym, whatblock(return_addr()));
6269662Slinton 	    break;
6279662Slinton 
6289662Slinton 	case O_PRINTIFCHANGED:
6299662Slinton 	    printifchanged(p->value.arg[0]);
6309662Slinton 	    break;
6319662Slinton 
6329662Slinton 	case O_PRINTRTN:
6339662Slinton 	    printrtn(p->value.sym);
6349662Slinton 	    break;
6359662Slinton 
6369662Slinton 	case O_PRINTSRCPOS:
6379662Slinton 	    getsrcpos();
6389662Slinton 	    if (p->value.arg[0] == nil) {
6399662Slinton 		printsrcpos();
6409662Slinton 		putchar('\n');
6419662Slinton 		printlines(curline, curline);
6429662Slinton 	    } else if (p->value.arg[0]->op == O_QLINE) {
6439662Slinton 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
6449662Slinton 		    printf("tracei: ");
6459662Slinton 		    printinst(pc, pc);
6469662Slinton 		} else {
64718217Slinton 		    if (canReadSource()) {
64818217Slinton 			printf("trace:  ");
64918217Slinton 			printlines(curline, curline);
65018217Slinton 		    }
6519662Slinton 		}
6529662Slinton 	    } else {
6539662Slinton 		printsrcpos();
6549662Slinton 		printf(": ");
6559662Slinton 		eval(p->value.arg[0]);
6569662Slinton 		prtree(stdout, p->value.arg[0]);
6579662Slinton 		printf(" = ");
6589662Slinton 		printval(p->value.arg[0]->nodetype);
6599662Slinton 		putchar('\n');
6609662Slinton 	    }
6619662Slinton 	    break;
6629662Slinton 
6639662Slinton 	case O_PROCRTN:
6649662Slinton 	    procreturn(p->value.sym);
6659662Slinton 	    break;
6669662Slinton 
6679662Slinton 	case O_STOPIFCHANGED:
6689662Slinton 	    stopifchanged(p->value.arg[0]);
6699662Slinton 	    break;
6709662Slinton 
6719662Slinton 	case O_STOPX:
6729662Slinton 	    isstopped = true;
6739662Slinton 	    break;
6749662Slinton 
6759662Slinton 	case O_TRACEON:
6769662Slinton 	    traceon(p->value.trace.inst, p->value.trace.event,
6779662Slinton 		p->value.trace.actions);
6789662Slinton 	    break;
6799662Slinton 
6809662Slinton 	case O_TRACEOFF:
6819662Slinton 	    traceoff(p->value.lcon);
6829662Slinton 	    break;
6839662Slinton 
6849662Slinton 	default:
6859662Slinton 	    panic("eval: bad op %d", p->op);
6869662Slinton     }
68718217Slinton     if (traceeval) {
68818217Slinton 	fprintf(stderr, "end eval %s\n", opname(p->op));
68918217Slinton     }
6909662Slinton }
6919662Slinton 
6929662Slinton /*
6939662Slinton  * Evaluate a list of commands.
6949662Slinton  */
6959662Slinton 
6969662Slinton public evalcmdlist(cl)
6979662Slinton Cmdlist cl;
6989662Slinton {
6999662Slinton     Command c;
7009662Slinton 
7019662Slinton     foreach (Command, c, cl)
7029662Slinton 	evalcmd(c);
7039662Slinton     endfor
7049662Slinton }
7059662Slinton 
7069662Slinton /*
7079662Slinton  * Push "len" bytes onto the expression stack from address "addr"
7089662Slinton  * in the process.  If there isn't room on the stack, print an error message.
7099662Slinton  */
7109662Slinton 
7119662Slinton public rpush(addr, len)
7129662Slinton Address addr;
7139662Slinton int len;
7149662Slinton {
7159662Slinton     if (not canpush(len)) {
7169662Slinton 	error("expression too large to evaluate");
7179662Slinton     } else {
7189662Slinton 	chksp();
7199662Slinton 	dread(sp, addr, len);
7209662Slinton 	sp += len;
7219662Slinton     }
7229662Slinton }
7239662Slinton 
7249662Slinton /*
7259662Slinton  * Check if the stack has n bytes available.
7269662Slinton  */
7279662Slinton 
7289662Slinton public Boolean canpush(n)
7299662Slinton Integer n;
7309662Slinton {
7319662Slinton     return (Boolean) (sp + n < &stack[STACKSIZE]);
7329662Slinton }
7339662Slinton 
7349662Slinton /*
7359662Slinton  * Push a small scalar of the given type onto the stack.
7369662Slinton  */
7379662Slinton 
7389662Slinton public pushsmall(t, v)
7399662Slinton Symbol t;
7409662Slinton long v;
7419662Slinton {
7429662Slinton     register Integer s;
7439662Slinton 
7449662Slinton     s = size(t);
7459662Slinton     switch (s) {
7469662Slinton 	case sizeof(char):
7479662Slinton 	    push(char, v);
7489662Slinton 	    break;
7499662Slinton 
7509662Slinton 	case sizeof(short):
7519662Slinton 	    push(short, v);
7529662Slinton 	    break;
7539662Slinton 
7549662Slinton 	case sizeof(long):
7559662Slinton 	    push(long, v);
7569662Slinton 	    break;
7579662Slinton 
7589662Slinton 	default:
7599662Slinton 	    panic("bad size %d in popsmall", s);
7609662Slinton     }
7619662Slinton }
7629662Slinton 
7639662Slinton /*
7649662Slinton  * Pop an item of the given type which is assumed to be no larger
7659662Slinton  * than a long and return it expanded into a long.
7669662Slinton  */
7679662Slinton 
7689662Slinton public long popsmall(t)
7699662Slinton Symbol t;
7709662Slinton {
77118217Slinton     register integer n;
7729662Slinton     long r;
7739662Slinton 
77418217Slinton     n = size(t);
77518217Slinton     if (n == sizeof(char)) {
77618217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
77718217Slinton 	    r = (long) pop(unsigned char);
77818217Slinton 	} else {
7799662Slinton 	    r = (long) pop(char);
78018217Slinton 	}
78118217Slinton     } else if (n == sizeof(short)) {
78218217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
78318217Slinton 	    r = (long) pop(unsigned short);
78418217Slinton 	} else {
7859662Slinton 	    r = (long) pop(short);
78618217Slinton 	}
78718217Slinton     } else if (n == sizeof(long)) {
78818217Slinton 	r = pop(long);
78918217Slinton     } else {
79018217Slinton 	error("[internal error: size %d in popsmall]", n);
7919662Slinton     }
7929662Slinton     return r;
7939662Slinton }
7949662Slinton 
7959662Slinton /*
7969662Slinton  * Evaluate a conditional expression.
7979662Slinton  */
7989662Slinton 
7999662Slinton public Boolean cond(p)
8009662Slinton Node p;
8019662Slinton {
80233315Sdonn     Boolean b;
80333315Sdonn     int i;
8049662Slinton 
8059662Slinton     if (p == nil) {
8069662Slinton 	b = true;
8079662Slinton     } else {
8089662Slinton 	eval(p);
80933315Sdonn 	i = pop(Boolrep);
81033315Sdonn 	b = (Boolean) i;
8119662Slinton     }
8129662Slinton     return b;
8139662Slinton }
8149662Slinton 
8159662Slinton /*
8169662Slinton  * Return the address corresponding to a given tree.
8179662Slinton  */
8189662Slinton 
8199662Slinton public Address lval(p)
8209662Slinton Node p;
8219662Slinton {
8229662Slinton     if (p->op == O_RVAL) {
8239662Slinton 	eval(p->value.arg[0]);
8249662Slinton     } else {
8259662Slinton 	eval(p);
8269662Slinton     }
8279662Slinton     return (Address) (pop(long));
8289662Slinton }
8299662Slinton 
8309662Slinton /*
8319662Slinton  * Process a trace command, translating into the appropriate events
8329662Slinton  * and associated actions.
8339662Slinton  */
8349662Slinton 
8359662Slinton public trace(p)
8369662Slinton Node p;
8379662Slinton {
8389662Slinton     Node exp, place, cond;
8399662Slinton     Node left;
8409662Slinton 
8419662Slinton     exp = p->value.arg[0];
8429662Slinton     place = p->value.arg[1];
8439662Slinton     cond = p->value.arg[2];
8449662Slinton     if (exp == nil) {
8459662Slinton 	traceall(p->op, place, cond);
84611771Slinton     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
8479662Slinton 	traceinst(p->op, exp, cond);
8489662Slinton     } else if (place != nil and place->op == O_QLINE) {
8499662Slinton 	traceat(p->op, exp, place, cond);
8509662Slinton     } else {
8519861Slinton 	left = exp;
8529861Slinton 	if (left->op == O_RVAL or left->op == O_CALL) {
8539861Slinton 	    left = left->value.arg[0];
8549861Slinton 	}
8559662Slinton 	if (left->op == O_SYM and isblock(left->value.sym)) {
8569662Slinton 	    traceproc(p->op, left->value.sym, place, cond);
8579662Slinton 	} else {
8589662Slinton 	    tracedata(p->op, exp, place, cond);
8599662Slinton 	}
8609662Slinton     }
8619662Slinton }
8629662Slinton 
8639662Slinton /*
8649662Slinton  * Set a breakpoint that will turn on tracing.
8659662Slinton  */
8669662Slinton 
8679662Slinton private traceall(op, place, cond)
8689662Slinton Operator op;
8699662Slinton Node place;
8709662Slinton Node cond;
8719662Slinton {
8729662Slinton     Symbol s;
8739662Slinton     Node event;
8749662Slinton     Command action;
8759662Slinton 
8769662Slinton     if (place == nil) {
8779662Slinton 	s = program;
8789662Slinton     } else {
8799662Slinton 	s = place->value.sym;
8809662Slinton     }
8819662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
8829662Slinton     action = build(O_PRINTSRCPOS,
8839662Slinton 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
8849662Slinton     if (cond != nil) {
8859662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8869662Slinton     }
8879662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
8889662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
88911871Slinton     if (isstdin()) {
89011871Slinton 	printevent(action->value.trace.event);
89111871Slinton     }
8929662Slinton }
8939662Slinton 
8949662Slinton /*
8959662Slinton  * Set up the appropriate breakpoint for tracing an instruction.
8969662Slinton  */
8979662Slinton 
8989662Slinton private traceinst(op, exp, cond)
8999662Slinton Operator op;
9009662Slinton Node exp;
9019662Slinton Node cond;
9029662Slinton {
90311771Slinton     Node event, wh;
9049662Slinton     Command action;
90511871Slinton     Event e;
9069662Slinton 
90711771Slinton     if (exp->op == O_LCON) {
90818217Slinton 	wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
90911771Slinton     } else {
91011771Slinton 	wh = exp;
91111771Slinton     }
9129662Slinton     if (op == O_TRACEI) {
91311771Slinton 	event = build(O_EQ, build(O_SYM, pcsym), wh);
9149662Slinton     } else {
91511771Slinton 	event = build(O_EQ, build(O_SYM, linesym), wh);
9169662Slinton     }
91711771Slinton     action = build(O_PRINTSRCPOS, wh);
9189662Slinton     if (cond) {
9199662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9209662Slinton     }
92111871Slinton     e = addevent(event, buildcmdlist(action));
92211871Slinton     if (isstdin()) {
92311871Slinton 	printevent(e);
92411871Slinton     }
9259662Slinton }
9269662Slinton 
9279662Slinton /*
9289662Slinton  * Set a breakpoint to print an expression at a given line or address.
9299662Slinton  */
9309662Slinton 
9319662Slinton private traceat(op, exp, place, cond)
9329662Slinton Operator op;
9339662Slinton Node exp;
9349662Slinton Node place;
9359662Slinton Node cond;
9369662Slinton {
9379662Slinton     Node event;
9389662Slinton     Command action;
93911871Slinton     Event e;
9409662Slinton 
9419662Slinton     if (op == O_TRACEI) {
9429662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
9439662Slinton     } else {
9449662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
9459662Slinton     }
9469662Slinton     action = build(O_PRINTSRCPOS, exp);
9479662Slinton     if (cond != nil) {
9489662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9499662Slinton     }
95011871Slinton     e = addevent(event, buildcmdlist(action));
95111871Slinton     if (isstdin()) {
95211871Slinton 	printevent(e);
95311871Slinton     }
9549662Slinton }
9559662Slinton 
9569662Slinton /*
9579662Slinton  * Construct event for tracing a procedure.
9589662Slinton  *
9599662Slinton  * What we want here is
9609662Slinton  *
9619662Slinton  * 	when $proc = p do
9629662Slinton  *	    if <condition> then
9639662Slinton  *	        printcall;
9649662Slinton  *	        once $pc = $retaddr do
9659662Slinton  *	            printrtn;
9669662Slinton  *	        end;
9679662Slinton  *	    end if;
9689662Slinton  *	end;
9699662Slinton  *
9709662Slinton  * Note that "once" is like "when" except that the event
9719662Slinton  * deletes itself as part of its associated action.
9729662Slinton  */
9739662Slinton 
9749662Slinton private traceproc(op, p, place, cond)
9759662Slinton Operator op;
9769662Slinton Symbol p;
9779662Slinton Node place;
9789662Slinton Node cond;
9799662Slinton {
9809662Slinton     Node event;
9819662Slinton     Command action;
9829662Slinton     Cmdlist actionlist;
98311871Slinton     Event e;
9849662Slinton 
9859662Slinton     action = build(O_PRINTCALL, p);
9869662Slinton     actionlist = list_alloc();
9879662Slinton     cmdlist_append(action, actionlist);
9889662Slinton     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
9899662Slinton     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
9909662Slinton     cmdlist_append(action, actionlist);
9919662Slinton     if (cond != nil) {
9929662Slinton 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
9939662Slinton     }
9949662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
99511871Slinton     e = addevent(event, actionlist);
99611871Slinton     if (isstdin()) {
99711871Slinton 	printevent(e);
99811871Slinton     }
9999662Slinton }
10009662Slinton 
10019662Slinton /*
10029662Slinton  * Set up breakpoint for tracing data.
10039662Slinton  */
10049662Slinton 
10059662Slinton private tracedata(op, exp, place, cond)
10069662Slinton Operator op;
10079662Slinton Node exp;
10089662Slinton Node place;
10099662Slinton Node cond;
10109662Slinton {
10119662Slinton     Symbol p;
10129662Slinton     Node event;
10139662Slinton     Command action;
10149662Slinton 
101533315Sdonn     if (size(exp->nodetype) > MAXTRSIZE) {
101633315Sdonn 	error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
101733315Sdonn     }
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 
111533315Sdonn     if (size(exp->nodetype) > MAXTRSIZE) {
111633315Sdonn 	error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
111733315Sdonn     }
111814445Slinton     if (place == nil) {
111914445Slinton 	if (exp->op == O_LCON) {
112014445Slinton 	    p = program;
112114445Slinton 	} else {
112214445Slinton 	    p = tcontainer(exp);
112314445Slinton 	    if (p == nil) {
112414445Slinton 		p = program;
112514445Slinton 	    }
112614445Slinton 	}
112714445Slinton     } else {
112814445Slinton 	p = place->value.sym;
11299662Slinton     }
113014445Slinton     action = build(O_STOPIFCHANGED, exp);
113114445Slinton     if (cond != nil) {
113214445Slinton 	action = build(O_IF, cond, buildcmdlist(action));
113314445Slinton     }
11349662Slinton     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
11359662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
11369662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
113711871Slinton     if (isstdin()) {
113811871Slinton 	printevent(action->value.trace.event);
113911871Slinton     }
11409662Slinton }
11419662Slinton 
11429662Slinton /*
11439662Slinton  * Assign the value of an expression to a variable (or term).
11449662Slinton  */
11459662Slinton 
11469662Slinton public assign(var, exp)
11479662Slinton Node var;
11489662Slinton Node exp;
11499662Slinton {
11509662Slinton     Address addr;
115116608Ssam     integer varsize, expsize;
11529662Slinton     char cvalue;
11539662Slinton     short svalue;
11549662Slinton     long lvalue;
115516608Ssam     float fvalue;
11569662Slinton 
115718217Slinton     if (var->op == O_SYM and regnum(var->value.sym) != -1) {
115818217Slinton 	eval(exp);
115918217Slinton 	setreg(regnum(var->value.sym), pop(Address));
116016608Ssam     } else {
116118217Slinton 	addr = lval(var);
116218217Slinton 	varsize = size(var->nodetype);
116318217Slinton 	expsize = size(exp->nodetype);
116418217Slinton 	eval(exp);
116518217Slinton 	if (varsize == sizeof(float) and expsize == sizeof(double)) {
116618217Slinton 	    fvalue = (float) pop(double);
116718217Slinton 	    dwrite(&fvalue, addr, sizeof(fvalue));
116818217Slinton 	} else {
116918217Slinton 	    if (varsize < sizeof(long)) {
117018217Slinton 		lvalue = 0;
117118217Slinton 		popn(expsize, &lvalue);
117218217Slinton 		if (varsize == sizeof(char)) {
117316608Ssam 		    cvalue = lvalue;
117416608Ssam 		    dwrite(&cvalue, addr, sizeof(cvalue));
117518217Slinton 		} else if (varsize == sizeof(short)) {
117616608Ssam 		    svalue = lvalue;
117716608Ssam 		    dwrite(&svalue, addr, sizeof(svalue));
117818217Slinton 		} else {
117918217Slinton 		    error("[internal error: bad size %d in assign]", varsize);
118018217Slinton 		}
118118217Slinton 	    } else {
118218217Slinton 		if (expsize <= varsize) {
118318217Slinton 		    sp -= expsize;
118418217Slinton 		    dwrite(sp, addr, expsize);
118518217Slinton 		} else {
118618217Slinton 		    sp -= expsize;
118718217Slinton 		    dwrite(sp, addr, varsize);
118818217Slinton 		}
118918217Slinton 	    }
119018217Slinton 	}
119118217Slinton     }
119218217Slinton }
11939662Slinton 
119418217Slinton /*
119518217Slinton  * Set a debugger variable.
119618217Slinton  */
119718217Slinton 
119818217Slinton private set (var, exp)
119918217Slinton Node var, exp;
120018217Slinton {
120118217Slinton     Symbol t;
120218217Slinton 
120318217Slinton     if (var == nil) {
120418217Slinton 	defvar(nil, nil);
120518217Slinton     } else if (exp == nil) {
120618217Slinton 	defvar(var->value.name, nil);
120718217Slinton     } else if (var->value.name == identname("$frame", true)) {
120818217Slinton 	t = exp->nodetype;
120918217Slinton 	if (not compatible(t, t_int) and not compatible(t, t_addr)) {
121018217Slinton 	    error("$frame must be an address");
121118217Slinton 	}
121218217Slinton 	eval(exp);
121318217Slinton 	getnewregs(pop(Address));
121418217Slinton     } else {
121518217Slinton 	defvar(var->value.name, unrval(exp));
121618217Slinton     }
121718217Slinton }
121818217Slinton 
121918217Slinton /*
122018217Slinton  * Execute a list command.
122118217Slinton  */
122218217Slinton 
122318217Slinton private list (p)
122418217Slinton Node p;
122518217Slinton {
122618217Slinton     Symbol f;
122718217Slinton     Address addr;
122818217Slinton     Lineno line, l1, l2;
122918217Slinton 
123018217Slinton     if (p->value.arg[0]->op == O_SYM) {
123118217Slinton 	f = p->value.arg[0]->value.sym;
123218217Slinton 	addr = firstline(f);
123318217Slinton 	if (addr == NOADDR) {
123418217Slinton 	    error("no source lines for \"%s\"", symname(f));
123518217Slinton 	}
123618217Slinton 	setsource(srcfilename(addr));
123718217Slinton 	line = srcline(addr);
123818217Slinton 	getsrcwindow(line, &l1, &l2);
123918217Slinton     } else {
124018217Slinton 	eval(p->value.arg[0]);
124118217Slinton 	l1 = (Lineno) (pop(long));
124218217Slinton 	eval(p->value.arg[1]);
124318217Slinton 	l2 = (Lineno) (pop(long));
124418217Slinton     }
124518217Slinton     printlines(l1, l2);
124618217Slinton }
124718217Slinton 
124818217Slinton /*
124918217Slinton  * Execute a func command.
125018217Slinton  */
125118217Slinton 
125218217Slinton private func (p)
125318217Slinton Node p;
125418217Slinton {
125518217Slinton     Symbol s, f;
125618217Slinton     Address addr;
125718217Slinton 
125818217Slinton     if (p == nil) {
125918217Slinton 	printname(stdout, curfunc);
126018217Slinton 	putchar('\n');
126118217Slinton     } else {
126218217Slinton 	s = p->value.sym;
126318217Slinton 	if (isroutine(s)) {
126418217Slinton 	    setcurfunc(s);
126516608Ssam 	} else {
126618217Slinton 	    find(f, s->name) where isroutine(f) endfind(f);
126718217Slinton 	    if (f == nil) {
126818217Slinton 		error("%s is not a procedure or function", symname(s));
126916608Ssam 	    }
127018217Slinton 	    setcurfunc(f);
12719662Slinton 	}
127218217Slinton 	addr = codeloc(curfunc);
127318217Slinton 	if (addr != NOADDR) {
127418217Slinton 	    setsource(srcfilename(addr));
127518217Slinton 	    cursrcline = srcline(addr);
127618217Slinton 	}
12779662Slinton     }
12789662Slinton }
12799662Slinton 
12809662Slinton /*
128118217Slinton  * Send a message to the current support person.
12829662Slinton  */
12839662Slinton 
12849662Slinton public gripe()
12859662Slinton {
12869662Slinton     typedef Operation();
12879662Slinton     Operation *old;
128814445Slinton     int pid, status;
128916608Ssam     extern int versionNumber;
129016608Ssam     char subject[100];
12919662Slinton 
129233315Sdonn #   ifdef MAINTAINER
129333315Sdonn 	puts("Type control-D to end your message.  Be sure to include");
129433315Sdonn 	puts("your name and the name of the file you are debugging.");
129533315Sdonn 	putchar('\n');
129633315Sdonn 	old = signal(SIGINT, SIG_DFL);
129733315Sdonn 	sprintf(subject, "dbx (version 3.%d) gripe", versionNumber);
129833315Sdonn 	pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil);
129933315Sdonn 	signal(SIGINT, SIG_IGN);
130033315Sdonn 	pwait(pid, &status);
130133315Sdonn 	signal(SIGINT, old);
130233315Sdonn 	if (status == 0) {
130333315Sdonn 	    puts("Thank you.");
130433315Sdonn 	} else {
130533315Sdonn 	    puts("\nMail not sent.");
130633315Sdonn 	}
130733315Sdonn #   else
130833315Sdonn 	puts("Sorry, no dbx maintainer available to gripe to.");
130933315Sdonn 	puts("Try contacting your system manager.");
131033315Sdonn #   endif
13119662Slinton }
13129662Slinton 
13139662Slinton /*
13149662Slinton  * Give the user some help.
13159662Slinton  */
13169662Slinton 
13179662Slinton public help()
13189662Slinton {
13199662Slinton     puts("run                    - begin execution of the program");
132016608Ssam     puts("print <exp>            - print the value of the expression");
132116608Ssam     puts("where                  - print currently active procedures");
132216608Ssam     puts("stop at <line>         - suspend execution at the line");
132316608Ssam     puts("stop in <proc>         - suspend execution when <proc> is called");
13249662Slinton     puts("cont                   - continue execution");
13259662Slinton     puts("step                   - single step one line");
13269662Slinton     puts("next                   - step to next line (skip over calls)");
13279662Slinton     puts("trace <line#>          - trace execution of the line");
13289662Slinton     puts("trace <proc>           - trace calls to the procedure");
13299662Slinton     puts("trace <var>            - trace changes to the variable");
13309662Slinton     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
13319662Slinton     puts("status                 - print trace/stop's in effect");
13329662Slinton     puts("delete <number>        - remove trace or stop of given number");
133316608Ssam     puts("call <proc>            - call a procedure in program");
13349662Slinton     puts("whatis <name>          - print the declaration of the name");
13359662Slinton     puts("list <line>, <line>    - list source lines");
13369662Slinton     puts("gripe                  - send mail to the person in charge of dbx");
13379662Slinton     puts("quit                   - exit dbx");
13389662Slinton }
13399662Slinton 
13409662Slinton /*
13419662Slinton  * Divert output to the given file name.
13429662Slinton  * Cannot redirect to an existing file.
13439662Slinton  */
13449662Slinton 
13459662Slinton private int so_fd;
13469662Slinton private Boolean notstdout;
13479662Slinton 
13489662Slinton public setout(filename)
13499662Slinton String filename;
13509662Slinton {
13519662Slinton     File f;
13529662Slinton 
13539662Slinton     f = fopen(filename, "r");
13549662Slinton     if (f != nil) {
13559662Slinton 	fclose(f);
13569662Slinton 	error("%s: file already exists", filename);
13579662Slinton     } else {
13589662Slinton 	so_fd = dup(1);
13599662Slinton 	close(1);
13609662Slinton 	if (creat(filename, 0666) == nil) {
13619662Slinton 	    unsetout();
13629662Slinton 	    error("can't create %s", filename);
13639662Slinton 	}
13649662Slinton 	notstdout = true;
13659662Slinton     }
13669662Slinton }
13679662Slinton 
13689662Slinton /*
13699662Slinton  * Revert output to standard output.
13709662Slinton  */
13719662Slinton 
13729662Slinton public unsetout()
13739662Slinton {
13749662Slinton     fflush(stdout);
13759662Slinton     close(1);
13769662Slinton     if (dup(so_fd) != 1) {
13779662Slinton 	panic("standard out dup failed");
13789662Slinton     }
13799662Slinton     close(so_fd);
13809662Slinton     notstdout = false;
13819662Slinton }
13829662Slinton 
13839662Slinton /*
13849662Slinton  * Determine is standard output is currently being redirected
13859662Slinton  * to a file (as far as we know).
13869662Slinton  */
13879662Slinton 
13889662Slinton public Boolean isredirected()
13899662Slinton {
13909662Slinton     return notstdout;
13919662Slinton }
1392