|
|
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[] = "@(#)runtime.vax.c 5.5 (Berkeley) 6/1/90";
22: #endif /* not lint */
23:
24: /*
25: * Runtime organization dependent routines, mostly dealing with
26: * activation records.
27: */
28:
29: #include "defs.h"
30: #include "runtime.h"
31: #include "process.h"
32: #include "machine.h"
33: #include "events.h"
34: #include "mappings.h"
35: #include "symbols.h"
36: #include "tree.h"
37: #include "eval.h"
38: #include "operators.h"
39: #include "object.h"
40: #include <sys/param.h>
41: #include <signal.h>
42:
43: #ifndef public
44: typedef struct Frame *Frame;
45:
46: #include "machine.h"
47: #endif
48:
49: #define NSAVEREG 12
50:
51: struct Frame {
52: integer condition_handler;
53: integer mask;
54: Address save_ap; /* argument pointer */
55: Address save_fp; /* frame pointer */
56: Address save_pc; /* program counter */
57: Word save_reg[NSAVEREG]; /* not necessarily there */
58: };
59:
60: private Frame curframe = nil;
61: private struct Frame curframerec;
62: private Boolean walkingstack = false;
63:
64: #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
65:
66: #define inSignalHandler(addr) \
67: (((addr) < 0x80000000) and ((addr) > 0x80000000 - ctob(UPAGES)))
68:
69: typedef struct {
70: Node callnode;
71: Node cmdnode;
72: boolean isfunc;
73: } CallEnv;
74:
75: private CallEnv endproc;
76:
77: /*
78: * Set a frame to the current activation record.
79: */
80:
81: private getcurframe(frp)
82: Frame frp;
83: {
84: register int i;
85:
86: checkref(frp);
87: frp->mask = reg(NREG);
88: frp->save_ap = reg(ARGP);
89: frp->save_fp = reg(FRP);
90: frp->save_pc = reg(PROGCTR);
91: for (i = 0; i < NSAVEREG; i++) {
92: frp->save_reg[i] = reg(i);
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;
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: ntramp++;
176: prev_frame = frame.save_fp;
177: goto nextf;
178: }
179: frame.save_pc = callpc;
180: ntramp = 0;
181: newfrp->save_fp = frame.save_fp;
182: newfrp->save_pc = frame.save_pc;
183: mask = ((frame.mask >> 16) & 0x0fff);
184: getsaveregs(newfrp, &frame, mask);
185: newfrp->condition_handler = frame.condition_handler;
186: newfrp->mask = mask;
187: newfrp->save_ap = frame.save_ap;
188: }
189: return newfrp;
190: }
191:
192: /*
193: * Get the current frame information in the given Frame and store the
194: * associated function in the given value-result parameter.
195: */
196:
197: private getcurfunc (frp, fp)
198: Frame frp;
199: Symbol *fp;
200: {
201: getcurframe(frp);
202: *fp = whatblock(frp->save_pc);
203: }
204:
205: /*
206: * Return the frame associated with the next function up the call stack, or
207: * nil if there is none. The function is returned in a value-result parameter.
208: * For "inline" functions the statically outer function and same frame
209: * are returned.
210: */
211:
212: public Frame nextfunc (frp, fp)
213: Frame frp;
214: Symbol *fp;
215: {
216: Symbol t;
217: Frame nfrp;
218:
219: t = *fp;
220: checkref(t);
221: if (isinline(t)) {
222: t = container(t);
223: nfrp = frp;
224: } else {
225: nfrp = nextframe(frp);
226: if (nfrp == nil) {
227: t = nil;
228: } else {
229: t = whatblock(nfrp->save_pc);
230: }
231: }
232: *fp = t;
233: return nfrp;
234: }
235:
236: /*
237: * Return the frame associated with the given function.
238: * If the function is nil, return the most recently activated frame.
239: *
240: * Static allocation for the frame.
241: */
242:
243: public Frame findframe(f)
244: Symbol f;
245: {
246: Frame frp;
247: static struct Frame frame;
248: Symbol p;
249: Boolean done;
250:
251: frp = &frame;
252: getcurframe(frp);
253: if (f != nil) {
254: if (f == curfunc and curframe != nil) {
255: *frp = *curframe;
256: } else {
257: done = false;
258: p = whatblock(frp->save_pc);
259: do {
260: if (p == f) {
261: done = true;
262: } else if (p == program) {
263: done = true;
264: frp = nil;
265: } else {
266: frp = nextfunc(frp, &p);
267: if (frp == nil) {
268: done = true;
269: }
270: }
271: } while (not done);
272: }
273: }
274: return frp;
275: }
276:
277: /*
278: * Set the registers according to the given frame pointer.
279: */
280:
281: public getnewregs (addr)
282: Address addr;
283: {
284: struct Frame frame;
285: integer i, j, mask;
286:
287: dread(&frame, addr, sizeof(frame));
288: setreg(FRP, frame.save_fp);
289: setreg(PROGCTR, frame.save_pc);
290: setreg(ARGP, frame.save_ap);
291: mask = ((frame.mask >> 16) & 0x0fff);
292: j = 0;
293: for (i = 0; i < NSAVEREG; i++) {
294: if (bis(mask, i)) {
295: setreg(i, frame.save_reg[j]);
296: ++j;
297: }
298: }
299: pc = frame.save_pc;
300: setcurfunc(whatblock(pc));
301: }
302:
303: /*
304: * Find the return address of the current procedure/function.
305: */
306:
307: public Address return_addr()
308: {
309: Frame frp;
310: Address addr;
311: struct Frame frame;
312:
313: frp = &frame;
314: getcurframe(frp);
315: frp = nextframe(frp);
316: if (frp == nil) {
317: addr = 0;
318: } else {
319: addr = frp->save_pc;
320: }
321: return addr;
322: }
323:
324: /*
325: * Push the value associated with the current function.
326: */
327:
328: public pushretval(len, isindirect)
329: integer len;
330: boolean isindirect;
331: {
332: Word r0;
333:
334: r0 = reg(0);
335: if (isindirect) {
336: rpush((Address) r0, len);
337: } else {
338: switch (len) {
339: case sizeof(char):
340: push(char, r0);
341: break;
342:
343: case sizeof(short):
344: push(short, r0);
345: break;
346:
347: default:
348: if (len == sizeof(Word)) {
349: push(Word, r0);
350: } else if (len == 2*sizeof(Word)) {
351: push(Word, r0);
352: push(Word, reg(1));
353: } else {
354: error("[internal error: bad size %d in pushretval]", len);
355: }
356: break;
357: }
358: }
359: }
360:
361: /*
362: * Return the base address for locals in the given frame.
363: */
364:
365: public Address locals_base(frp)
366: Frame frp;
367: {
368: return (frp == nil) ? reg(FRP) : frp->save_fp;
369: }
370:
371: /*
372: * Return the base address for arguments in the given frame.
373: */
374:
375: public Address args_base(frp)
376: Frame frp;
377: {
378: return (frp == nil) ? reg(ARGP) : frp->save_ap;
379: }
380:
381: /*
382: * Return saved register n from the given frame.
383: */
384:
385: public Word savereg(n, frp)
386: integer n;
387: Frame frp;
388: {
389: Word w;
390:
391: if (frp == nil) {
392: w = reg(n);
393: } else {
394: switch (n) {
395: case ARGP:
396: w = frp->save_ap;
397: break;
398:
399: case FRP:
400: w = frp->save_fp;
401: break;
402:
403: case STKP:
404: w = reg(STKP);
405: break;
406:
407: case PROGCTR:
408: w = frp->save_pc;
409: break;
410:
411: default:
412: assert(n >= 0 and n < NSAVEREG);
413: w = frp->save_reg[n];
414: break;
415: }
416: }
417: return w;
418: }
419:
420: /*
421: * Return the nth argument to the current procedure.
422: */
423:
424: public Word argn(n, frp)
425: integer n;
426: Frame frp;
427: {
428: Address argaddr;
429: Word w;
430:
431: argaddr = args_base(frp) + (n * sizeof(Word));
432: dread(&w, argaddr, sizeof(w));
433: return w;
434: }
435:
436: /*
437: * Print a list of currently active blocks starting with most recent.
438: */
439:
440: public wherecmd()
441: {
442: walkstack(false);
443: }
444:
445: /*
446: * Print the variables in the given frame or the current one if nil.
447: */
448:
449: public dump (func)
450: Symbol func;
451: {
452: Symbol f;
453: Frame frp;
454:
455: if (func == nil) {
456: f = curfunc;
457: if (curframe != nil) {
458: frp = curframe;
459: } else {
460: frp = findframe(f);
461: }
462: } else {
463: f = func;
464: frp = findframe(f);
465: }
466: showaggrs = true;
467: printcallinfo(f, frp);
468: dumpvars(f, frp);
469: }
470:
471: /*
472: * Dump all values.
473: */
474:
475: public dumpall ()
476: {
477: walkstack(true);
478: }
479:
480: /*
481: * Walk the stack of active procedures printing information
482: * about each active procedure.
483: */
484:
485: private walkstack(dumpvariables)
486: Boolean dumpvariables;
487: {
488: Frame frp;
489: boolean save;
490: Symbol f;
491: struct Frame frame;
492:
493: if (notstarted(process) or isfinished(process)) {
494: error("program is not active");
495: } else {
496: save = walkingstack;
497: walkingstack = true;
498: showaggrs = dumpvariables;
499: frp = &frame;
500: getcurfunc(frp, &f);
501: for (;;) {
502: printcallinfo(f, frp);
503: if (dumpvariables) {
504: dumpvars(f, frp);
505: putchar('\n');
506: }
507: frp = nextfunc(frp, &f);
508: if (frp == nil or f == program) {
509: break;
510: }
511: }
512: if (dumpvariables) {
513: printf("in \"%s\":\n", symname(program));
514: dumpvars(program, nil);
515: putchar('\n');
516: }
517: walkingstack = save;
518: }
519: }
520:
521: /*
522: * Print out the information about a call, i.e.,
523: * routine name, parameter values, and source location.
524: */
525:
526: private printcallinfo (f, frp)
527: Symbol f;
528: Frame frp;
529: {
530: Lineno line;
531: Address savepc;
532:
533: savepc = frp->save_pc;
534: if (frp->save_fp != reg(FRP)) {
535: savepc -= 1;
536: }
537: printname(stdout, f);
538: if (not isinline(f)) {
539: printparams(f, frp);
540: }
541: line = srcline(savepc);
542: if (line != 0) {
543: printf(", line %d", line);
544: printf(" in \"%s\"\n", srcfilename(savepc));
545: } else {
546: printf(" at 0x%x\n", savepc);
547: }
548: }
549:
550: /*
551: * Set the current function to the given symbol.
552: * We must adjust "curframe" so that subsequent operations are
553: * not confused; for simplicity we simply clear it.
554: */
555:
556: public setcurfunc (f)
557: Symbol f;
558: {
559: curfunc = f;
560: curframe = nil;
561: }
562:
563: /*
564: * Return the frame for the current function.
565: * The space for the frame is allocated statically.
566: */
567:
568: public Frame curfuncframe ()
569: {
570: static struct Frame frame;
571: Frame frp;
572:
573: if (curframe == nil) {
574: frp = findframe(curfunc);
575: curframe = &curframerec;
576: *curframe = *frp;
577: } else {
578: frp = &frame;
579: *frp = *curframe;
580: }
581: return frp;
582: }
583:
584: /*
585: * Set curfunc to be N up/down the stack from its current value.
586: */
587:
588: public up (n)
589: integer n;
590: {
591: integer i;
592: Symbol f;
593: Frame frp;
594: boolean done;
595:
596: if (not isactive(program)) {
597: error("program is not active");
598: } else if (curfunc == nil) {
599: error("no current function");
600: } else {
601: i = 0;
602: f = curfunc;
603: frp = curfuncframe();
604: done = false;
605: do {
606: if (frp == nil) {
607: done = true;
608: error("not that many levels");
609: } else if (i >= n) {
610: done = true;
611: curfunc = f;
612: curframe = &curframerec;
613: *curframe = *frp;
614: showaggrs = false;
615: printcallinfo(curfunc, curframe);
616: } else if (f == program) {
617: done = true;
618: error("not that many levels");
619: } else {
620: frp = nextfunc(frp, &f);
621: }
622: ++i;
623: } while (not done);
624: }
625: }
626:
627: public down (n)
628: integer n;
629: {
630: integer i, depth;
631: Frame frp, curfrp;
632: Symbol f;
633: struct Frame frame;
634:
635: if (not isactive(program)) {
636: error("program is not active");
637: } else if (curfunc == nil) {
638: error("no current function");
639: } else {
640: depth = 0;
641: frp = &frame;
642: getcurfunc(frp, &f);
643: if (curframe == nil) {
644: curfrp = findframe(curfunc);
645: curframe = &curframerec;
646: *curframe = *curfrp;
647: }
648: while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
649: frp = nextfunc(frp, &f);
650: ++depth;
651: }
652: if (f == nil or n > depth) {
653: error("not that many levels");
654: } else {
655: depth -= n;
656: frp = &frame;
657: getcurfunc(frp, &f);
658: for (i = 0; i < depth; i++) {
659: frp = nextfunc(frp, &f);
660: assert(frp != nil);
661: }
662: curfunc = f;
663: *curframe = *frp;
664: showaggrs = false;
665: printcallinfo(curfunc, curframe);
666: }
667: }
668: }
669:
670: /*
671: * Find the entry point of a procedure or function.
672: *
673: * On the VAX we add the size of the register mask (FUNCOFFSET) or
674: * the size of the Modula-2 internal entry sequence, on other machines
675: * (68000's) we add the entry sequence size (FUNCOFFSET) unless
676: * we're right at the beginning of the program.
677: */
678:
679: public findbeginning (f)
680: Symbol f;
681: {
682: if (isinternal(f)) {
683: f->symvalue.funcv.beginaddr += 18; /* VAX only */
684: } else {
685: f->symvalue.funcv.beginaddr += FUNCOFFSET;
686: }
687: }
688:
689: /*
690: * Return the address corresponding to the first line in a function.
691: */
692:
693: public Address firstline(f)
694: Symbol f;
695: {
696: Address addr;
697:
698: addr = codeloc(f);
699: while (linelookup(addr) == 0 and addr < objsize) {
700: ++addr;
701: }
702: if (addr == objsize) {
703: addr = -1;
704: }
705: return addr;
706: }
707:
708: /*
709: * Catcher drops strike three ...
710: */
711:
712: public runtofirst()
713: {
714: Address addr, endaddr;
715:
716: addr = pc;
717: endaddr = objsize + CODESTART;
718: while (linelookup(addr) == 0 and addr < endaddr) {
719: ++addr;
720: }
721: if (addr < endaddr) {
722: stepto(addr);
723: }
724: }
725:
726: /*
727: * Return the address corresponding to the end of the program.
728: *
729: * We look for the entry to "exit".
730: */
731:
732: public Address lastaddr()
733: {
734: Symbol s;
735:
736: s = lookup(identname("exit", true));
737: if (s == nil) {
738: panic("can't find exit");
739: }
740: return codeloc(s);
741: }
742:
743: /*
744: * Decide if the given function is currently active.
745: *
746: * We avoid calls to "findframe" during a stack trace for efficiency.
747: * Presumably information evaluated while walking the stack is active.
748: */
749:
750: public Boolean isactive (f)
751: Symbol f;
752: {
753: Boolean b;
754:
755: if (isfinished(process)) {
756: b = false;
757: } else {
758: if (walkingstack or f == program or f == nil or
759: (ismodule(f) and isactive(container(f)))) {
760: b = true;
761: } else {
762: b = (Boolean) (findframe(f) != nil);
763: }
764: }
765: return b;
766: }
767:
768: /*
769: * Evaluate a call to a procedure.
770: */
771:
772: public callproc(exprnode, isfunc)
773: Node exprnode;
774: boolean isfunc;
775: {
776: Node procnode, arglist;
777: Symbol proc;
778: integer argc;
779:
780: procnode = exprnode->value.arg[0];
781: arglist = exprnode->value.arg[1];
782: if (procnode->op != O_SYM) {
783: beginerrmsg();
784: fprintf(stderr, "can't call \"");
785: prtree(stderr, procnode);
786: fprintf(stderr, "\"");
787: enderrmsg();
788: }
789: assert(procnode->op == O_SYM);
790: proc = procnode->value.sym;
791: if (not isblock(proc)) {
792: error("\"%s\" is not a procedure or function", symname(proc));
793: }
794: endproc.isfunc = isfunc;
795: endproc.callnode = exprnode;
796: endproc.cmdnode = topnode;
797: pushenv();
798: pc = codeloc(proc);
799: argc = pushargs(proc, arglist);
800: setreg(FRP, 1); /* have to ensure it's non-zero for return_addr() */
801: beginproc(proc, argc);
802: event_once(
803: build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
804: buildcmdlist(build(O_PROCRTN, proc))
805: );
806: isstopped = false;
807: if (not bpact()) {
808: isstopped = true;
809: cont(0);
810: }
811: /*
812: * bpact() won't return true, it will call printstatus() and go back
813: * to command input if a breakpoint is found.
814: */
815: /* NOTREACHED */
816: }
817:
818: /*
819: * Push the arguments on the process' stack. We do this by first
820: * evaluating them on the "eval" stack, then copying into the process'
821: * space.
822: */
823:
824: private integer pushargs(proc, arglist)
825: Symbol proc;
826: Node arglist;
827: {
828: Stack *savesp;
829: int argc, args_size;
830:
831: savesp = sp;
832: if (varIsSet("$unsafecall")) {
833: argc = unsafe_evalargs(proc, arglist);
834: } else {
835: argc = evalargs(proc, arglist);
836: }
837: args_size = sp - savesp;
838: setreg(STKP, reg(STKP) - args_size);
839: dwrite(savesp, reg(STKP), args_size);
840: sp = savesp;
841: return argc;
842: }
843:
844: /*
845: * Check to see if an expression is correct for a given parameter.
846: * If the given parameter is false, don't worry about type inconsistencies.
847: *
848: * Return whether or not it is ok.
849: */
850:
851: private boolean chkparam (actual, formal, chk)
852: Node actual;
853: Symbol formal;
854: boolean chk;
855: {
856: boolean b;
857:
858: b = true;
859: if (chk) {
860: if (formal == nil) {
861: beginerrmsg();
862: fprintf(stderr, "too many parameters");
863: b = false;
864: } else if (not compatible(formal->type, actual->nodetype)) {
865: beginerrmsg();
866: fprintf(stderr, "type mismatch for %s", symname(formal));
867: b = false;
868: }
869: }
870: if (b and formal != nil and
871: isvarparam(formal) and not isopenarray(formal->type) and
872: not (
873: actual->op == O_RVAL or actual->nodetype == t_addr or
874: (
875: actual->op == O_TYPERENAME and
876: (
877: actual->value.arg[0]->op == O_RVAL or
878: actual->value.arg[0]->nodetype == t_addr
879: )
880: )
881: )
882: ) {
883: beginerrmsg();
884: fprintf(stderr, "expected variable, found \"");
885: prtree(stderr, actual);
886: fprintf(stderr, "\"");
887: b = false;
888: }
889: return b;
890: }
891:
892: /*
893: * Pass an expression to a particular parameter.
894: *
895: * Normally we pass either the address or value, but in some cases
896: * (such as C strings) we want to copy the value onto the stack and
897: * pass its address.
898: *
899: * Another special case raised by strings is the possibility that
900: * the actual parameter will be larger than the formal, even with
901: * appropriate type-checking. This occurs because we assume during
902: * evaluation that strings are null-terminated, whereas some languages,
903: * notably Pascal, do not work under that assumption.
904: */
905:
906: private passparam (actual, formal)
907: Node actual;
908: Symbol formal;
909: {
910: boolean b;
911: Address addr;
912: Stack *savesp;
913: integer actsize, formsize;
914:
915: if (formal != nil and isvarparam(formal) and
916: (not isopenarray(formal->type))
917: ) {
918: addr = lval(actual->value.arg[0]);
919: push(Address, addr);
920: } else if (passaddr(formal, actual->nodetype)) {
921: savesp = sp;
922: eval(actual);
923: actsize = sp - savesp;
924: setreg(STKP,
925: reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
926: );
927: dwrite(savesp, reg(STKP), actsize);
928: sp = savesp;
929: push(Address, reg(STKP));
930: if (formal != nil and isopenarray(formal->type)) {
931: push(integer, actsize div size(formal->type->type));
932: }
933: } else if (formal != nil) {
934: formsize = size(formal);
935: savesp = sp;
936: eval(actual);
937: actsize = sp - savesp;
938: if (actsize > formsize) {
939: sp -= (actsize - formsize);
940: }
941: } else {
942: eval(actual);
943: }
944: }
945:
946: /*
947: * Evaluate an argument list left-to-right.
948: */
949:
950: private integer evalargs(proc, arglist)
951: Symbol proc;
952: Node arglist;
953: {
954: Node p, actual;
955: Symbol formal;
956: Stack *savesp;
957: integer count;
958: boolean chk;
959:
960: savesp = sp;
961: count = 0;
962: formal = proc->chain;
963: chk = (boolean) (not nosource(proc));
964: for (p = arglist; p != nil; p = p->value.arg[1]) {
965: assert(p->op == O_COMMA);
966: actual = p->value.arg[0];
967: if (not chkparam(actual, formal, chk)) {
968: fprintf(stderr, " in call to %s", symname(proc));
969: sp = savesp;
970: enderrmsg();
971: }
972: passparam(actual, formal);
973: if (formal != nil) {
974: formal = formal->chain;
975: }
976: ++count;
977: }
978: if (chk) {
979: if (formal != nil) {
980: sp = savesp;
981: error("not enough parameters to %s", symname(proc));
982: }
983: }
984: return count;
985: }
986:
987: /*
988: * Evaluate an argument list without any type checking.
989: * This is only useful for procedures with a varying number of
990: * arguments that are compiled -g.
991: */
992:
993: private integer unsafe_evalargs (proc, arglist)
994: Symbol proc;
995: Node arglist;
996: {
997: Node p;
998: integer count;
999:
1000: count = 0;
1001: for (p = arglist; p != nil; p = p->value.arg[1]) {
1002: assert(p->op == O_COMMA);
1003: eval(p->value.arg[0]);
1004: ++count;
1005: }
1006: return count;
1007: }
1008:
1009: public procreturn(f)
1010: Symbol f;
1011: {
1012: integer retvalsize;
1013: Node tmp;
1014: char *copy;
1015:
1016: flushoutput();
1017: popenv();
1018: if (endproc.isfunc) {
1019: retvalsize = size(f->type);
1020: if (retvalsize > sizeof(long)) {
1021: pushretval(retvalsize, true);
1022: copy = newarr(char, retvalsize);
1023: popn(retvalsize, copy);
1024: tmp = build(O_SCON, copy);
1025: } else {
1026: tmp = build(O_LCON, (long) (reg(0)));
1027: }
1028: tmp->nodetype = f->type;
1029: tfree(endproc.callnode);
1030: *(endproc.callnode) = *(tmp);
1031: dispose(tmp);
1032: eval(endproc.cmdnode);
1033: } else {
1034: putchar('\n');
1035: printname(stdout, f);
1036: printf(" returns successfully\n");
1037: }
1038: erecover();
1039: }
1040:
1041: /*
1042: * Push the current environment.
1043: */
1044:
1045: private pushenv()
1046: {
1047: push(Address, pc);
1048: push(Lineno, curline);
1049: push(String, cursource);
1050: push(Boolean, isstopped);
1051: push(Symbol, curfunc);
1052: push(Frame, curframe);
1053: push(struct Frame, curframerec);
1054: push(CallEnv, endproc);
1055: push(Word, reg(PROGCTR));
1056: push(Word, reg(STKP));
1057: push(Word, reg(FRP));
1058: }
1059:
1060: /*
1061: * Pop back to the real world.
1062: */
1063:
1064: public popenv()
1065: {
1066: String filename;
1067:
1068: setreg(FRP, pop(Word));
1069: setreg(STKP, pop(Word));
1070: setreg(PROGCTR, pop(Word));
1071: endproc = pop(CallEnv);
1072: curframerec = pop(struct Frame);
1073: curframe = pop(Frame);
1074: curfunc = pop(Symbol);
1075: isstopped = pop(Boolean);
1076: filename = pop(String);
1077: curline = pop(Lineno);
1078: pc = pop(Address);
1079: setsource(filename);
1080: }
1081:
1082: /*
1083: * Flush the debuggee's standard output.
1084: *
1085: * This is VERY dependent on the use of stdio.
1086: */
1087:
1088: public flushoutput()
1089: {
1090: Symbol p, iob;
1091: Stack *savesp;
1092:
1093: p = lookup(identname("fflush", true));
1094: while (p != nil and not isblock(p)) {
1095: p = p->next_sym;
1096: }
1097: if (p != nil) {
1098: iob = lookup(identname("_iob", true));
1099: if (iob != nil) {
1100: pushenv();
1101: pc = codeloc(p) - FUNCOFFSET;
1102: savesp = sp;
1103: push(long, address(iob, nil) + sizeof(*stdout));
1104: setreg(STKP, reg(STKP) - sizeof(long));
1105: dwrite(savesp, reg(STKP), sizeof(long));
1106: sp = savesp;
1107: beginproc(p, 1);
1108: stepto(return_addr());
1109: popenv();
1110: }
1111: }
1112: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.