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