|
|
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[] = "@(#)runtime.iris.c 5.1 (Berkeley) 1/12/88";
9: #endif not lint
10:
11: static char rcsid[] = "$Header: runtime.iris.c,v 1.3 88/01/11 21:26:46 donn Exp $";
12:
13: /*
14: * Runtime organization dependent routines, mostly dealing with
15: * activation records.
16: */
17:
18: #include "defs.h"
19: #include "runtime.h"
20: #include "process.h"
21: #include "machine.h"
22: #include "events.h"
23: #include "mappings.h"
24: #include "symbols.h"
25: #include "tree.h"
26: #include "eval.h"
27: #include "operators.h"
28: #include "object.h"
29: #include <sys/param.h>
30: #include <signal.h>
31:
32: #ifndef public
33: typedef struct Frame *Frame;
34:
35: #include "machine.h"
36: #endif
37:
38: #define NSAVEREG 14
39:
40: struct Frame {
41: Address save_fp; /* frame pointer */
42: Address save_pc; /* program counter */
43: Word save_reg[NSAVEREG]; /* not necessarily there */
44: integer nargwords; /* computed, not stored */
45: };
46:
47: private Frame curframe = nil;
48: private struct Frame curframerec;
49: private Boolean walkingstack = false;
50:
51: #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
52:
53: private boolean inSignalHandler (addr)
54: Address addr;
55: {
56: Symbol f;
57:
58: #ifdef IRIS
59: return false;
60: #else /* sun */
61: f = whatblock(addr);
62: return (boolean) (f != nil and streq(symname(f), "_sigtramp"));
63: #endif
64: }
65:
66: typedef struct {
67: Node callnode;
68: Node cmdnode;
69: boolean isfunc;
70: } CallEnv;
71:
72: private CallEnv endproc;
73:
74: /*
75: * Set a frame to the current activation record.
76: */
77:
78: private getcurframe(frp)
79: Frame frp;
80: {
81: register int i;
82:
83: checkref(frp);
84: frp->save_fp = reg(FRP);
85: frp->save_pc = reg(PROGCTR);
86: for (i = 0; i < NSAVEREG; i++) {
87: frp->save_reg[i] = reg(i);
88: }
89: if (frp->save_fp == nil) {
90: frp->nargwords = 0;
91: } else {
92: findnumargs(frp);
93: }
94: }
95:
96: /*
97: * Get the saved registers from one frame to another
98: * given mask specifying which registers were actually saved.
99: */
100:
101: #define bis(b, n) ((b & (1 << (n))) != 0)
102:
103: private getsaveregs (newfrp, frp, mask)
104: Frame newfrp, frp;
105: integer mask;
106: {
107: integer i, j;
108:
109: j = 0;
110: for (i = 0; i < NSAVEREG; i++) {
111: if (bis(mask, i)) {
112: newfrp->save_reg[i] = frp->save_reg[j];
113: ++j;
114: }
115: }
116: }
117:
118: /*
119: * Return a pointer to the next activation record up the stack.
120: * Return nil if there is none.
121: * Writes over space pointed to by given argument.
122: */
123:
124: private Frame nextframe(frp)
125: Frame frp;
126: {
127: Frame newfrp;
128: struct Frame frame;
129: integer mask;
130: Address prev_frame, callpc, higher_fp, higher_pc;
131: static integer ntramp = 0;
132:
133: newfrp = frp;
134: prev_frame = frp->save_fp;
135:
136: /*
137: * The check for interrupt generated frames is taken from adb with only
138: * partial understanding. If you're in "sub" and on a sigxxx "sigsub"
139: * gets control, then the stack does NOT look like <main, sub, sigsub>.
140: *
141: * As best I can make out it looks like:
142: *
143: * <main, (machine check exception block + sub), sysframe, sigsub>.
144: *
145: * When the signal occurs an exception block and a frame for the routine
146: * in which it occured are pushed on the user stack. Then another frame
147: * is pushed corresponding to a call from the kernel to sigsub.
148: *
149: * The addr in sub at which the exception occured is not in sub.save_pc
150: * but in the machine check exception block. It is at the magic address
151: * fp + 84.
152: *
153: * The current approach ignores the sys_frame (what adb reports as sigtramp)
154: * and takes the pc for sub from the exception block. This allows the
155: * "where" command to report <main, sub, sigsub>, which seems reasonable.
156: */
157:
158: nextf:
159: if (prev_frame + sizeof(struct Frame) <= USRSTACK) {
160: dread(&frame, prev_frame, sizeof(struct Frame));
161: } else if (USRSTACK - prev_frame > 2 * sizeof(Word)) {
162: dread(&frame, prev_frame, USRSTACK - prev_frame);
163: } else {
164: frame.save_fp = nil;
165: }
166: if (ntramp == 1) {
167: dread(&callpc, prev_frame + 92, sizeof(callpc));
168: } else {
169: callpc = frame.save_pc;
170: }
171: if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
172: newfrp = nil;
173: } else {
174: if (inSignalHandler(callpc)) {
175: # ifdef sun
176: Address scp;
177:
178: dread(&scp, prev_frame + 16, sizeof(scp));
179: dread(&callpc,
180: &(((struct sigcontext *)scp)->sc_pc), sizeof(Word)
181: );
182: # endif /* sun */
183: }
184: frame.save_pc = callpc;
185: ntramp = 0;
186: higher_fp = frp->save_fp;
187: higher_pc = frp->save_pc;
188: newfrp->save_fp = frame.save_fp;
189: newfrp->save_pc = frame.save_pc;
190: findnumargs(newfrp);
191: findsavedregs(newfrp, higher_fp, higher_pc);
192: }
193: return newfrp;
194: }
195:
196: /*
197: * Finding the saved registers and number of arguments passed to
198: * the current procedure is painful for the 68000.
199: *
200: * This is a version of the way adb for the 68000 does this.
201: */
202:
203: #define HIWORD 0xffff0000
204: #define LOWORD 0x0000ffff
205: #define LINKA6 0x4e560000 /* link a6,#x */
206: #define ADDLSP 0xdffc0000 /* addl #x,sp */
207: #define ADDWSP 0xdefc0000 /* addw #x,sp */
208: #define LEASP 0x4fef0000 /* lea sp@(x),sp*/
209: #define TSTBSP 0x4a2f0000 /* tstb sp@(x) */
210: #define INSMSK 0xfff80000
211: #define MOVLSP 0x2e800000 /* movl dx,sp@ */
212: #define MOVLD0 0x20000000 /* movl d0,dx */
213: #define MOVLA0 0x20400000 /* movl d0,ax */
214: #define MVLMSK 0xf1ff0000
215: #define MOVEML 0x48d70000 /* moveml #x,sp@ */
216: #define JSR 0x4eb80000 /* jsr x.[WL] */
217: #define JSRPC 0x4eba0000 /* jsr PC@( ) */
218: #define LONGBIT 0x00010000
219: #define BSR 0x61000000 /* bsr x */
220: #define BYTE3 0x0000ff00
221: #define LOBYTE 0x000000ff
222: #define ADQMSK 0xf1ff0000
223: #define ADDQSP 0x508f0000 /* addql #x,sp */
224: #define ADDQWSP 0x504f0000 /* addqw #x,sp */
225:
226: private int savedregsmask;
227: private int savedregp;
228:
229: /*
230: * Find out how many words of arguments were passed to
231: * the current procedure.
232: */
233:
234: private findnumargs (newfrp)
235: Frame newfrp;
236: {
237: integer val;
238: integer instruc;
239: Address addr;
240:
241: dread(&addr, newfrp->save_fp + sizeof(Address), sizeof(addr));
242: iread(&instruc, addr, sizeof(instruc));
243: if ((instruc&MVLMSK) == MOVLA0 or (instruc&MVLMSK) == MOVLD0) {
244: addr += 2;
245: iread(&instruc, addr, sizeof(instruc));
246: }
247: if ((instruc&ADQMSK) == ADDQSP or (instruc&ADQMSK) == ADDQWSP){
248: val = (instruc >> (16+9)) & 07;
249: if (val == 0) {
250: val = 8;
251: }
252: } else if ((instruc&HIWORD) == ADDLSP){
253: iread(&val, addr + 2, sizeof(val));
254: } else if ((instruc&HIWORD) == ADDWSP || (instruc&HIWORD) == LEASP){
255: val = instruc&LOWORD;
256: } else {
257: val = 0;
258: }
259: newfrp->nargwords = val / sizeof(Word);
260: }
261:
262: /*
263: * Get the saved registers for the given Frame.
264: */
265:
266: private findsavedregs (newfrp, higher_fp, higher_pc)
267: Frame newfrp;
268: register Address higher_fp, higher_pc;
269: {
270: int val, regp, i;
271: Address addr;
272: Symbol func;
273: Address calladdr;
274: int instruc;
275:
276: /*
277: * Find the entry point of the current procedure.
278: * This is done by finding the procedure for the higher frame's pc
279: * and taking its starting address.
280: */
281: func = whatblock(higher_pc, true);
282: calladdr = codeloc(func) - FUNCOFFSET;
283:
284: /*
285: * Look at the entry code for the current procedure
286: * to determine which registers were saved, and where they are.
287: *
288: * First find the size of the activation record.
289: */
290: addr = calladdr;
291: iread(&instruc, addr, sizeof(instruc));
292: if ((instruc&HIWORD) == LINKA6) {
293: if ((instruc &= LOWORD) == 0) {
294: /* look for addl */
295: addr += 4;
296: iread(&instruc, addr, sizeof(instruc));
297: if ((instruc&HIWORD) == ADDLSP) {
298: iread(&instruc, addr + 2, sizeof(instruc));
299: addr += 6;
300: } else {
301: instruc = 0;
302: }
303: } else {
304: /* link offset was non-zero -- sign extend it */
305: instruc <<= 16;
306: instruc >>= 16;
307: }
308: /* we now have the negative frame size */
309: regp = higher_fp + instruc;
310: savedregp = regp;
311: }
312:
313: /*
314: * Now find which registers were saved.
315: * (expecting a probe instruction next)
316: */
317: iread(&instruc, addr, sizeof(instruc));
318: if ((instruc&HIWORD) == TSTBSP) {
319: addr += 4;
320: iread(&instruc, addr, sizeof(instruc));
321: }
322: /*
323: * expect either a moveml or a movl next
324: */
325: if ((instruc&INSMSK) == MOVLSP){
326: /*
327: * Only one register saved.
328: */
329: i = (instruc>>16) & 07;
330: dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
331: savedregsmask = 1 << i;
332: } else if ((instruc&HIWORD) == MOVEML) {
333: /*
334: * Saving multiple registers or unoptimized code
335: */
336: val = instruc & LOWORD;
337: savedregsmask = val;
338: i = 0;
339: while (val != 0) {
340: if (val&1) {
341: dread(&(newfrp->save_reg[i]), regp, sizeof(Word));
342: regp += sizeof(Word);
343: }
344: val >>= 1;
345: ++i;
346: }
347: } else {
348: savedregsmask = 0;
349: }
350: }
351:
352: /*
353: * Get the current frame information in the given Frame and store the
354: * associated function in the given value-result parameter.
355: */
356:
357: private getcurfunc (frp, fp)
358: Frame frp;
359: Symbol *fp;
360: {
361: getcurframe(frp);
362: *fp = whatblock(frp->save_pc);
363: }
364:
365: /*
366: * Return the frame associated with the next function up the call stack, or
367: * nil if there is none. The function is returned in a value-result parameter.
368: * For "inline" functions the statically outer function and same frame
369: * are returned.
370: */
371:
372: public Frame nextfunc (frp, fp)
373: Frame frp;
374: Symbol *fp;
375: {
376: Symbol t;
377: Frame nfrp;
378:
379: t = *fp;
380: checkref(t);
381: if (isinline(t)) {
382: t = container(t);
383: nfrp = frp;
384: } else {
385: nfrp = nextframe(frp);
386: if (nfrp == nil) {
387: t = nil;
388: } else {
389: t = whatblock(nfrp->save_pc);
390: }
391: }
392: *fp = t;
393: return nfrp;
394: }
395:
396: /*
397: * Return the frame associated with the given function.
398: * If the function is nil, return the most recently activated frame.
399: *
400: * Static allocation for the frame.
401: */
402:
403: public Frame findframe(f)
404: Symbol f;
405: {
406: Frame frp;
407: static struct Frame frame;
408: Symbol p;
409: Boolean done;
410:
411: frp = &frame;
412: getcurframe(frp);
413: if (f != nil) {
414: if (f == curfunc and curframe != nil) {
415: *frp = *curframe;
416: } else {
417: done = false;
418: p = whatblock(frp->save_pc);
419: do {
420: if (p == f) {
421: done = true;
422: } else if (p == program) {
423: done = true;
424: frp = nil;
425: } else {
426: frp = nextfunc(frp, &p);
427: if (frp == nil) {
428: done = true;
429: }
430: }
431: } while (not done);
432: }
433: }
434: return frp;
435: }
436:
437: /*
438: * Set the registers according to the given frame pointer.
439: */
440:
441: public getnewregs (addr)
442: Address addr;
443: {
444: struct Frame frame;
445: integer i, j, mask;
446:
447: dread(&frame, addr, sizeof(frame));
448: setreg(FRP, frame.save_fp);
449: setreg(PROGCTR, frame.save_pc);
450: pc = frame.save_pc;
451: setcurfunc(whatblock(pc));
452: }
453:
454: /*
455: * Find the return address of the current procedure/function.
456: */
457:
458: public Address return_addr()
459: {
460: Frame frp;
461: Address addr;
462: struct Frame frame;
463:
464: frp = &frame;
465: getcurframe(frp);
466: frp = nextframe(frp);
467: if (frp == nil) {
468: addr = 0;
469: } else {
470: addr = frp->save_pc;
471: }
472: return addr;
473: }
474:
475: /*
476: * Push the value associated with the current function.
477: */
478:
479: public pushretval(len, isindirect)
480: integer len;
481: boolean isindirect;
482: {
483: Word r0;
484:
485: r0 = reg(0);
486: if (isindirect) {
487: rpush((Address) r0, len);
488: } else {
489: switch (len) {
490: case sizeof(char):
491: push(char, r0);
492: break;
493:
494: case sizeof(short):
495: push(short, r0);
496: break;
497:
498: default:
499: if (len == sizeof(Word)) {
500: push(Word, r0);
501: } else if (len == 2*sizeof(Word)) {
502: push(Word, r0);
503: push(Word, reg(1));
504: } else {
505: error("[internal error: bad size %d in pushretval]", len);
506: }
507: break;
508: }
509: }
510: }
511:
512: /*
513: * Return the base address for locals in the given frame.
514: */
515:
516: public Address locals_base(frp)
517: Frame frp;
518: {
519: return (frp == nil) ? reg(FRP) : frp->save_fp;
520: }
521:
522: /*
523: * Return the base address for arguments in the given frame.
524: */
525:
526: public Address args_base(frp)
527: Frame frp;
528: {
529: return (frp == nil) ? reg(FRP) : frp->save_fp;
530: }
531:
532: /*
533: * Return saved register n from the given frame.
534: */
535:
536: public Word savereg(n, frp)
537: integer n;
538: Frame frp;
539: {
540: Word w;
541:
542: if (frp == nil) {
543: w = reg(n);
544: } else {
545: switch (n) {
546: case FRP:
547: w = frp->save_fp;
548: break;
549:
550: case STKP:
551: w = reg(STKP);
552: break;
553:
554: case PROGCTR:
555: w = frp->save_pc;
556: break;
557:
558: default:
559: assert(n >= 0 and n < NSAVEREG);
560: w = frp->save_reg[n];
561: break;
562: }
563: }
564: return w;
565: }
566:
567: /*
568: * Return the nth argument to the current procedure.
569: */
570:
571: public Word argn(n, frp)
572: integer n;
573: Frame frp;
574: {
575: Address argaddr;
576: Word w;
577:
578: argaddr = args_base(frp) + 4 + (n * sizeof(Word));
579: dread(&w, argaddr, sizeof(w));
580: return w;
581: }
582:
583: /*
584: * Return the number of words of arguments passed to the procedure
585: * associated with the given frame (it's a macro for the VAX).
586: */
587:
588: public integer nargspassed (frp)
589: Frame frp;
590: {
591: integer n;
592: struct Frame frame;
593:
594: if (frp == nil) {
595: getcurframe(&frame);
596: n = frame.nargwords;
597: } else {
598: n = frp->nargwords;
599: }
600: return n;
601: }
602:
603: /*
604: * Print a list of currently active blocks starting with most recent.
605: */
606:
607: public wherecmd()
608: {
609: walkstack(false);
610: }
611:
612: /*
613: * Print the variables in the given frame or the current one if nil.
614: */
615:
616: public dump (func)
617: Symbol func;
618: {
619: Symbol f;
620: Frame frp;
621:
622: if (func == nil) {
623: f = curfunc;
624: if (curframe != nil) {
625: frp = curframe;
626: } else {
627: frp = findframe(f);
628: }
629: } else {
630: f = func;
631: frp = findframe(f);
632: }
633: showaggrs = true;
634: printcallinfo(f, frp);
635: dumpvars(f, frp);
636: }
637:
638: /*
639: * Dump all values.
640: */
641:
642: public dumpall ()
643: {
644: walkstack(true);
645: }
646:
647: /*
648: * Walk the stack of active procedures printing information
649: * about each active procedure.
650: */
651:
652: private walkstack(dumpvariables)
653: Boolean dumpvariables;
654: {
655: Frame frp;
656: boolean save;
657: Symbol f;
658: struct Frame frame;
659:
660: if (notstarted(process) or isfinished(process)) {
661: error("program is not active");
662: } else {
663: save = walkingstack;
664: walkingstack = true;
665: showaggrs = dumpvariables;
666: frp = &frame;
667: getcurfunc(frp, &f);
668: for (;;) {
669: printcallinfo(f, frp);
670: if (dumpvariables) {
671: dumpvars(f, frp);
672: putchar('\n');
673: }
674: frp = nextfunc(frp, &f);
675: if (frp == nil or f == program) {
676: break;
677: }
678: }
679: if (dumpvariables) {
680: printf("in \"%s\":\n", symname(program));
681: dumpvars(program, nil);
682: putchar('\n');
683: }
684: walkingstack = save;
685: }
686: }
687:
688: /*
689: * Print out the information about a call, i.e.,
690: * routine name, parameter values, and source location.
691: */
692:
693: private printcallinfo (f, frp)
694: Symbol f;
695: Frame frp;
696: {
697: Lineno line;
698: Address savepc;
699:
700: savepc = frp->save_pc;
701: if (frp->save_fp != reg(FRP)) {
702: savepc -= 1;
703: }
704: printname(stdout, f);
705: if (not isinline(f)) {
706: printparams(f, frp);
707: }
708: line = srcline(savepc);
709: if (line != 0) {
710: printf(", line %d", line);
711: printf(" in \"%s\"\n", srcfilename(savepc));
712: } else {
713: printf(" at 0x%x\n", savepc);
714: }
715: }
716:
717: /*
718: * Set the current function to the given symbol.
719: * We must adjust "curframe" so that subsequent operations are
720: * not confused; for simplicity we simply clear it.
721: */
722:
723: public setcurfunc (f)
724: Symbol f;
725: {
726: curfunc = f;
727: curframe = nil;
728: }
729:
730: /*
731: * Return the frame for the current function.
732: * The space for the frame is allocated statically.
733: */
734:
735: public Frame curfuncframe ()
736: {
737: static struct Frame frame;
738: Frame frp;
739:
740: if (curframe == nil) {
741: frp = findframe(curfunc);
742: curframe = &curframerec;
743: *curframe = *frp;
744: } else {
745: frp = &frame;
746: *frp = *curframe;
747: }
748: return frp;
749: }
750:
751: /*
752: * Set curfunc to be N up/down the stack from its current value.
753: */
754:
755: public up (n)
756: integer n;
757: {
758: integer i;
759: Symbol f;
760: Frame frp;
761: boolean done;
762:
763: if (not isactive(program)) {
764: error("program is not active");
765: } else if (curfunc == nil) {
766: error("no current function");
767: } else {
768: i = 0;
769: f = curfunc;
770: frp = curfuncframe();
771: done = false;
772: do {
773: if (frp == nil) {
774: done = true;
775: error("not that many levels");
776: } else if (i >= n) {
777: done = true;
778: curfunc = f;
779: curframe = &curframerec;
780: *curframe = *frp;
781: showaggrs = false;
782: printcallinfo(curfunc, curframe);
783: } else if (f == program) {
784: done = true;
785: error("not that many levels");
786: } else {
787: frp = nextfunc(frp, &f);
788: }
789: ++i;
790: } while (not done);
791: }
792: }
793:
794: public down (n)
795: integer n;
796: {
797: integer i, depth;
798: Frame frp, curfrp;
799: Symbol f;
800: struct Frame frame;
801:
802: if (not isactive(program)) {
803: error("program is not active");
804: } else if (curfunc == nil) {
805: error("no current function");
806: } else {
807: depth = 0;
808: frp = &frame;
809: getcurfunc(frp, &f);
810: if (curframe == nil) {
811: curfrp = findframe(curfunc);
812: curframe = &curframerec;
813: *curframe = *curfrp;
814: }
815: while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
816: frp = nextfunc(frp, &f);
817: ++depth;
818: }
819: if (f == nil or n > depth) {
820: error("not that many levels");
821: } else {
822: depth -= n;
823: frp = &frame;
824: getcurfunc(frp, &f);
825: for (i = 0; i < depth; i++) {
826: frp = nextfunc(frp, &f);
827: assert(frp != nil);
828: }
829: curfunc = f;
830: *curframe = *frp;
831: showaggrs = false;
832: printcallinfo(curfunc, curframe);
833: }
834: }
835: }
836:
837: /*
838: * Find the entry point of a procedure or function.
839: */
840:
841: public findbeginning (f)
842: Symbol f;
843: {
844: if (isinternal(f)) {
845: f->symvalue.funcv.beginaddr += 18; /* VAX only */
846: } else {
847: /* on 68000's don't add for beginning of program */
848: if (f->symvalue.funcv.beginaddr != CODESTART) {
849: f->symvalue.funcv.beginaddr += FUNCOFFSET;
850: }
851: }
852: }
853:
854: /*
855: * Return the address corresponding to the first line in a function.
856: */
857:
858: public Address firstline(f)
859: Symbol f;
860: {
861: Address addr;
862:
863: addr = codeloc(f);
864: while (linelookup(addr) == 0 and addr < objsize) {
865: ++addr;
866: }
867: if (addr == objsize) {
868: addr = -1;
869: }
870: return addr;
871: }
872:
873: /*
874: * Catcher drops strike three ...
875: */
876:
877: public runtofirst()
878: {
879: Address addr, endaddr;
880:
881: addr = pc;
882: endaddr = objsize + CODESTART;
883: while (linelookup(addr) == 0 and addr < endaddr) {
884: ++addr;
885: }
886: if (addr < endaddr) {
887: stepto(addr);
888: }
889: }
890:
891: /*
892: * Return the address corresponding to the end of the program.
893: *
894: * We look for the entry to "exit".
895: */
896:
897: public Address lastaddr()
898: {
899: Symbol s;
900:
901: s = lookup(identname("exit", true));
902: if (s == nil) {
903: panic("can't find exit");
904: }
905: return codeloc(s);
906: }
907:
908: /*
909: * Decide if the given function is currently active.
910: *
911: * We avoid calls to "findframe" during a stack trace for efficiency.
912: * Presumably information evaluated while walking the stack is active.
913: */
914:
915: public Boolean isactive (f)
916: Symbol f;
917: {
918: Boolean b;
919:
920: if (isfinished(process)) {
921: b = false;
922: } else {
923: if (walkingstack or f == program or f == nil or
924: (ismodule(f) and isactive(container(f)))) {
925: b = true;
926: } else {
927: b = (Boolean) (findframe(f) != nil);
928: }
929: }
930: return b;
931: }
932:
933: /*
934: * Evaluate a call to a procedure.
935: */
936:
937: public callproc(exprnode, isfunc)
938: Node exprnode;
939: boolean isfunc;
940: {
941: Node procnode, arglist;
942: Symbol proc;
943: integer argc;
944:
945: procnode = exprnode->value.arg[0];
946: arglist = exprnode->value.arg[1];
947: if (procnode->op != O_SYM) {
948: beginerrmsg();
949: fprintf(stderr, "can't call \"");
950: prtree(stderr, procnode);
951: fprintf(stderr, "\"");
952: enderrmsg();
953: }
954: assert(procnode->op == O_SYM);
955: proc = procnode->value.sym;
956: if (not isblock(proc)) {
957: error("\"%s\" is not a procedure or function", symname(proc));
958: }
959: endproc.isfunc = isfunc;
960: endproc.callnode = exprnode;
961: endproc.cmdnode = topnode;
962: pushenv();
963: pc = codeloc(proc);
964: argc = pushargs(proc, arglist);
965: setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */
966: beginproc(proc, argc);
967: event_once(
968: build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
969: buildcmdlist(build(O_PROCRTN, proc))
970: );
971: isstopped = false;
972: if (not bpact()) {
973: isstopped = true;
974: cont(0);
975: }
976: /*
977: * bpact() won't return true, it will call printstatus() and go back
978: * to command input if a breakpoint is found.
979: */
980: /* NOTREACHED */
981: }
982:
983: /*
984: * Push the arguments on the process' stack. We do this by first
985: * evaluating them on the "eval" stack, then copying into the process'
986: * space.
987: */
988:
989: private integer pushargs(proc, arglist)
990: Symbol proc;
991: Node arglist;
992: {
993: Stack *savesp;
994: int argc, args_size;
995:
996: savesp = sp;
997: if (varIsSet("$unsafecall")) {
998: argc = unsafe_evalargs(proc, arglist);
999: } else {
1000: argc = evalargs(proc, arglist);
1001: }
1002: args_size = sp - savesp;
1003: setreg(STKP, reg(STKP) - args_size);
1004: dwrite(savesp, reg(STKP), args_size);
1005: sp = savesp;
1006: return argc;
1007: }
1008:
1009: /*
1010: * Check to see if an expression is correct for a given parameter.
1011: * If the given parameter is false, don't worry about type inconsistencies.
1012: *
1013: * Return whether or not it is ok.
1014: */
1015:
1016: private boolean chkparam (actual, formal, chk)
1017: Node actual;
1018: Symbol formal;
1019: boolean chk;
1020: {
1021: boolean b;
1022:
1023: b = true;
1024: if (chk) {
1025: if (formal == nil) {
1026: beginerrmsg();
1027: fprintf(stderr, "too many parameters");
1028: b = false;
1029: } else if (not compatible(formal->type, actual->nodetype)) {
1030: beginerrmsg();
1031: fprintf(stderr, "type mismatch for %s", symname(formal));
1032: b = false;
1033: }
1034: }
1035: if (b and formal != nil and
1036: isvarparam(formal) and not isopenarray(formal->type) and
1037: not (
1038: actual->op == O_RVAL or actual->nodetype == t_addr or
1039: (
1040: actual->op == O_TYPERENAME and
1041: (
1042: actual->value.arg[0]->op == O_RVAL or
1043: actual->value.arg[0]->nodetype == t_addr
1044: )
1045: )
1046: )
1047: ) {
1048: beginerrmsg();
1049: fprintf(stderr, "expected variable, found \"");
1050: prtree(stderr, actual);
1051: fprintf(stderr, "\"");
1052: b = false;
1053: }
1054: return b;
1055: }
1056:
1057: /*
1058: * Pass an expression to a particular parameter.
1059: *
1060: * Normally we pass either the address or value, but in some cases
1061: * (such as C strings) we want to copy the value onto the stack and
1062: * pass its address.
1063: *
1064: * Another special case raised by strings is the possibility that
1065: * the actual parameter will be larger than the formal, even with
1066: * appropriate type-checking. This occurs because we assume during
1067: * evaluation that strings are null-terminated, whereas some languages,
1068: * notably Pascal, do not work under that assumption.
1069: */
1070:
1071: private passparam (actual, formal)
1072: Node actual;
1073: Symbol formal;
1074: {
1075: boolean b;
1076: Address addr;
1077: Stack *savesp;
1078: integer actsize, formsize;
1079:
1080: if (formal != nil and isvarparam(formal) and
1081: (not isopenarray(formal->type))
1082: ) {
1083: addr = lval(actual->value.arg[0]);
1084: push(Address, addr);
1085: } else if (passaddr(formal, actual->nodetype)) {
1086: savesp = sp;
1087: eval(actual);
1088: actsize = sp - savesp;
1089: setreg(STKP,
1090: reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
1091: );
1092: dwrite(savesp, reg(STKP), actsize);
1093: sp = savesp;
1094: push(Address, reg(STKP));
1095: if (formal != nil and isopenarray(formal->type)) {
1096: push(integer, actsize div size(formal->type->type));
1097: }
1098: } else if (formal != nil) {
1099: formsize = size(formal);
1100: savesp = sp;
1101: eval(actual);
1102: actsize = sp - savesp;
1103: if (actsize > formsize) {
1104: sp -= (actsize - formsize);
1105: }
1106: } else {
1107: eval(actual);
1108: }
1109: }
1110:
1111: /*
1112: * Evaluate an argument list left-to-right.
1113: */
1114:
1115: private integer evalargs(proc, arglist)
1116: Symbol proc;
1117: Node arglist;
1118: {
1119: Node p, actual;
1120: Symbol formal;
1121: Stack *savesp;
1122: integer count;
1123: boolean chk;
1124:
1125: savesp = sp;
1126: count = 0;
1127: formal = proc->chain;
1128: chk = (boolean) (not nosource(proc));
1129: for (p = arglist; p != nil; p = p->value.arg[1]) {
1130: assert(p->op == O_COMMA);
1131: actual = p->value.arg[0];
1132: if (not chkparam(actual, formal, chk)) {
1133: fprintf(stderr, " in call to %s", symname(proc));
1134: sp = savesp;
1135: enderrmsg();
1136: }
1137: passparam(actual, formal);
1138: if (formal != nil) {
1139: formal = formal->chain;
1140: }
1141: ++count;
1142: }
1143: if (chk) {
1144: if (formal != nil) {
1145: sp = savesp;
1146: error("not enough parameters to %s", symname(proc));
1147: }
1148: }
1149: return count;
1150: }
1151:
1152: /*
1153: * Evaluate an argument list without any type checking.
1154: * This is only useful for procedures with a varying number of
1155: * arguments that are compiled -g.
1156: */
1157:
1158: private integer unsafe_evalargs (proc, arglist)
1159: Symbol proc;
1160: Node arglist;
1161: {
1162: Node p;
1163: integer count;
1164:
1165: count = 0;
1166: for (p = arglist; p != nil; p = p->value.arg[1]) {
1167: assert(p->op == O_COMMA);
1168: eval(p->value.arg[0]);
1169: ++count;
1170: }
1171: return count;
1172: }
1173:
1174: public procreturn(f)
1175: Symbol f;
1176: {
1177: integer retvalsize;
1178: Node tmp;
1179: char *copy;
1180:
1181: flushoutput();
1182: popenv();
1183: if (endproc.isfunc) {
1184: retvalsize = size(f->type);
1185: if (retvalsize > sizeof(long)) {
1186: pushretval(retvalsize, true);
1187: copy = newarr(char, retvalsize);
1188: popn(retvalsize, copy);
1189: tmp = build(O_SCON, copy);
1190: } else {
1191: tmp = build(O_LCON, (long) (reg(0)));
1192: }
1193: tmp->nodetype = f->type;
1194: tfree(endproc.callnode);
1195: *(endproc.callnode) = *(tmp);
1196: dispose(tmp);
1197: eval(endproc.cmdnode);
1198: } else {
1199: putchar('\n');
1200: printname(stdout, f);
1201: printf(" returns successfully\n");
1202: }
1203: erecover();
1204: }
1205:
1206: /*
1207: * Push the current environment.
1208: */
1209:
1210: private pushenv()
1211: {
1212: push(Address, pc);
1213: push(Lineno, curline);
1214: push(String, cursource);
1215: push(Boolean, isstopped);
1216: push(Symbol, curfunc);
1217: push(Frame, curframe);
1218: push(struct Frame, curframerec);
1219: push(CallEnv, endproc);
1220: push(Word, reg(PROGCTR));
1221: push(Word, reg(STKP));
1222: push(Word, reg(FRP));
1223: }
1224:
1225: /*
1226: * Pop back to the real world.
1227: */
1228:
1229: public popenv()
1230: {
1231: String filename;
1232:
1233: setreg(FRP, pop(Word));
1234: setreg(STKP, pop(Word));
1235: setreg(PROGCTR, pop(Word));
1236: endproc = pop(CallEnv);
1237: curframerec = pop(struct Frame);
1238: curframe = pop(Frame);
1239: curfunc = pop(Symbol);
1240: isstopped = pop(Boolean);
1241: filename = pop(String);
1242: curline = pop(Lineno);
1243: pc = pop(Address);
1244: setsource(filename);
1245: }
1246:
1247: /*
1248: * Flush the debuggee's standard output.
1249: *
1250: * This is VERY dependent on the use of stdio.
1251: */
1252:
1253: public flushoutput()
1254: {
1255: Symbol p, iob;
1256: Stack *savesp;
1257:
1258: p = lookup(identname("fflush", true));
1259: while (p != nil and not isblock(p)) {
1260: p = p->next_sym;
1261: }
1262: if (p != nil) {
1263: iob = lookup(identname("_iob", true));
1264: if (iob != nil) {
1265: pushenv();
1266: pc = codeloc(p) - FUNCOFFSET;
1267: savesp = sp;
1268: push(long, address(iob, nil) + sizeof(*stdout));
1269: setreg(STKP, reg(STKP) - sizeof(long));
1270: dwrite(savesp, reg(STKP), sizeof(long));
1271: sp = savesp;
1272: beginproc(p, 1);
1273: stepto(return_addr());
1274: popenv();
1275: }
1276: }
1277: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.