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