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