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