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