xref: /csrg-svn/old/dbx/eval.c (revision 38105)
1 /*
2  * Copyright (c) 1983 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)eval.c	5.6 (Berkeley) 05/23/89";
20 #endif /* not lint */
21 
22 /*
23  * Tree evaluation.
24  */
25 
26 #include "defs.h"
27 #include "tree.h"
28 #include "operators.h"
29 #include "debug.h"
30 #include "eval.h"
31 #include "events.h"
32 #include "symbols.h"
33 #include "scanner.h"
34 #include "source.h"
35 #include "object.h"
36 #include "mappings.h"
37 #include "process.h"
38 #include "runtime.h"
39 #include "machine.h"
40 #include <signal.h>
41 
42 #ifndef public
43 
44 #include "machine.h"
45 
46 #define STACKSIZE 20000
47 
48 typedef Char Stack;
49 
50 #define push(type, value) { \
51     ((type *) (sp += sizeof(type)))[-1] = (value); \
52 }
53 
54 #define pop(type) ( \
55     (*((type *) (sp -= sizeof(type)))) \
56 )
57 
58 #define popn(n, dest) { \
59     sp -= n; \
60     bcopy(sp, dest, n); \
61 }
62 
63 #define alignstack() { \
64     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
65 }
66 
67 #endif
68 
69 public Stack stack[STACKSIZE];
70 public Stack *sp = &stack[0];
71 public Boolean useInstLoc = false;
72 
73 #define chksp() \
74 { \
75     if (sp < &stack[0]) { \
76 	panic("stack underflow"); \
77     } \
78 }
79 
80 #define poparg(n, r, fr) { \
81     eval(p->value.arg[n]); \
82     if (isreal(p->op)) { \
83 	if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
84 	    fr = pop(float); \
85 	} else { \
86 	    fr = pop(double); \
87 	} \
88     } else if (isint(p->op)) { \
89 	r = popsmall(p->value.arg[n]->nodetype); \
90     } \
91 }
92 
93 #define Boolrep char	/* underlying representation type for booleans */
94 
95 /*
96  * Command-level evaluation.
97  */
98 
99 public Node topnode;
100 
101 public topeval (p)
102 Node p;
103 {
104     if (traceeval) {
105 	fprintf(stderr, "topeval(");
106 	prtree(stderr, p);
107 	fprintf(stderr, ")\n");
108 	fflush(stderr);
109     }
110     topnode = p;
111     eval(p);
112 }
113 
114 /*
115  * Evaluate a parse tree leaving the value on the top of the stack.
116  */
117 
118 public eval(p)
119 register Node p;
120 {
121     long r0, r1;
122     double fr0, fr1;
123     Address addr;
124     long i, n;
125     int len;
126     Symbol s;
127     Node n1, n2;
128     boolean b;
129     File file;
130     String str;
131 
132     checkref(p);
133     if (traceeval) {
134 	fprintf(stderr, "begin eval %s\n", opname(p->op));
135     }
136     switch (degree(p->op)) {
137 	case BINARY:
138 	    poparg(1, r1, fr1);
139 	    poparg(0, r0, fr0);
140 	    break;
141 
142 	case UNARY:
143 	    poparg(0, r0, fr0);
144 	    break;
145 
146 	default:
147 	    /* do nothing */;
148     }
149     switch (p->op) {
150 	case O_SYM:
151 	    s = p->value.sym;
152 	    if (s == retaddrsym) {
153 		push(long, return_addr());
154 	    } else if (isvariable(s)) {
155 		if (s != program and not isactive(container(s))) {
156 		    error("\"%s\" is not active", symname(s));
157 		}
158 		if (isvarparam(s) and not isopenarray(s)) {
159 		    rpush(address(s, nil), sizeof(Address));
160 		} else {
161 		    push(Address, address(s, nil));
162 		}
163 	    } else if (isblock(s)) {
164 		push(Symbol, s);
165 	    } else if (isconst(s)) {
166 		eval(constval(s));
167 	    } else {
168 		error("can't evaluate a %s", classname(s));
169 	    }
170 	    break;
171 
172 	case O_LCON:
173 	case O_CCON:
174 	    r0 = p->value.lcon;
175 	    pushsmall(p->nodetype, r0);
176 	    break;
177 
178 	case O_FCON:
179 	    push(double, p->value.fcon);
180 	    break;
181 
182 	case O_SCON:
183 	    len = size(p->nodetype);
184 	    mov(p->value.scon, sp, len);
185 	    sp += len;
186 	    break;
187 
188 	case O_INDEX:
189 	    s = p->value.arg[0]->nodetype;
190 	    p->value.arg[0]->nodetype = t_addr;
191 	    eval(p->value.arg[0]);
192 	    p->value.arg[0]->nodetype = s;
193 	    n = pop(Address);
194 	    eval(p->value.arg[1]);
195 	    evalindex(s, n, popsmall(p->value.arg[1]->nodetype));
196 	    break;
197 
198 	case O_DOT:
199 	    s = p->value.arg[1]->value.sym;
200 	    eval(p->value.arg[0]);
201 	    n = pop(long);
202 	    push(long, n + (s->symvalue.field.offset div 8));
203 	    break;
204 
205 	/*
206 	 * Get the value of the expression addressed by the top of the stack.
207 	 * Push the result back on the stack.
208 	 */
209 
210 	case O_INDIR:
211 	case O_RVAL:
212 	    addr = pop(long);
213 	    if (addr == 0) {
214 		error("reference through nil pointer");
215 	    }
216 	    len = size(p->nodetype);
217 	    rpush(addr, len);
218 	    break;
219 
220 	case O_TYPERENAME:
221 	    loophole(size(p->value.arg[0]->nodetype), size(p->nodetype));
222 	    break;
223 
224 	case O_COMMA:
225 	    eval(p->value.arg[0]);
226 	    if (p->value.arg[1] != nil) {
227 		eval(p->value.arg[1]);
228 	    }
229 	    break;
230 
231 	case O_ITOF:
232 	    push(double, (double) r0);
233 	    break;
234 
235 	case O_ADD:
236 	    push(long, r0+r1);
237 	    break;
238 
239 	case O_ADDF:
240 	    push(double, fr0+fr1);
241 	    break;
242 
243 	case O_SUB:
244 	    push(long, r0-r1);
245 	    break;
246 
247 	case O_SUBF:
248 	    push(double, fr0-fr1);
249 	    break;
250 
251 	case O_NEG:
252 	    push(long, -r0);
253 	    break;
254 
255 	case O_NEGF:
256 	    push(double, -fr0);
257 	    break;
258 
259 	case O_MUL:
260 	    push(long, r0*r1);
261 	    break;
262 
263 	case O_MULF:
264 	    push(double, fr0*fr1);
265 	    break;
266 
267 	case O_DIVF:
268 	    if (fr1 == 0) {
269 		error("error: division by 0");
270 	    }
271 	    push(double, fr0 / fr1);
272 	    break;
273 
274 	case O_DIV:
275 	    if (r1 == 0) {
276 		error("error: div by 0");
277 	    }
278 	    push(long, r0 div r1);
279 	    break;
280 
281 	case O_MOD:
282 	    if (r1 == 0) {
283 		error("error: mod by 0");
284 	    }
285 	    push(long, r0 mod r1);
286 	    break;
287 
288 	case O_LT:
289 	    push(Boolrep, r0 < r1);
290 	    break;
291 
292 	case O_LTF:
293 	    push(Boolrep, fr0 < fr1);
294 	    break;
295 
296 	case O_LE:
297 	    push(Boolrep, r0 <= r1);
298 	    break;
299 
300 	case O_LEF:
301 	    push(Boolrep, fr0 <= fr1);
302 	    break;
303 
304 	case O_GT:
305 	    push(Boolrep, r0 > r1);
306 	    break;
307 
308 	case O_GTF:
309 	    push(Boolrep, fr0 > fr1);
310 	    break;
311 
312 	case O_EQ:
313 	    push(Boolrep, r0 == r1);
314 	    break;
315 
316 	case O_EQF:
317 	    push(Boolrep, fr0 == fr1);
318 	    break;
319 
320 	case O_NE:
321 	    push(Boolrep, r0 != r1);
322 	    break;
323 
324 	case O_NEF:
325 	    push(Boolrep, fr0 != fr1);
326 	    break;
327 
328 	case O_AND:
329 	    push(Boolrep, r0 and r1);
330 	    break;
331 
332 	case O_OR:
333 	    push(Boolrep, r0 or r1);
334 	    break;
335 
336 	case O_ASSIGN:
337 	    assign(p->value.arg[0], p->value.arg[1]);
338 	    break;
339 
340 	case O_CHFILE:
341 	    if (p->value.scon == nil) {
342 		printf("%s\n", cursource);
343 	    } else {
344 		file = opensource(p->value.scon);
345 		if (file == nil) {
346 		    error("can't read \"%s\"", p->value.scon);
347 		} else {
348 		    fclose(file);
349 		    setsource(p->value.scon);
350 		}
351 	    }
352 	    break;
353 
354 	case O_CONT:
355 	    cont(p->value.lcon);
356 	    printnews();
357 	    break;
358 
359 	case O_LIST:
360 	    list(p);
361 	    break;
362 
363 	case O_FUNC:
364 	    func(p->value.arg[0]);
365 	    break;
366 
367 	case O_EXAMINE:
368 	    eval(p->value.examine.beginaddr);
369 	    r0 = pop(long);
370 	    if (p->value.examine.endaddr == nil) {
371 		n = p->value.examine.count;
372 		if (n == 0) {
373 		    printvalue(r0, p->value.examine.mode);
374 		} else if (streq(p->value.examine.mode, "i")) {
375 		    printninst(n, (Address) r0);
376 		} else {
377 		    printndata(n, (Address) r0, p->value.examine.mode);
378 		}
379 	    } else {
380 		eval(p->value.examine.endaddr);
381 		r1 = pop(long);
382 		if (streq(p->value.examine.mode, "i")) {
383 		    printinst((Address)r0, (Address)r1);
384 		} else {
385 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
386 		}
387 	    }
388 	    break;
389 
390 	case O_PRINT:
391 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
392 		eval(n1->value.arg[0]);
393 		printval(n1->value.arg[0]->nodetype);
394 		putchar(' ');
395 	    }
396 	    putchar('\n');
397 	    break;
398 
399 	case O_PSYM:
400 	    if (p->value.arg[0]->op == O_SYM) {
401 		psym(p->value.arg[0]->value.sym);
402 	    } else {
403 		psym(p->value.arg[0]->nodetype);
404 	    }
405 	    break;
406 
407 	case O_QLINE:
408 	    eval(p->value.arg[1]);
409 	    break;
410 
411 	case O_STEP:
412 	    b = inst_tracing;
413 	    inst_tracing = (Boolean) (not p->value.step.source);
414 	    if (p->value.step.skipcalls) {
415 		next();
416 	    } else {
417 		stepc();
418 	    }
419 	    inst_tracing = b;
420 	    useInstLoc = (Boolean) (not p->value.step.source);
421 	    printnews();
422 	    break;
423 
424 	case O_WHATIS:
425 	    if (p->value.arg[0]->op == O_SYM) {
426 		printdecl(p->value.arg[0]->value.sym);
427 	    } else {
428 		printdecl(p->value.arg[0]->nodetype);
429 	    }
430 	    break;
431 
432 	case O_WHERE:
433 	    wherecmd();
434 	    break;
435 
436 	case O_WHEREIS:
437 	    if (p->value.arg[0]->op == O_SYM) {
438 		printwhereis(stdout, p->value.arg[0]->value.sym);
439 	    } else {
440 		printwhereis(stdout, p->value.arg[0]->nodetype);
441 	    }
442 	    break;
443 
444 	case O_WHICH:
445 	    if (p->value.arg[0]->op == O_SYM) {
446 		printwhich(stdout, p->value.arg[0]->value.sym);
447 	    } else {
448 		printwhich(stdout, p->value.arg[0]->nodetype);
449 	    }
450 	    putchar('\n');
451 	    break;
452 
453 	case O_ALIAS:
454 	    n1 = p->value.arg[0];
455 	    n2 = p->value.arg[1];
456 	    if (n2 == nil) {
457 		if (n1 == nil) {
458 		    alias(nil, nil, nil);
459 		} else {
460 		    alias(n1->value.name, nil, nil);
461 		}
462 	    } else if (n2->op == O_NAME) {
463 		str = ident(n2->value.name);
464 		alias(n1->value.name, nil, strdup(str));
465 	    } else {
466 		if (n1->op == O_COMMA) {
467 		    alias(
468 			n1->value.arg[0]->value.name,
469 			(List) n1->value.arg[1],
470 			n2->value.scon
471 		    );
472 		} else {
473 		    alias(n1->value.name, nil, n2->value.scon);
474 		}
475 	    }
476 	    break;
477 
478 	case O_UNALIAS:
479 	    unalias(p->value.arg[0]->value.name);
480 	    break;
481 
482 	case O_CALLPROC:
483 	    callproc(p, false);
484 	    break;
485 
486 	case O_CALL:
487 	    callproc(p, true);
488 	    break;
489 
490 	case O_CATCH:
491 	    if (p->value.lcon == 0) {
492 		printsigscaught(process);
493 	    } else {
494 		psigtrace(process, p->value.lcon, true);
495 	    }
496 	    break;
497 
498 	case O_EDIT:
499 	    edit(p->value.scon);
500 	    break;
501 
502         case O_DEBUG:
503             debug(p);
504 	    break;
505 
506 	case O_DOWN:
507 	    checkref(p->value.arg[0]);
508 	    assert(p->value.arg[0]->op == O_LCON);
509 	    down(p->value.arg[0]->value.lcon);
510 	    break;
511 
512 	case O_DUMP:
513 	    if (p->value.arg[0] == nil) {
514 		dumpall();
515 	    } else {
516 		s = p->value.arg[0]->value.sym;
517 		if (s == curfunc) {
518 		    dump(nil);
519 		} else {
520 		    dump(s);
521 		}
522 	    }
523 	    break;
524 
525 	case O_GRIPE:
526 	    gripe();
527 	    break;
528 
529 	case O_HELP:
530 	    help();
531 	    break;
532 
533 	case O_IGNORE:
534 	    if (p->value.lcon == 0) {
535 		printsigsignored(process);
536 	    } else {
537 		psigtrace(process, p->value.lcon, false);
538 	    }
539 	    break;
540 
541 	case O_RETURN:
542 	    if (p->value.arg[0] == nil) {
543 		rtnfunc(nil);
544 	    } else {
545 		assert(p->value.arg[0]->op == O_SYM);
546 		rtnfunc(p->value.arg[0]->value.sym);
547 	    }
548 	    break;
549 
550 	case O_RUN:
551 	    run();
552 	    break;
553 
554 	case O_SET:
555 	    set(p->value.arg[0], p->value.arg[1]);
556 	    break;
557 
558 	case O_SEARCH:
559 	    search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon);
560 	    break;
561 
562 	case O_SOURCE:
563 	    setinput(p->value.scon);
564 	    break;
565 
566 	case O_STATUS:
567 	    status();
568 	    break;
569 
570 	case O_TRACE:
571 	case O_TRACEI:
572 	    trace(p);
573 	    break;
574 
575 	case O_STOP:
576 	case O_STOPI:
577 	    stop(p);
578 	    break;
579 
580 	case O_UNSET:
581 	    undefvar(p->value.arg[0]->value.name);
582 	    break;
583 
584 	case O_UP:
585 	    checkref(p->value.arg[0]);
586 	    assert(p->value.arg[0]->op == O_LCON);
587 	    up(p->value.arg[0]->value.lcon);
588 	    break;
589 
590 	case O_ADDEVENT:
591 	    addevent(p->value.event.cond, p->value.event.actions);
592 	    break;
593 
594 	case O_DELETE:
595 	    n1 = p->value.arg[0];
596 	    while (n1->op == O_COMMA) {
597 		n2 = n1->value.arg[0];
598 		assert(n2->op == O_LCON);
599 		if (not delevent((unsigned int) n2->value.lcon)) {
600 		    error("unknown event %ld", n2->value.lcon);
601 		}
602 		n1 = n1->value.arg[1];
603 	    }
604 	    assert(n1->op == O_LCON);
605 	    if (not delevent((unsigned int) n1->value.lcon)) {
606 		error("unknown event %ld", n1->value.lcon);
607 	    }
608 	    break;
609 
610 	case O_ENDX:
611 	    endprogram();
612 	    break;
613 
614 	case O_IF:
615 	    if (cond(p->value.event.cond)) {
616 		evalcmdlist(p->value.event.actions);
617 	    }
618 	    break;
619 
620 	case O_ONCE:
621 	    event_once(p->value.event.cond, p->value.event.actions);
622 	    break;
623 
624 	case O_PRINTCALL:
625 	    printcall(p->value.sym, whatblock(return_addr()));
626 	    break;
627 
628 	case O_PRINTIFCHANGED:
629 	    printifchanged(p->value.arg[0]);
630 	    break;
631 
632 	case O_PRINTRTN:
633 	    printrtn(p->value.sym);
634 	    break;
635 
636 	case O_PRINTSRCPOS:
637 	    getsrcpos();
638 	    if (p->value.arg[0] == nil) {
639 		printsrcpos();
640 		putchar('\n');
641 		printlines(curline, curline);
642 	    } else if (p->value.arg[0]->op == O_QLINE) {
643 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
644 		    printf("tracei: ");
645 		    printinst(pc, pc);
646 		} else {
647 		    if (canReadSource()) {
648 			printf("trace:  ");
649 			printlines(curline, curline);
650 		    }
651 		}
652 	    } else {
653 		printsrcpos();
654 		printf(": ");
655 		eval(p->value.arg[0]);
656 		prtree(stdout, p->value.arg[0]);
657 		printf(" = ");
658 		printval(p->value.arg[0]->nodetype);
659 		putchar('\n');
660 	    }
661 	    break;
662 
663 	case O_PROCRTN:
664 	    procreturn(p->value.sym);
665 	    break;
666 
667 	case O_STOPIFCHANGED:
668 	    stopifchanged(p->value.arg[0]);
669 	    break;
670 
671 	case O_STOPX:
672 	    isstopped = true;
673 	    break;
674 
675 	case O_TRACEON:
676 	    traceon(p->value.trace.inst, p->value.trace.event,
677 		p->value.trace.actions);
678 	    break;
679 
680 	case O_TRACEOFF:
681 	    traceoff(p->value.lcon);
682 	    break;
683 
684 	default:
685 	    panic("eval: bad op %d", p->op);
686     }
687     if (traceeval) {
688 	fprintf(stderr, "end eval %s\n", opname(p->op));
689     }
690 }
691 
692 /*
693  * Evaluate a list of commands.
694  */
695 
696 public evalcmdlist(cl)
697 Cmdlist cl;
698 {
699     Command c;
700 
701     foreach (Command, c, cl)
702 	evalcmd(c);
703     endfor
704 }
705 
706 /*
707  * Push "len" bytes onto the expression stack from address "addr"
708  * in the process.  If there isn't room on the stack, print an error message.
709  */
710 
711 public rpush(addr, len)
712 Address addr;
713 int len;
714 {
715     if (not canpush(len)) {
716 	error("expression too large to evaluate");
717     } else {
718 	chksp();
719 	dread(sp, addr, len);
720 	sp += len;
721     }
722 }
723 
724 /*
725  * Check if the stack has n bytes available.
726  */
727 
728 public Boolean canpush(n)
729 Integer n;
730 {
731     return (Boolean) (sp + n < &stack[STACKSIZE]);
732 }
733 
734 /*
735  * Push a small scalar of the given type onto the stack.
736  */
737 
738 public pushsmall(t, v)
739 Symbol t;
740 long v;
741 {
742     register Integer s;
743 
744     s = size(t);
745     switch (s) {
746 	case sizeof(char):
747 	    push(char, v);
748 	    break;
749 
750 	case sizeof(short):
751 	    push(short, v);
752 	    break;
753 
754 	case sizeof(long):
755 	    push(long, v);
756 	    break;
757 
758 	default:
759 	    panic("bad size %d in popsmall", s);
760     }
761 }
762 
763 /*
764  * Pop an item of the given type which is assumed to be no larger
765  * than a long and return it expanded into a long.
766  */
767 
768 public long popsmall(t)
769 Symbol t;
770 {
771     register integer n;
772     long r;
773 
774     n = size(t);
775     if (n == sizeof(char)) {
776 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
777 	    r = (long) pop(unsigned char);
778 	} else {
779 	    r = (long) pop(char);
780 	}
781     } else if (n == sizeof(short)) {
782 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
783 	    r = (long) pop(unsigned short);
784 	} else {
785 	    r = (long) pop(short);
786 	}
787     } else if (n == sizeof(long)) {
788 	r = pop(long);
789     } else {
790 	error("[internal error: size %d in popsmall]", n);
791     }
792     return r;
793 }
794 
795 /*
796  * Evaluate a conditional expression.
797  */
798 
799 public Boolean cond(p)
800 Node p;
801 {
802     Boolean b;
803     int i;
804 
805     if (p == nil) {
806 	b = true;
807     } else {
808 	eval(p);
809 	i = pop(Boolrep);
810 	b = (Boolean) i;
811     }
812     return b;
813 }
814 
815 /*
816  * Return the address corresponding to a given tree.
817  */
818 
819 public Address lval(p)
820 Node p;
821 {
822     if (p->op == O_RVAL) {
823 	eval(p->value.arg[0]);
824     } else {
825 	eval(p);
826     }
827     return (Address) (pop(long));
828 }
829 
830 /*
831  * Process a trace command, translating into the appropriate events
832  * and associated actions.
833  */
834 
835 public trace(p)
836 Node p;
837 {
838     Node exp, place, cond;
839     Node left;
840 
841     exp = p->value.arg[0];
842     place = p->value.arg[1];
843     cond = p->value.arg[2];
844     if (exp == nil) {
845 	traceall(p->op, place, cond);
846     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
847 	traceinst(p->op, exp, cond);
848     } else if (place != nil and place->op == O_QLINE) {
849 	traceat(p->op, exp, place, cond);
850     } else {
851 	left = exp;
852 	if (left->op == O_RVAL or left->op == O_CALL) {
853 	    left = left->value.arg[0];
854 	}
855 	if (left->op == O_SYM and isblock(left->value.sym)) {
856 	    traceproc(p->op, left->value.sym, place, cond);
857 	} else {
858 	    tracedata(p->op, exp, place, cond);
859 	}
860     }
861 }
862 
863 /*
864  * Set a breakpoint that will turn on tracing.
865  */
866 
867 private traceall(op, place, cond)
868 Operator op;
869 Node place;
870 Node cond;
871 {
872     Symbol s;
873     Node event;
874     Command action;
875 
876     if (place == nil) {
877 	s = program;
878     } else {
879 	s = place->value.sym;
880     }
881     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
882     action = build(O_PRINTSRCPOS,
883 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
884     if (cond != nil) {
885 	action = build(O_IF, cond, buildcmdlist(action));
886     }
887     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
888     action->value.trace.event = addevent(event, buildcmdlist(action));
889     if (isstdin()) {
890 	printevent(action->value.trace.event);
891     }
892 }
893 
894 /*
895  * Set up the appropriate breakpoint for tracing an instruction.
896  */
897 
898 private traceinst(op, exp, cond)
899 Operator op;
900 Node exp;
901 Node cond;
902 {
903     Node event, wh;
904     Command action;
905     Event e;
906 
907     if (exp->op == O_LCON) {
908 	wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
909     } else {
910 	wh = exp;
911     }
912     if (op == O_TRACEI) {
913 	event = build(O_EQ, build(O_SYM, pcsym), wh);
914     } else {
915 	event = build(O_EQ, build(O_SYM, linesym), wh);
916     }
917     action = build(O_PRINTSRCPOS, wh);
918     if (cond) {
919 	action = build(O_IF, cond, buildcmdlist(action));
920     }
921     e = addevent(event, buildcmdlist(action));
922     if (isstdin()) {
923 	printevent(e);
924     }
925 }
926 
927 /*
928  * Set a breakpoint to print an expression at a given line or address.
929  */
930 
931 private traceat(op, exp, place, cond)
932 Operator op;
933 Node exp;
934 Node place;
935 Node cond;
936 {
937     Node event;
938     Command action;
939     Event e;
940 
941     if (op == O_TRACEI) {
942 	event = build(O_EQ, build(O_SYM, pcsym), place);
943     } else {
944 	event = build(O_EQ, build(O_SYM, linesym), place);
945     }
946     action = build(O_PRINTSRCPOS, exp);
947     if (cond != nil) {
948 	action = build(O_IF, cond, buildcmdlist(action));
949     }
950     e = addevent(event, buildcmdlist(action));
951     if (isstdin()) {
952 	printevent(e);
953     }
954 }
955 
956 /*
957  * Construct event for tracing a procedure.
958  *
959  * What we want here is
960  *
961  * 	when $proc = p do
962  *	    if <condition> then
963  *	        printcall;
964  *	        once $pc = $retaddr do
965  *	            printrtn;
966  *	        end;
967  *	    end if;
968  *	end;
969  *
970  * Note that "once" is like "when" except that the event
971  * deletes itself as part of its associated action.
972  */
973 
974 private traceproc(op, p, place, cond)
975 Operator op;
976 Symbol p;
977 Node place;
978 Node cond;
979 {
980     Node event;
981     Command action;
982     Cmdlist actionlist;
983     Event e;
984 
985     action = build(O_PRINTCALL, p);
986     actionlist = list_alloc();
987     cmdlist_append(action, actionlist);
988     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
989     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
990     cmdlist_append(action, actionlist);
991     if (cond != nil) {
992 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
993     }
994     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
995     e = addevent(event, actionlist);
996     if (isstdin()) {
997 	printevent(e);
998     }
999 }
1000 
1001 /*
1002  * Set up breakpoint for tracing data.
1003  */
1004 
1005 private tracedata(op, exp, place, cond)
1006 Operator op;
1007 Node exp;
1008 Node place;
1009 Node cond;
1010 {
1011     Symbol p;
1012     Node event;
1013     Command action;
1014 
1015     if (size(exp->nodetype) > MAXTRSIZE) {
1016 	error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
1017     }
1018     p = (place == nil) ? tcontainer(exp) : place->value.sym;
1019     if (p == nil) {
1020 	p = program;
1021     }
1022     action = build(O_PRINTIFCHANGED, exp);
1023     if (cond != nil) {
1024 	action = build(O_IF, cond, buildcmdlist(action));
1025     }
1026     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
1027     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
1028     action->value.trace.event = addevent(event, buildcmdlist(action));
1029     if (isstdin()) {
1030 	printevent(action->value.trace.event);
1031     }
1032 }
1033 
1034 /*
1035  * Setting and unsetting of stops.
1036  */
1037 
1038 public stop(p)
1039 Node p;
1040 {
1041     Node exp, place, cond, t;
1042     Symbol s;
1043     Command action;
1044     Event e;
1045 
1046     exp = p->value.arg[0];
1047     place = p->value.arg[1];
1048     cond = p->value.arg[2];
1049     if (exp != nil) {
1050 	stopvar(p->op, exp, place, cond);
1051     } else {
1052 	action = build(O_STOPX);
1053 	if (cond != nil) {
1054 	    action = build(O_IF, cond, buildcmdlist(action));
1055 	}
1056 	if (place == nil or place->op == O_SYM) {
1057 	    if (place == nil) {
1058 		s = program;
1059 	    } else {
1060 		s = place->value.sym;
1061 	    }
1062 	    t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
1063 	    if (cond != nil) {
1064 		action = build(O_TRACEON, (p->op == O_STOPI),
1065 		    buildcmdlist(action));
1066 		e = addevent(t, buildcmdlist(action));
1067 		action->value.trace.event = e;
1068 	    } else {
1069 		e = addevent(t, buildcmdlist(action));
1070 	    }
1071 	    if (isstdin()) {
1072 		printevent(e);
1073 	    }
1074 	} else {
1075 	    stopinst(p->op, place, cond, action);
1076 	}
1077     }
1078 }
1079 
1080 private stopinst(op, place, cond, action)
1081 Operator op;
1082 Node place;
1083 Node cond;
1084 Command action;
1085 {
1086     Node event;
1087     Event e;
1088 
1089     if (op == O_STOP) {
1090 	event = build(O_EQ, build(O_SYM, linesym), place);
1091     } else {
1092 	event = build(O_EQ, build(O_SYM, pcsym), place);
1093     }
1094     e = addevent(event, buildcmdlist(action));
1095     if (isstdin()) {
1096 	printevent(e);
1097     }
1098 }
1099 
1100 /*
1101  * Implement stopping on assignment to a variable by adding it to
1102  * the variable list.
1103  */
1104 
1105 private stopvar(op, exp, place, cond)
1106 Operator op;
1107 Node exp;
1108 Node place;
1109 Node cond;
1110 {
1111     Symbol p;
1112     Node event;
1113     Command action;
1114 
1115     if (size(exp->nodetype) > MAXTRSIZE) {
1116 	error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
1117     }
1118     if (place == nil) {
1119 	if (exp->op == O_LCON) {
1120 	    p = program;
1121 	} else {
1122 	    p = tcontainer(exp);
1123 	    if (p == nil) {
1124 		p = program;
1125 	    }
1126 	}
1127     } else {
1128 	p = place->value.sym;
1129     }
1130     action = build(O_STOPIFCHANGED, exp);
1131     if (cond != nil) {
1132 	action = build(O_IF, cond, buildcmdlist(action));
1133     }
1134     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
1135     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
1136     action->value.trace.event = addevent(event, buildcmdlist(action));
1137     if (isstdin()) {
1138 	printevent(action->value.trace.event);
1139     }
1140 }
1141 
1142 /*
1143  * Assign the value of an expression to a variable (or term).
1144  */
1145 
1146 public assign(var, exp)
1147 Node var;
1148 Node exp;
1149 {
1150     Address addr;
1151     integer varsize, expsize;
1152     char cvalue;
1153     short svalue;
1154     long lvalue;
1155     float fvalue;
1156 
1157     if (var->op == O_SYM and regnum(var->value.sym) != -1) {
1158 	eval(exp);
1159 	setreg(regnum(var->value.sym), pop(Address));
1160     } else {
1161 	addr = lval(var);
1162 	varsize = size(var->nodetype);
1163 	expsize = size(exp->nodetype);
1164 	eval(exp);
1165 	if (varsize == sizeof(float) and expsize == sizeof(double)) {
1166 	    fvalue = (float) pop(double);
1167 	    dwrite(&fvalue, addr, sizeof(fvalue));
1168 	} else {
1169 	    if (varsize < sizeof(long)) {
1170 		lvalue = 0;
1171 		popn(expsize, &lvalue);
1172 		if (varsize == sizeof(char)) {
1173 		    cvalue = lvalue;
1174 		    dwrite(&cvalue, addr, sizeof(cvalue));
1175 		} else if (varsize == sizeof(short)) {
1176 		    svalue = lvalue;
1177 		    dwrite(&svalue, addr, sizeof(svalue));
1178 		} else {
1179 		    error("[internal error: bad size %d in assign]", varsize);
1180 		}
1181 	    } else {
1182 		if (expsize <= varsize) {
1183 		    sp -= expsize;
1184 		    dwrite(sp, addr, expsize);
1185 		} else {
1186 		    sp -= expsize;
1187 		    dwrite(sp, addr, varsize);
1188 		}
1189 	    }
1190 	}
1191     }
1192 }
1193 
1194 /*
1195  * Set a debugger variable.
1196  */
1197 
1198 private set (var, exp)
1199 Node var, exp;
1200 {
1201     Symbol t;
1202 
1203     if (var == nil) {
1204 	defvar(nil, nil);
1205     } else if (exp == nil) {
1206 	defvar(var->value.name, nil);
1207     } else if (var->value.name == identname("$frame", true)) {
1208 	t = exp->nodetype;
1209 	if (not compatible(t, t_int) and not compatible(t, t_addr)) {
1210 	    error("$frame must be an address");
1211 	}
1212 	eval(exp);
1213 	getnewregs(pop(Address));
1214     } else {
1215 	defvar(var->value.name, unrval(exp));
1216     }
1217 }
1218 
1219 /*
1220  * Execute a list command.
1221  */
1222 
1223 private list (p)
1224 Node p;
1225 {
1226     Symbol f;
1227     Address addr;
1228     Lineno line, l1, l2;
1229 
1230     if (p->value.arg[0]->op == O_SYM) {
1231 	f = p->value.arg[0]->value.sym;
1232 	addr = firstline(f);
1233 	if (addr == NOADDR) {
1234 	    error("no source lines for \"%s\"", symname(f));
1235 	}
1236 	setsource(srcfilename(addr));
1237 	line = srcline(addr);
1238 	getsrcwindow(line, &l1, &l2);
1239     } else {
1240 	eval(p->value.arg[0]);
1241 	l1 = (Lineno) (pop(long));
1242 	eval(p->value.arg[1]);
1243 	l2 = (Lineno) (pop(long));
1244     }
1245     printlines(l1, l2);
1246 }
1247 
1248 /*
1249  * Execute a func command.
1250  */
1251 
1252 private func (p)
1253 Node p;
1254 {
1255     Symbol s, f;
1256     Address addr;
1257 
1258     if (p == nil) {
1259 	printname(stdout, curfunc);
1260 	putchar('\n');
1261     } else {
1262 	s = p->value.sym;
1263 	if (isroutine(s)) {
1264 	    setcurfunc(s);
1265 	} else {
1266 	    find(f, s->name) where isroutine(f) endfind(f);
1267 	    if (f == nil) {
1268 		error("%s is not a procedure or function", symname(s));
1269 	    }
1270 	    setcurfunc(f);
1271 	}
1272 	addr = codeloc(curfunc);
1273 	if (addr != NOADDR) {
1274 	    setsource(srcfilename(addr));
1275 	    cursrcline = srcline(addr);
1276 	}
1277     }
1278 }
1279 
1280 /*
1281  * Send a message to the current support person.
1282  */
1283 
1284 public gripe()
1285 {
1286     typedef Operation();
1287     Operation *old;
1288     int pid, status;
1289     extern int versionNumber;
1290     char subject[100];
1291 
1292 #   ifdef MAINTAINER
1293 	puts("Type control-D to end your message.  Be sure to include");
1294 	puts("your name and the name of the file you are debugging.");
1295 	putchar('\n');
1296 	old = signal(SIGINT, SIG_DFL);
1297 	sprintf(subject, "dbx (version 3.%d) gripe", versionNumber);
1298 	pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil);
1299 	signal(SIGINT, SIG_IGN);
1300 	pwait(pid, &status);
1301 	signal(SIGINT, old);
1302 	if (status == 0) {
1303 	    puts("Thank you.");
1304 	} else {
1305 	    puts("\nMail not sent.");
1306 	}
1307 #   else
1308 	puts("Sorry, no dbx maintainer available to gripe to.");
1309 	puts("Try contacting your system manager.");
1310 #   endif
1311 }
1312 
1313 /*
1314  * Give the user some help.
1315  */
1316 
1317 public help()
1318 {
1319     puts("run                    - begin execution of the program");
1320     puts("print <exp>            - print the value of the expression");
1321     puts("where                  - print currently active procedures");
1322     puts("stop at <line>         - suspend execution at the line");
1323     puts("stop in <proc>         - suspend execution when <proc> is called");
1324     puts("cont                   - continue execution");
1325     puts("step                   - single step one line");
1326     puts("next                   - step to next line (skip over calls)");
1327     puts("trace <line#>          - trace execution of the line");
1328     puts("trace <proc>           - trace calls to the procedure");
1329     puts("trace <var>            - trace changes to the variable");
1330     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
1331     puts("status                 - print trace/stop's in effect");
1332     puts("delete <number>        - remove trace or stop of given number");
1333     puts("call <proc>            - call a procedure in program");
1334     puts("whatis <name>          - print the declaration of the name");
1335     puts("list <line>, <line>    - list source lines");
1336     puts("gripe                  - send mail to the person in charge of dbx");
1337     puts("quit                   - exit dbx");
1338 }
1339 
1340 /*
1341  * Divert output to the given file name.
1342  * Cannot redirect to an existing file.
1343  */
1344 
1345 private int so_fd;
1346 private Boolean notstdout;
1347 
1348 public setout(filename)
1349 String filename;
1350 {
1351     File f;
1352 
1353     f = fopen(filename, "r");
1354     if (f != nil) {
1355 	fclose(f);
1356 	error("%s: file already exists", filename);
1357     } else {
1358 	so_fd = dup(1);
1359 	close(1);
1360 	if (creat(filename, 0666) == nil) {
1361 	    unsetout();
1362 	    error("can't create %s", filename);
1363 	}
1364 	notstdout = true;
1365     }
1366 }
1367 
1368 /*
1369  * Revert output to standard output.
1370  */
1371 
1372 public unsetout()
1373 {
1374     fflush(stdout);
1375     close(1);
1376     if (dup(so_fd) != 1) {
1377 	panic("standard out dup failed");
1378     }
1379     close(so_fd);
1380     notstdout = false;
1381 }
1382 
1383 /*
1384  * Determine is standard output is currently being redirected
1385  * to a file (as far as we know).
1386  */
1387 
1388 public Boolean isredirected()
1389 {
1390     return notstdout;
1391 }
1392