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