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