|
|
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.5 (Berkeley) 1/12/88";
9: #endif not lint
10:
11: static char rcsid[] = "$Header: eval.c,v 1.2 87/03/25 19:48:33 donn 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: case O_TYPERENAME:
212: loophole(size(p->value.arg[0]->nodetype), size(p->nodetype));
213: break;
214:
215: case O_COMMA:
216: eval(p->value.arg[0]);
217: if (p->value.arg[1] != nil) {
218: eval(p->value.arg[1]);
219: }
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:
346: cont(p->value.lcon);
347: printnews();
348: break;
349:
350: case O_LIST:
351: list(p);
352: break;
353:
354: case O_FUNC:
355: func(p->value.arg[0]);
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;
363: if (n == 0) {
364: printvalue(r0, p->value.examine.mode);
365: } else if (streq(p->value.examine.mode, "i")) {
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;
411: useInstLoc = (Boolean) (not p->value.step.source);
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:
428: if (p->value.arg[0]->op == O_SYM) {
429: printwhereis(stdout, p->value.arg[0]->value.sym);
430: } else {
431: printwhereis(stdout, p->value.arg[0]->nodetype);
432: }
433: break;
434:
435: case O_WHICH:
436: if (p->value.arg[0]->op == O_SYM) {
437: printwhich(stdout, p->value.arg[0]->value.sym);
438: } else {
439: printwhich(stdout, p->value.arg[0]->nodetype);
440: }
441: putchar('\n');
442: break;
443:
444: case O_ALIAS:
445: n1 = p->value.arg[0];
446: n2 = p->value.arg[1];
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));
456: } else {
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: }
466: }
467: break;
468:
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:
477: case O_CALL:
478: callproc(p, true);
479: break;
480:
481: case O_CATCH:
482: if (p->value.lcon == 0) {
483: printsigscaught(process);
484: } else {
485: psigtrace(process, p->value.lcon, true);
486: }
487: break;
488:
489: case O_EDIT:
490: edit(p->value.scon);
491: break;
492:
493: case O_DEBUG:
494: debug(p);
495: break;
496:
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:
503: case O_DUMP:
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: }
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:
525: if (p->value.lcon == 0) {
526: printsigsignored(process);
527: } else {
528: psigtrace(process, p->value.lcon, false);
529: }
530: break;
531:
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:
541: case O_RUN:
542: run();
543: break;
544:
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:
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);
564: break;
565:
566: case O_STOP:
567: case O_STOPI:
568: stop(p);
569: break;
570:
571: case O_UNSET:
572: undefvar(p->value.arg[0]->value.name);
573: break;
574:
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:
581: case O_ADDEVENT:
582: addevent(p->value.event.cond, p->value.event.actions);
583: break;
584:
585: case O_DELETE:
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: }
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 {
638: if (canReadSource()) {
639: printf("trace: ");
640: printlines(curline, curline);
641: }
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: }
678: if (traceeval) {
679: fprintf(stderr, "end eval %s\n", opname(p->op));
680: }
681: }
682:
683: /*
684: * Evaluate a list of commands.
685: */
686:
687: public evalcmdlist(cl)
688: Cmdlist 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:
702: public rpush(addr, len)
703: Address addr;
704: int 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:
719: public Boolean canpush(n)
720: Integer 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:
729: public pushsmall(t, v)
730: Symbol t;
731: long 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:
759: public long popsmall(t)
760: Symbol t;
761: {
762: register integer n;
763: long r;
764:
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 {
770: r = (long) pop(char);
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 {
776: r = (long) pop(short);
777: }
778: } else if (n == sizeof(long)) {
779: r = pop(long);
780: } else {
781: error("[internal error: size %d in popsmall]", n);
782: }
783: return r;
784: }
785:
786: /*
787: * Evaluate a conditional expression.
788: */
789:
790: public Boolean cond(p)
791: Node p;
792: {
793: Boolean b;
794: int i;
795:
796: if (p == nil) {
797: b = true;
798: } else {
799: eval(p);
800: i = pop(Boolrep);
801: b = (Boolean) i;
802: }
803: return b;
804: }
805:
806: /*
807: * Return the address corresponding to a given tree.
808: */
809:
810: public Address lval(p)
811: Node 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:
826: public trace(p)
827: Node 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);
837: } else if (exp->op == O_QLINE or exp->op == O_LCON) {
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 {
842: left = exp;
843: if (left->op == O_RVAL or left->op == O_CALL) {
844: left = left->value.arg[0];
845: }
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:
858: private traceall(op, place, cond)
859: Operator op;
860: Node place;
861: Node 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));
880: if (isstdin()) {
881: printevent(action->value.trace.event);
882: }
883: }
884:
885: /*
886: * Set up the appropriate breakpoint for tracing an instruction.
887: */
888:
889: private traceinst(op, exp, cond)
890: Operator op;
891: Node exp;
892: Node cond;
893: {
894: Node event, wh;
895: Command action;
896: Event e;
897:
898: if (exp->op == O_LCON) {
899: wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
900: } else {
901: wh = exp;
902: }
903: if (op == O_TRACEI) {
904: event = build(O_EQ, build(O_SYM, pcsym), wh);
905: } else {
906: event = build(O_EQ, build(O_SYM, linesym), wh);
907: }
908: action = build(O_PRINTSRCPOS, wh);
909: if (cond) {
910: action = build(O_IF, cond, buildcmdlist(action));
911: }
912: e = addevent(event, buildcmdlist(action));
913: if (isstdin()) {
914: printevent(e);
915: }
916: }
917:
918: /*
919: * Set a breakpoint to print an expression at a given line or address.
920: */
921:
922: private traceat(op, exp, place, cond)
923: Operator op;
924: Node exp;
925: Node place;
926: Node cond;
927: {
928: Node event;
929: Command action;
930: Event e;
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: }
941: e = addevent(event, buildcmdlist(action));
942: if (isstdin()) {
943: printevent(e);
944: }
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:
965: private traceproc(op, p, place, cond)
966: Operator op;
967: Symbol p;
968: Node place;
969: Node cond;
970: {
971: Node event;
972: Command action;
973: Cmdlist actionlist;
974: Event e;
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));
986: e = addevent(event, actionlist);
987: if (isstdin()) {
988: printevent(e);
989: }
990: }
991:
992: /*
993: * Set up breakpoint for tracing data.
994: */
995:
996: private tracedata(op, exp, place, cond)
997: Operator op;
998: Node exp;
999: Node place;
1000: Node cond;
1001: {
1002: Symbol p;
1003: Node event;
1004: Command action;
1005:
1006: if (size(exp->nodetype) > MAXTRSIZE) {
1007: error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
1008: }
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));
1020: if (isstdin()) {
1021: printevent(action->value.trace.event);
1022: }
1023: }
1024:
1025: /*
1026: * Setting and unsetting of stops.
1027: */
1028:
1029: public stop(p)
1030: Node p;
1031: {
1032: Node exp, place, cond, t;
1033: Symbol s;
1034: Command action;
1035: Event e;
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);
1042: } else {
1043: action = build(O_STOPX);
1044: if (cond != nil) {
1045: action = build(O_IF, cond, buildcmdlist(action));
1046: }
1047: if (place == nil or place->op == O_SYM) {
1048: if (place == nil) {
1049: s = program;
1050: } else {
1051: s = place->value.sym;
1052: }
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: }
1068: }
1069: }
1070:
1071: private stopinst(op, place, cond, action)
1072: Operator op;
1073: Node place;
1074: Node cond;
1075: Command action;
1076: {
1077: Node event;
1078: Event e;
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: }
1085: e = addevent(event, buildcmdlist(action));
1086: if (isstdin()) {
1087: printevent(e);
1088: }
1089: }
1090:
1091: /*
1092: * Implement stopping on assignment to a variable by adding it to
1093: * the variable list.
1094: */
1095:
1096: private stopvar(op, exp, place, cond)
1097: Operator op;
1098: Node exp;
1099: Node place;
1100: Node cond;
1101: {
1102: Symbol p;
1103: Node event;
1104: Command action;
1105:
1106: if (size(exp->nodetype) > MAXTRSIZE) {
1107: error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
1108: }
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));
1124: }
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));
1128: if (isstdin()) {
1129: printevent(action->value.trace.event);
1130: }
1131: }
1132:
1133: /*
1134: * Assign the value of an expression to a variable (or term).
1135: */
1136:
1137: public assign(var, exp)
1138: Node var;
1139: Node exp;
1140: {
1141: Address addr;
1142: integer varsize, expsize;
1143: char cvalue;
1144: short svalue;
1145: long lvalue;
1146: float fvalue;
1147:
1148: if (var->op == O_SYM and regnum(var->value.sym) != -1) {
1149: eval(exp);
1150: setreg(regnum(var->value.sym), pop(Address));
1151: } else {
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)) {
1164: cvalue = lvalue;
1165: dwrite(&cvalue, addr, sizeof(cvalue));
1166: } else if (varsize == sizeof(short)) {
1167: svalue = lvalue;
1168: dwrite(&svalue, addr, sizeof(svalue));
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: }
1180: }
1181: }
1182: }
1183: }
1184:
1185: /*
1186: * Set a debugger variable.
1187: */
1188:
1189: private set (var, exp)
1190: Node 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:
1214: private list (p)
1215: Node 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:
1243: private func (p)
1244: Node 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);
1256: } else {
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));
1260: }
1261: setcurfunc(f);
1262: }
1263: addr = codeloc(curfunc);
1264: if (addr != NOADDR) {
1265: setsource(srcfilename(addr));
1266: cursrcline = srcline(addr);
1267: }
1268: }
1269: }
1270:
1271: /*
1272: * Send a message to the current support person.
1273: */
1274:
1275: public gripe()
1276: {
1277: typedef Operation();
1278: Operation *old;
1279: int pid, status;
1280: extern int versionNumber;
1281: char subject[100];
1282:
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
1302: }
1303:
1304: /*
1305: * Give the user some help.
1306: */
1307:
1308: public help()
1309: {
1310: puts("run - begin execution of the program");
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");
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");
1322: puts("status - print trace/stop's in effect");
1323: puts("delete <number> - remove trace or stop of given number");
1324: puts("call <proc> - call a procedure in program");
1325: puts("whatis <name> - print the declaration of the name");
1326: puts("list <line>, <line> - list source lines");
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:
1336: private int so_fd;
1337: private Boolean notstdout;
1338:
1339: public setout(filename)
1340: String 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:
1363: public 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:
1379: public Boolean isredirected()
1380: {
1381: return notstdout;
1382: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.