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