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