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