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