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