date and time created 90/06/25 15:37:01 by bostic
[unix-history] / usr / src / old / dbx / runtime.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 7#ifndef lint
b9ae3d87 8static char sccsid[] = "@(#)runtime.c 5.3 (Berkeley) %G%";
2a24676e 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;
6167b701
DS
804 if (varIsSet("$unsafecall")) {
805 argc = unsafe_evalargs(proc, arglist);
806 } else {
807 argc = evalargs(proc, arglist);
808 }
52646e6f
ML
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/*
2fd0f574
SL
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
823private boolean chkparam (actual, formal, chk)
824Node actual;
825Symbol formal;
826boolean 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 }
0022c355
ML
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 ) {
2fd0f574
SL
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.
0022c355
ML
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.
2fd0f574
SL
876 */
877
878private passparam (actual, formal)
879Node actual;
880Symbol formal;
881{
882 boolean b;
883 Address addr;
884 Stack *savesp;
0022c355 885 integer actsize, formsize;
2fd0f574 886
0022c355
ML
887 if (formal != nil and isvarparam(formal) and
888 (not isopenarray(formal->type))
889 ) {
2fd0f574
SL
890 addr = lval(actual->value.arg[0]);
891 push(Address, addr);
892 } else if (passaddr(formal, actual->nodetype)) {
893 savesp = sp;
894 eval(actual);
0022c355
ML
895 actsize = sp - savesp;
896 setreg(STKP,
897 reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1))
898 );
899 dwrite(savesp, reg(STKP), actsize);
2fd0f574
SL
900 sp = savesp;
901 push(Address, reg(STKP));
902 if (formal != nil and isopenarray(formal->type)) {
0022c355
ML
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);
2fd0f574
SL
912 }
913 } else {
914 eval(actual);
915 }
916}
917
918/*
919 * Evaluate an argument list left-to-right.
52646e6f
ML
920 */
921
0022c355 922private integer evalargs(proc, arglist)
52646e6f
ML
923Symbol proc;
924Node arglist;
925{
2fd0f574
SL
926 Node p, actual;
927 Symbol formal;
52646e6f 928 Stack *savesp;
0022c355 929 integer count;
2fd0f574 930 boolean chk;
52646e6f
ML
931
932 savesp = sp;
933 count = 0;
2fd0f574
SL
934 formal = proc->chain;
935 chk = (boolean) (not nosource(proc));
52646e6f 936 for (p = arglist; p != nil; p = p->value.arg[1]) {
2fd0f574
SL
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));
52646e6f 941 sp = savesp;
2fd0f574 942 enderrmsg();
52646e6f 943 }
2fd0f574
SL
944 passparam(actual, formal);
945 if (formal != nil) {
946 formal = formal->chain;
52646e6f 947 }
52646e6f
ML
948 ++count;
949 }
2fd0f574
SL
950 if (chk) {
951 if (formal != nil) {
952 sp = savesp;
953 error("not enough parameters to %s", symname(proc));
954 }
52646e6f
ML
955 }
956 return count;
6167b701
DS
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
965private integer unsafe_evalargs(proc, arglist)
966Symbol proc;
967Node 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;
52646e6f
ML
979}
980
981public procreturn(f)
982Symbol f;
983{
0022c355
ML
984 integer retvalsize;
985 Node tmp;
986 char *copy;
987
52646e6f 988 flushoutput();
52646e6f 989 popenv();
0022c355
ML
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);
b9ae3d87 1008 printf("%s returns successfully\n", symname(f));
0022c355 1009 }
52646e6f
ML
1010 erecover();
1011}
1012
1013/*
1014 * Push the current environment.
1015 */
1016
1017private pushenv()
1018{
1019 push(Address, pc);
1020 push(Lineno, curline);
1021 push(String, cursource);
1022 push(Boolean, isstopped);
1023 push(Symbol, curfunc);
2fd0f574
SL
1024 push(Frame, curframe);
1025 push(struct Frame, curframerec);
0022c355 1026 push(CallEnv, endproc);
52646e6f
ML
1027 push(Word, reg(PROGCTR));
1028 push(Word, reg(STKP));
1029}
1030
1031/*
1032 * Pop back to the real world.
1033 */
1034
1035public popenv()
1036{
0022c355 1037 String filename;
52646e6f
ML
1038
1039 setreg(STKP, pop(Word));
1040 setreg(PROGCTR, pop(Word));
0022c355 1041 endproc = pop(CallEnv);
2fd0f574
SL
1042 curframerec = pop(struct Frame);
1043 curframe = pop(Frame);
52646e6f
ML
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
1058public flushoutput()
1059{
0022c355
ML
1060 Symbol p, iob;
1061 Stack *savesp;
52646e6f
ML
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}