install with -s
[unix-history] / usr / src / old / dbx / runtime.vax.c
CommitLineData
2a24676e
DF
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 */
52646e6f 6
2a24676e
DF
7#ifndef lint
8static char sccsid[] = "@(#)runtime.vax.c 5.1 (Berkeley) %G%";
9#endif not lint
0022c355
ML
10
11static char rcsid[] = "$Header: runtime.c,v 1.5 84/12/26 10:41:52 linton Exp $";
52646e6f
ML
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"
381c0f0e 29#include <sys/param.h>
52646e6f
ML
30
31#ifndef public
32typedef struct Frame *Frame;
33
34#include "machine.h"
35#endif
36
37#define NSAVEREG 12
38
39struct Frame {
0022c355
ML
40 integer condition_handler;
41 integer mask;
52646e6f
ML
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
2fd0f574
SL
48private Frame curframe = nil;
49private struct Frame curframerec;
52646e6f
ML
50private Boolean walkingstack = false;
51
2fd0f574
SL
52#define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
53
0022c355
ML
54#define isstackaddr(addr) \
55 (((addr) < 0x80000000) and ((addr) > 0x80000000 - 0x200 * UPAGES))
56
57typedef struct {
58 Node callnode;
59 Node cmdnode;
60 boolean isfunc;
61} CallEnv;
62
63private CallEnv endproc;
64
52646e6f
ML
65/*
66 * Set a frame to the current activation record.
67 */
68
69private getcurframe(frp)
0022c355 70Frame frp;
52646e6f
ML
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);
0022c355 78 frp->save_pc = reg(PROGCTR);
52646e6f
ML
79 for (i = 0; i < NSAVEREG; i++) {
80 frp->save_reg[i] = reg(i);
81 }
82}
83
0022c355
ML
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
91private getsaveregs (newfrp, frp, mask)
92Frame newfrp, frp;
93integer 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
52646e6f
ML
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
52646e6f
ML
112private Frame nextframe(frp)
113Frame frp;
114{
0022c355 115 Frame newfrp;
52646e6f 116 struct Frame frame;
0022c355 117 integer mask;
381c0f0e 118 Address prev_frame, callpc;
0022c355 119 static integer ntramp = 0;
52646e6f
ML
120
121 newfrp = frp;
381c0f0e
AF
122 prev_frame = frp->save_fp;
123
316d2228
ML
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>.
381c0f0e
AF
128 *
129 * As best I can make out it looks like:
316d2228
ML
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.
381c0f0e
AF
136 *
137 * The addr in sub at which the exception occured is not in sub.save_pc
316d2228 138 * but in the machine check exception block. It is at the magic address
8d44f3a5 139 * fp + 84.
381c0f0e
AF
140 *
141 * The current approach ignores the sys_frame (what adb reports as sigtramp)
316d2228
ML
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.
381c0f0e 144 */
381c0f0e 145
316d2228
ML
146nextf:
147 dread(&frame, prev_frame, sizeof(struct Frame));
148 if (ntramp == 1) {
8d44f3a5 149 dread(&callpc, prev_frame + 84, sizeof(callpc));
316d2228
ML
150 } else {
151 callpc = frame.save_pc;
152 }
0022c355 153 if (frame.save_fp == nil or frame.save_pc == (Address) -1) {
52646e6f 154 newfrp = nil;
0022c355
ML
155 } else if (isstackaddr(callpc)) {
156 ntramp++;
157 prev_frame = frame.save_fp;
158 goto nextf;
316d2228 159 } else {
381c0f0e 160 frame.save_pc = callpc;
316d2228 161 ntramp = 0;
52646e6f 162 mask = ((frame.mask >> 16) & 0x0fff);
0022c355 163 getsaveregs(newfrp, &frame, mask);
52646e6f
ML
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
2fd0f574
SL
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
178private getcurfunc (frp, fp)
179Frame frp;
180Symbol *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
0022c355 193public Frame nextfunc (frp, fp)
2fd0f574
SL
194Frame frp;
195Symbol *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
52646e6f
ML
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
224public Frame findframe(f)
225Symbol f;
226{
0022c355 227 Frame frp;
52646e6f 228 static struct Frame frame;
4fd956ac 229 Symbol p;
0022c355 230 Boolean done;
52646e6f
ML
231
232 frp = &frame;
233 getcurframe(frp);
0022c355
ML
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);
912533aa 253 }
0022c355
ML
254 }
255 return frp;
256}
257
258/*
259 * Set the registers according to the given frame pointer.
260 */
261
262public getnewregs (addr)
263Address 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;
912533aa 278 }
52646e6f 279 }
0022c355
ML
280 pc = frame.save_pc;
281 setcurfunc(whatblock(pc));
52646e6f
ML
282}
283
284/*
285 * Find the return address of the current procedure/function.
286 */
287
288public 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
309public pushretval(len, isindirect)
0022c355
ML
310integer len;
311boolean isindirect;
52646e6f
ML
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 {
0022c355 335 error("[internal error: bad size %d in pushretval]", len);
52646e6f
ML
336 }
337 break;
338 }
339 }
340}
341
342/*
343 * Return the base address for locals in the given frame.
344 */
345
346public Address locals_base(frp)
0022c355 347Frame frp;
52646e6f
ML
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
356public Address args_base(frp)
0022c355 357Frame frp;
52646e6f
ML
358{
359 return (frp == nil) ? reg(ARGP) : frp->save_ap;
360}
361
362/*
363 * Return saved register n from the given frame.
364 */
365
366public Word savereg(n, frp)
0022c355
ML
367integer n;
368Frame frp;
52646e6f 369{
0022c355 370 Word w;
52646e6f
ML
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
405public Word argn(n, frp)
0022c355 406integer n;
52646e6f
ML
407Frame frp;
408{
409 Word w;
410
411 dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
412 return w;
413}
414
415/*
0022c355 416 * Print a list of currently active blocks starting with most recent.
52646e6f
ML
417 */
418
0022c355 419public wherecmd()
52646e6f 420{
0022c355 421 walkstack(false);
52646e6f
ML
422}
423
424/*
0022c355 425 * Print the variables in the given frame or the current one if nil.
52646e6f
ML
426 */
427
0022c355
ML
428public dump (func)
429Symbol func;
52646e6f 430{
0022c355
ML
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);
52646e6f
ML
448}
449
450/*
0022c355 451 * Dump all values.
52646e6f
ML
452 */
453
0022c355 454public dumpall ()
52646e6f
ML
455{
456 walkstack(true);
457}
458
459/*
460 * Walk the stack of active procedures printing information
461 * about each active procedure.
462 */
463
52646e6f
ML
464private walkstack(dumpvariables)
465Boolean dumpvariables;
466{
0022c355
ML
467 Frame frp;
468 boolean save;
2fd0f574 469 Symbol f;
52646e6f
ML
470 struct Frame frame;
471
0022c355 472 if (notstarted(process) or isfinished(process)) {
52646e6f
ML
473 error("program is not active");
474 } else {
475 save = walkingstack;
476 walkingstack = true;
0022c355 477 showaggrs = dumpvariables;
52646e6f 478 frp = &frame;
2fd0f574 479 getcurfunc(frp, &f);
0022c355
ML
480 for (;;) {
481 printcallinfo(f, frp);
52646e6f
ML
482 if (dumpvariables) {
483 dumpvars(f, frp);
484 putchar('\n');
485 }
2fd0f574 486 frp = nextfunc(frp, &f);
0022c355
ML
487 if (frp == nil or f == program) {
488 break;
489 }
490 }
52646e6f
ML
491 if (dumpvariables) {
492 printf("in \"%s\":\n", symname(program));
493 dumpvars(program, nil);
494 putchar('\n');
495 }
496 walkingstack = save;
497 }
498}
499
0022c355
ML
500/*
501 * Print out the information about a call, i.e.,
502 * routine name, parameter values, and source location.
503 */
504
505private printcallinfo (f, frp)
506Symbol f;
507Frame 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
2fd0f574
SL
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
535public setcurfunc (f)
536Symbol f;
537{
538 curfunc = f;
539 curframe = nil;
540}
541
0022c355
ML
542/*
543 * Return the frame for the current function.
544 * The space for the frame is allocated statically.
545 */
546
547public 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
2fd0f574
SL
563/*
564 * Set curfunc to be N up/down the stack from its current value.
565 */
566
567public up (n)
568integer 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;
0022c355 582 frp = curfuncframe();
2fd0f574
SL
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;
0022c355
ML
593 showaggrs = false;
594 printcallinfo(curfunc, curframe);
2fd0f574
SL
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
606public down (n)
607integer n;
608{
609 integer i, depth;
0022c355 610 Frame frp, curfrp;
2fd0f574
SL
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) {
0022c355 623 curfrp = findframe(curfunc);
2fd0f574 624 curframe = &curframerec;
0022c355 625 *curframe = *curfrp;
2fd0f574
SL
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;
0022c355
ML
643 showaggrs = false;
644 printcallinfo(curfunc, curframe);
2fd0f574
SL
645 }
646 }
647}
648
52646e6f
ML
649/*
650 * Find the entry point of a procedure or function.
651 */
652
0022c355 653public findbeginning (f)
52646e6f
ML
654Symbol f;
655{
2fd0f574
SL
656 if (isinternal(f)) {
657 f->symvalue.funcv.beginaddr += 15;
658 } else {
659 f->symvalue.funcv.beginaddr += 2;
660 }
52646e6f
ML
661}
662
663/*
664 * Return the address corresponding to the first line in a function.
665 */
666
667public Address firstline(f)
668Symbol 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
686public 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
705public Address lastaddr()
706{
0022c355 707 Symbol s;
52646e6f
ML
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
723public Boolean isactive(f)
724Symbol f;
725{
0022c355 726 Boolean b;
52646e6f
ML
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
0022c355
ML
745public callproc(exprnode, isfunc)
746Node exprnode;
747boolean isfunc;
52646e6f 748{
0022c355 749 Node procnode, arglist;
52646e6f 750 Symbol proc;
0022c355 751 integer argc;
52646e6f 752
0022c355
ML
753 procnode = exprnode->value.arg[0];
754 arglist = exprnode->value.arg[1];
52646e6f
ML
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 }
0022c355
ML
767 endproc.isfunc = isfunc;
768 endproc.callnode = exprnode;
769 endproc.cmdnode = topnode;
52646e6f
ML
770 pushenv();
771 pc = codeloc(proc);
772 argc = pushargs(proc, arglist);
773 beginproc(proc, argc);
0022c355
ML
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 */
52646e6f
ML
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
0022c355 796private integer pushargs(proc, arglist)
52646e6f
ML
797Symbol proc;
798Node arglist;
799{
800 Stack *savesp;
801 int argc, args_size;
802
803 savesp = sp;
804 argc = evalargs(proc, arglist);
805 args_size = sp - savesp;
806 setreg(STKP, reg(STKP) - args_size);
807 dwrite(savesp, reg(STKP), args_size);
808 sp = savesp;
809 return argc;
810}
811
812/*
2fd0f574
SL
813 * Check to see if an expression is correct for a given parameter.
814 * If the given parameter is false, don't worry about type inconsistencies.
815 *
816 * Return whether or not it is ok.
817 */
818
819private boolean chkparam (actual, formal, chk)
820Node actual;
821Symbol formal;
822boolean chk;
823{
824 boolean b;
825
826 b = true;
827 if (chk) {
828 if (formal == nil) {
829 beginerrmsg();
830 fprintf(stderr, "too many parameters");
831 b = false;
832 } else if (not compatible(formal->type, actual->nodetype)) {
833 beginerrmsg();
834 fprintf(stderr, "type mismatch for %s", symname(formal));
835 b = false;
836 }
837 }
0022c355
ML
838 if (b and formal != nil and
839 isvarparam(formal) and not isopenarray(formal->type) and
840 not (
841 actual->op == O_RVAL or actual->nodetype == t_addr or
842 (
843 actual->op == O_TYPERENAME and
844 (
845 actual->value.arg[0]->op == O_RVAL or
846 actual->value.arg[0]->nodetype == t_addr
847 )
848 )
849 )
850 ) {
2fd0f574
SL
851 beginerrmsg();
852 fprintf(stderr, "expected variable, found \"");
853 prtree(stderr, actual);
854 fprintf(stderr, "\"");
855 b = false;
856 }
857 return b;
858}
859
860/*
861 * Pass an expression to a particular parameter.
862 *
863 * Normally we pass either the address or value, but in some cases
864 * (such as C strings) we want to copy the value onto the stack and
865 * pass its address.
0022c355
ML
866 *
867 * Another special case raised by strings is the possibility that
868 * the actual parameter will be larger than the formal, even with
869 * appropriate type-checking. This occurs because we assume during
870 * evaluation that strings are null-terminated, whereas some languages,
871 * notably Pascal, do not work under that assumption.
2fd0f574
SL
872 */
873
874private passparam (actual, formal)
875Node actual;
876Symbol formal;
877{
878 boolean b;
879 Address addr;
880 Stack *savesp;
0022c355 881 integer actsize, formsize;
2fd0f574 882
0022c355
ML
883 if (formal != nil and isvarparam(formal) and
884 (not isopenarray(formal->type))
885 ) {
2fd0f574
SL
886 addr = lval(actual->value.arg[0]);
887 push(Address, addr);
888 } else if (passaddr(formal, actual->nodetype)) {
889 savesp = sp;
890 eval(actual);
0022c355
ML
891 actsize = sp - savesp;
892 setreg(STKP,
893 reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
894 );
895 dwrite(savesp, reg(STKP), actsize);
2fd0f574
SL
896 sp = savesp;
897 push(Address, reg(STKP));
898 if (formal != nil and isopenarray(formal->type)) {
0022c355
ML
899 push(integer, actsize div size(formal->type->type));
900 }
901 } else if (formal != nil) {
902 formsize = size(formal);
903 savesp = sp;
904 eval(actual);
905 actsize = sp - savesp;
906 if (actsize > formsize) {
907 sp -= (actsize - formsize);
2fd0f574
SL
908 }
909 } else {
910 eval(actual);
911 }
912}
913
914/*
915 * Evaluate an argument list left-to-right.
52646e6f
ML
916 */
917
0022c355 918private integer evalargs(proc, arglist)
52646e6f
ML
919Symbol proc;
920Node arglist;
921{
2fd0f574
SL
922 Node p, actual;
923 Symbol formal;
52646e6f 924 Stack *savesp;
0022c355 925 integer count;
2fd0f574 926 boolean chk;
52646e6f
ML
927
928 savesp = sp;
929 count = 0;
2fd0f574
SL
930 formal = proc->chain;
931 chk = (boolean) (not nosource(proc));
52646e6f 932 for (p = arglist; p != nil; p = p->value.arg[1]) {
2fd0f574
SL
933 assert(p->op == O_COMMA);
934 actual = p->value.arg[0];
935 if (not chkparam(actual, formal, chk)) {
936 fprintf(stderr, " in call to %s", symname(proc));
52646e6f 937 sp = savesp;
2fd0f574 938 enderrmsg();
52646e6f 939 }
2fd0f574
SL
940 passparam(actual, formal);
941 if (formal != nil) {
942 formal = formal->chain;
52646e6f 943 }
52646e6f
ML
944 ++count;
945 }
2fd0f574
SL
946 if (chk) {
947 if (formal != nil) {
948 sp = savesp;
949 error("not enough parameters to %s", symname(proc));
950 }
52646e6f
ML
951 }
952 return count;
953}
954
955public procreturn(f)
956Symbol f;
957{
0022c355
ML
958 integer retvalsize;
959 Node tmp;
960 char *copy;
961
52646e6f 962 flushoutput();
52646e6f 963 popenv();
0022c355
ML
964 if (endproc.isfunc) {
965 retvalsize = size(f->type);
966 if (retvalsize > sizeof(long)) {
967 pushretval(retvalsize, true);
968 copy = newarr(char, retvalsize);
969 popn(retvalsize, copy);
970 tmp = build(O_SCON, copy);
971 } else {
972 tmp = build(O_LCON, (long) (reg(0)));
973 }
974 tmp->nodetype = f->type;
975 tfree(endproc.callnode);
976 *(endproc.callnode) = *(tmp);
977 dispose(tmp);
978 eval(endproc.cmdnode);
979 } else {
980 putchar('\n');
981 printname(stdout, f);
982 printf(" returns successfully\n", symname(f));
983 }
52646e6f
ML
984 erecover();
985}
986
987/*
988 * Push the current environment.
989 */
990
991private pushenv()
992{
993 push(Address, pc);
994 push(Lineno, curline);
995 push(String, cursource);
996 push(Boolean, isstopped);
997 push(Symbol, curfunc);
2fd0f574
SL
998 push(Frame, curframe);
999 push(struct Frame, curframerec);
0022c355 1000 push(CallEnv, endproc);
52646e6f
ML
1001 push(Word, reg(PROGCTR));
1002 push(Word, reg(STKP));
1003}
1004
1005/*
1006 * Pop back to the real world.
1007 */
1008
1009public popenv()
1010{
0022c355 1011 String filename;
52646e6f
ML
1012
1013 setreg(STKP, pop(Word));
1014 setreg(PROGCTR, pop(Word));
0022c355 1015 endproc = pop(CallEnv);
2fd0f574
SL
1016 curframerec = pop(struct Frame);
1017 curframe = pop(Frame);
52646e6f
ML
1018 curfunc = pop(Symbol);
1019 isstopped = pop(Boolean);
1020 filename = pop(String);
1021 curline = pop(Lineno);
1022 pc = pop(Address);
1023 setsource(filename);
1024}
1025
1026/*
1027 * Flush the debuggee's standard output.
1028 *
1029 * This is VERY dependent on the use of stdio.
1030 */
1031
1032public flushoutput()
1033{
0022c355
ML
1034 Symbol p, iob;
1035 Stack *savesp;
52646e6f
ML
1036
1037 p = lookup(identname("fflush", true));
1038 while (p != nil and not isblock(p)) {
1039 p = p->next_sym;
1040 }
1041 if (p != nil) {
1042 iob = lookup(identname("_iob", true));
1043 if (iob != nil) {
1044 pushenv();
1045 pc = codeloc(p);
1046 savesp = sp;
1047 push(long, address(iob, nil) + sizeof(struct _iobuf));
1048 setreg(STKP, reg(STKP) - sizeof(long));
1049 dwrite(savesp, reg(STKP), sizeof(long));
1050 sp = savesp;
1051 beginproc(p, 1);
1052 stepto(return_addr());
1053 popenv();
1054 }
1055 }
1056}