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