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