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