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