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