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