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