xref: /csrg-svn/old/dbx/runtime.vax.c (revision 16618)
1 
2 /* Copyright (c) 1982 Regents of the University of California */
3 
4 static char sccsid[] = "@(#)runtime.c 1.8 8/10/83";
5 
6 static char rcsid[] = "$Header: runtime.c,v 1.3 84/03/27 10:23:40 linton Exp $";
7 
8 /*
9  * Runtime organization dependent routines, mostly dealing with
10  * activation records.
11  */
12 
13 #include "defs.h"
14 #include "runtime.h"
15 #include "process.h"
16 #include "machine.h"
17 #include "events.h"
18 #include "mappings.h"
19 #include "symbols.h"
20 #include "tree.h"
21 #include "eval.h"
22 #include "operators.h"
23 #include "object.h"
24 #include <sys/param.h>
25 
26 #ifndef public
27 typedef struct Frame *Frame;
28 
29 #include "machine.h"
30 #endif
31 
32 #define NSAVEREG 12
33 
34 struct Frame {
35     Integer condition_handler;
36     Integer mask;
37     Address save_ap;		/* argument pointer */
38     Address save_fp;		/* frame pointer */
39     Address save_pc;		/* program counter */
40     Word save_reg[NSAVEREG];	/* not necessarily there */
41 };
42 
43 private Frame curframe = nil;
44 private struct Frame curframerec;
45 private Boolean walkingstack = false;
46 
47 #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp)
48 
49 /*
50  * Set a frame to the current activation record.
51  */
52 
53 private getcurframe(frp)
54 register Frame frp;
55 {
56     register int i;
57 
58     checkref(frp);
59     frp->mask = reg(NREG);
60     frp->save_ap = reg(ARGP);
61     frp->save_fp = reg(FRP);
62     frp->save_pc = reg(PROGCTR) + 1;
63     for (i = 0; i < NSAVEREG; i++) {
64 	frp->save_reg[i] = reg(i);
65     }
66 }
67 
68 /*
69  * Return a pointer to the next activation record up the stack.
70  * Return nil if there is none.
71  * Writes over space pointed to by given argument.
72  */
73 
74 #define bis(b, n) ((b & (1 << (n))) != 0)
75 
76 private Frame nextframe(frp)
77 Frame frp;
78 {
79     register Frame newfrp;
80     struct Frame frame;
81     register Integer i, j, mask;
82     Address prev_frame, callpc;
83     static Integer ntramp = 0;
84 
85     newfrp = frp;
86     prev_frame = frp->save_fp;
87 
88 /*
89  *  The check for interrupt generated frames is taken from adb with only
90  *  partial understanding.  If you're in "sub" and on a sigxxx "sigsub"
91  *  gets control, then the stack does NOT look like <main, sub, sigsub>.
92  *
93  *  As best I can make out it looks like:
94  *
95  *     <main, (machine check exception block + sub), sysframe, sigsub>.
96  *
97  *  When the signal occurs an exception block and a frame for the routine
98  *  in which it occured are pushed on the user stack.  Then another frame
99  *  is pushed corresponding to a call from the kernel to sigsub.
100  *
101  *  The addr in sub at which the exception occured is not in sub.save_pc
102  *  but in the machine check exception block.  It is at the magic address
103  *  fp + 84.
104  *
105  *  The current approach ignores the sys_frame (what adb reports as sigtramp)
106  *  and takes the pc for sub from the exception block.  This allows the
107  *  "where" command to report <main, sub, sigsub>, which seems reasonable.
108  */
109 
110 nextf:
111     dread(&frame, prev_frame, sizeof(struct Frame));
112     if (ntramp == 1) {
113 	dread(&callpc, prev_frame + 84, sizeof(callpc));
114     } else {
115 	callpc = frame.save_pc;
116     }
117     if (frame.save_fp == nil) {
118 	newfrp = nil;
119     } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
120 	 ntramp++;
121 	 prev_frame = frame.save_fp;
122 	 goto nextf;
123     } else {
124 	frame.save_pc = callpc;
125         ntramp = 0;
126 	mask = ((frame.mask >> 16) & 0x0fff);
127 	j = 0;
128 	for (i = 0; i < NSAVEREG; i++) {
129 	    if (bis(mask, i)) {
130 		newfrp->save_reg[i] = frame.save_reg[j];
131 		++j;
132 	    }
133 	}
134 	newfrp->condition_handler = frame.condition_handler;
135 	newfrp->mask = mask;
136 	newfrp->save_ap = frame.save_ap;
137 	newfrp->save_fp = frame.save_fp;
138 	newfrp->save_pc = frame.save_pc;
139     }
140     return newfrp;
141 }
142 
143 /*
144  * Get the current frame information in the given Frame and store the
145  * associated function in the given value-result parameter.
146  */
147 
148 private getcurfunc (frp, fp)
149 Frame frp;
150 Symbol *fp;
151 {
152     getcurframe(frp);
153     *fp = whatblock(frp->save_pc);
154 }
155 
156 /*
157  * Return the frame associated with the next function up the call stack, or
158  * nil if there is none.  The function is returned in a value-result parameter.
159  * For "inline" functions the statically outer function and same frame
160  * are returned.
161  */
162 
163 private Frame nextfunc (frp, fp)
164 Frame frp;
165 Symbol *fp;
166 {
167     Symbol t;
168     Frame nfrp;
169 
170     t = *fp;
171     checkref(t);
172     if (isinline(t)) {
173 	t = container(t);
174 	nfrp = frp;
175     } else {
176 	nfrp = nextframe(frp);
177 	if (nfrp == nil) {
178 	    t = nil;
179 	} else {
180 	    t = whatblock(nfrp->save_pc);
181 	}
182     }
183     *fp = t;
184     return nfrp;
185 }
186 
187 /*
188  * Return the frame associated with the given function.
189  * If the function is nil, return the most recently activated frame.
190  *
191  * Static allocation for the frame.
192  */
193 
194 public Frame findframe(f)
195 Symbol f;
196 {
197     register Frame frp;
198     static struct Frame frame;
199     Symbol p;
200     Boolean done;
201 
202     frp = &frame;
203     getcurframe(frp);
204     if (f != nil) {
205 	if (f == curfunc and curframe != nil) {
206 	    *frp = *curframe;
207 	} else {
208 	    done = false;
209 	    p = whatblock(frp->save_pc);
210 	    do {
211 		if (p == f) {
212 		    done = true;
213 		} else if (p == program) {
214 		    done = true;
215 		    frp = nil;
216 		} else {
217 		    frp = nextfunc(frp, &p);
218 		    if (frp == nil) {
219 			done = true;
220 		    }
221 		}
222 	    } while (not done);
223 	}
224     }
225     return frp;
226 }
227 
228 /*
229  * Find the return address of the current procedure/function.
230  */
231 
232 public Address return_addr()
233 {
234     Frame frp;
235     Address addr;
236     struct Frame frame;
237 
238     frp = &frame;
239     getcurframe(frp);
240     frp = nextframe(frp);
241     if (frp == nil) {
242 	addr = 0;
243     } else {
244 	addr = frp->save_pc;
245     }
246     return addr;
247 }
248 
249 /*
250  * Push the value associated with the current function.
251  */
252 
253 public pushretval(len, isindirect)
254 Integer len;
255 Boolean isindirect;
256 {
257     Word r0;
258 
259     r0 = reg(0);
260     if (isindirect) {
261 	rpush((Address) r0, len);
262     } else {
263 	switch (len) {
264 	    case sizeof(char):
265 		push(char, r0);
266 		break;
267 
268 	    case sizeof(short):
269 		push(short, r0);
270 		break;
271 
272 	    default:
273 		if (len == sizeof(Word)) {
274 		    push(Word, r0);
275 		} else if (len == 2*sizeof(Word)) {
276 		    push(Word, r0);
277 		    push(Word, reg(1));
278 		} else {
279 		    panic("not indirect in pushretval?");
280 		}
281 		break;
282 	}
283     }
284 }
285 
286 /*
287  * Return the base address for locals in the given frame.
288  */
289 
290 public Address locals_base(frp)
291 register Frame frp;
292 {
293     return (frp == nil) ? reg(FRP) : frp->save_fp;
294 }
295 
296 /*
297  * Return the base address for arguments in the given frame.
298  */
299 
300 public Address args_base(frp)
301 register Frame frp;
302 {
303     return (frp == nil) ? reg(ARGP) : frp->save_ap;
304 }
305 
306 /*
307  * Return saved register n from the given frame.
308  */
309 
310 public Word savereg(n, frp)
311 register Integer n;
312 register Frame frp;
313 {
314     register Word w;
315 
316     if (frp == nil) {
317 	w = reg(n);
318     } else {
319 	switch (n) {
320 	    case ARGP:
321 		w = frp->save_ap;
322 		break;
323 
324 	    case FRP:
325 		w = frp->save_fp;
326 		break;
327 
328 	    case STKP:
329 		w = reg(STKP);
330 		break;
331 
332 	    case PROGCTR:
333 		w = frp->save_pc;
334 		break;
335 
336 	    default:
337 		assert(n >= 0 and n < NSAVEREG);
338 		w = frp->save_reg[n];
339 		break;
340 	}
341     }
342     return w;
343 }
344 
345 /*
346  * Return the nth argument to the current procedure.
347  */
348 
349 public Word argn(n, frp)
350 Integer n;
351 Frame frp;
352 {
353     Word w;
354 
355     dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
356     return w;
357 }
358 
359 /*
360  * Calculate the entry address for a procedure or function parameter,
361  * given the address of the descriptor.
362  */
363 
364 public Address fparamaddr(a)
365 Address a;
366 {
367     Address r;
368 
369     dread(&r, a, sizeof(r));
370     return r;
371 }
372 
373 /*
374  * Print a list of currently active blocks starting with most recent.
375  */
376 
377 public wherecmd()
378 {
379     walkstack(false);
380 }
381 
382 /*
383  * Dump the world to the given file.
384  * Like "where", but variables are dumped also.
385  */
386 
387 public dump()
388 {
389     walkstack(true);
390 }
391 
392 /*
393  * Walk the stack of active procedures printing information
394  * about each active procedure.
395  */
396 
397 private walkstack(dumpvariables)
398 Boolean dumpvariables;
399 {
400     register Frame frp;
401     register Boolean save;
402     register Lineno line;
403     Symbol f;
404     struct Frame frame;
405 
406     if (notstarted(process)) {
407 	error("program is not active");
408     } else {
409 	save = walkingstack;
410 	walkingstack = true;
411 	frp = &frame;
412 	getcurfunc(frp, &f);
413 	do {
414 	    printf("%s", symname(f));
415 	    if (not isinline(f)) {
416 		printparams(f, frp);
417 	    }
418 	    line = srcline(frp->save_pc - 1);
419 	    if (line != 0) {
420 		printf(", line %d", line);
421 		printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
422 	    } else {
423 		printf(" at 0x%x\n", frp->save_pc);
424 	    }
425 	    if (dumpvariables) {
426 		dumpvars(f, frp);
427 		putchar('\n');
428 	    }
429 	    frp = nextfunc(frp, &f);
430 	} while (frp != nil and f != program);
431 	if (dumpvariables) {
432 	    printf("in \"%s\":\n", symname(program));
433 	    dumpvars(program, nil);
434 	    putchar('\n');
435 	}
436 	walkingstack = save;
437     }
438 }
439 
440 /*
441  * Set the current function to the given symbol.
442  * We must adjust "curframe" so that subsequent operations are
443  * not confused; for simplicity we simply clear it.
444  */
445 
446 public setcurfunc (f)
447 Symbol f;
448 {
449     curfunc = f;
450     curframe = nil;
451 }
452 
453 /*
454  * Set curfunc to be N up/down the stack from its current value.
455  */
456 
457 public up (n)
458 integer n;
459 {
460     integer i;
461     Symbol f;
462     Frame frp;
463     boolean done;
464 
465     if (not isactive(program)) {
466 	error("program is not active");
467     } else if (curfunc == nil) {
468 	error("no current function");
469     } else {
470 	i = 0;
471 	f = curfunc;
472 	if (curframe != nil) {
473 	    frp = curframe;
474 	} else {
475 	    frp = findframe(f);
476 	}
477 	done = false;
478 	do {
479 	    if (frp == nil) {
480 		done = true;
481 		error("not that many levels");
482 	    } else if (i >= n) {
483 		done = true;
484 		curfunc = f;
485 		curframe = &curframerec;
486 		*curframe = *frp;
487 	    } else if (f == program) {
488 		done = true;
489 		error("not that many levels");
490 	    } else {
491 		frp = nextfunc(frp, &f);
492 	    }
493 	    ++i;
494 	} while (not done);
495     }
496 }
497 
498 public down (n)
499 integer n;
500 {
501     integer i, depth;
502     register Frame frp;
503     Symbol f;
504     struct Frame frame;
505 
506     if (not isactive(program)) {
507 	error("program is not active");
508     } else if (curfunc == nil) {
509 	error("no current function");
510     } else {
511 	depth = 0;
512 	frp = &frame;
513 	getcurfunc(frp, &f);
514 	if (curframe == nil) {
515 	    curframe = &curframerec;
516 	    *curframe = *(findframe(curfunc));
517 	}
518 	while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) {
519 	    frp = nextfunc(frp, &f);
520 	    ++depth;
521 	}
522 	if (f == nil or n > depth) {
523 	    error("not that many levels");
524 	} else {
525 	    depth -= n;
526 	    frp = &frame;
527 	    getcurfunc(frp, &f);
528 	    for (i = 0; i < depth; i++) {
529 		frp = nextfunc(frp, &f);
530 		assert(frp != nil);
531 	    }
532 	    curfunc = f;
533 	    *curframe = *frp;
534 	}
535     }
536 }
537 
538 /*
539  * Find the entry point of a procedure or function.
540  */
541 
542 public findbeginning(f)
543 Symbol f;
544 {
545     if (isinternal(f)) {
546 	f->symvalue.funcv.beginaddr += 15;
547     } else {
548 	f->symvalue.funcv.beginaddr += 2;
549     }
550 }
551 
552 /*
553  * Return the address corresponding to the first line in a function.
554  */
555 
556 public Address firstline(f)
557 Symbol f;
558 {
559     Address addr;
560 
561     addr = codeloc(f);
562     while (linelookup(addr) == 0 and addr < objsize) {
563 	++addr;
564     }
565     if (addr == objsize) {
566 	addr = -1;
567     }
568     return addr;
569 }
570 
571 /*
572  * Catcher drops strike three ...
573  */
574 
575 public runtofirst()
576 {
577     Address addr;
578 
579     addr = pc;
580     while (linelookup(addr) == 0 and addr < objsize) {
581 	++addr;
582     }
583     if (addr < objsize) {
584 	stepto(addr);
585     }
586 }
587 
588 /*
589  * Return the address corresponding to the end of the program.
590  *
591  * We look for the entry to "exit".
592  */
593 
594 public Address lastaddr()
595 {
596     register Symbol s;
597 
598     s = lookup(identname("exit", true));
599     if (s == nil) {
600 	panic("can't find exit");
601     }
602     return codeloc(s);
603 }
604 
605 /*
606  * Decide if the given function is currently active.
607  *
608  * We avoid calls to "findframe" during a stack trace for efficiency.
609  * Presumably information evaluated while walking the stack is active.
610  */
611 
612 public Boolean isactive(f)
613 Symbol f;
614 {
615     register Boolean b;
616 
617     if (isfinished(process)) {
618 	b = false;
619     } else {
620 	if (walkingstack or f == program or
621 	  (ismodule(f) and isactive(container(f)))) {
622 	    b = true;
623 	} else {
624 	    b = (Boolean) (findframe(f) != nil);
625 	}
626     }
627     return b;
628 }
629 
630 /*
631  * Evaluate a call to a procedure.
632  */
633 
634 public callproc(procnode, arglist)
635 Node procnode;
636 Node arglist;
637 {
638     Symbol proc;
639     Integer argc;
640 
641     if (procnode->op != O_SYM) {
642 	beginerrmsg();
643 	fprintf(stderr, "can't call \"");
644 	prtree(stderr, procnode);
645 	fprintf(stderr, "\"");
646 	enderrmsg();
647     }
648     assert(procnode->op == O_SYM);
649     proc = procnode->value.sym;
650     if (not isblock(proc)) {
651 	error("\"%s\" is not a procedure or function", symname(proc));
652     }
653     pushenv();
654     pc = codeloc(proc);
655     argc = pushargs(proc, arglist);
656     beginproc(proc, argc);
657     isstopped = true;
658     event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
659 	buildcmdlist(build(O_PROCRTN, proc)));
660     cont(0);
661     /* NOTREACHED */
662 }
663 
664 /*
665  * Push the arguments on the process' stack.  We do this by first
666  * evaluating them on the "eval" stack, then copying into the process'
667  * space.
668  */
669 
670 private Integer pushargs(proc, arglist)
671 Symbol proc;
672 Node arglist;
673 {
674     Stack *savesp;
675     int argc, args_size;
676 
677     savesp = sp;
678     argc = evalargs(proc, arglist);
679     args_size = sp - savesp;
680     setreg(STKP, reg(STKP) - args_size);
681     dwrite(savesp, reg(STKP), args_size);
682     sp = savesp;
683     return argc;
684 }
685 
686 /*
687  * Check to see if an expression is correct for a given parameter.
688  * If the given parameter is false, don't worry about type inconsistencies.
689  *
690  * Return whether or not it is ok.
691  */
692 
693 private boolean chkparam (actual, formal, chk)
694 Node actual;
695 Symbol formal;
696 boolean chk;
697 {
698     boolean b;
699 
700     b = true;
701     if (chk) {
702 	if (formal == nil) {
703 	    beginerrmsg();
704 	    fprintf(stderr, "too many parameters");
705 	    b = false;
706 	} else if (not compatible(formal->type, actual->nodetype)) {
707 	    beginerrmsg();
708 	    fprintf(stderr, "type mismatch for %s", symname(formal));
709 	    b = false;
710 	}
711     }
712     if (b and formal != nil and isvarparam(formal) and
713 	not isopenarray(formal->type) and actual->op != O_RVAL)
714     {
715 	beginerrmsg();
716 	fprintf(stderr, "expected variable, found \"");
717 	prtree(stderr, actual);
718 	fprintf(stderr, "\"");
719 	b = false;
720     }
721     return b;
722 }
723 
724 /*
725  * Pass an expression to a particular parameter.
726  *
727  * Normally we pass either the address or value, but in some cases
728  * (such as C strings) we want to copy the value onto the stack and
729  * pass its address.
730  */
731 
732 private passparam (actual, formal)
733 Node actual;
734 Symbol formal;
735 {
736     boolean b;
737     Address addr;
738     Stack *savesp;
739     integer paramsize;
740 
741     if (isvarparam(formal) and not isopenarray(formal->type)) {
742 	addr = lval(actual->value.arg[0]);
743 	push(Address, addr);
744     } else if (passaddr(formal, actual->nodetype)) {
745 	savesp = sp;
746 	eval(actual);
747 	paramsize = sp - savesp;
748 	setreg(STKP, reg(STKP) - paramsize);
749 	dwrite(savesp, reg(STKP), paramsize);
750 	sp = savesp;
751 	push(Address, reg(STKP));
752 	if (formal != nil and isopenarray(formal->type)) {
753 	    push(integer, paramsize div size(formal->type->type));
754 	}
755     } else {
756 	eval(actual);
757     }
758 }
759 
760 /*
761  * Evaluate an argument list left-to-right.
762  */
763 
764 private Integer evalargs(proc, arglist)
765 Symbol proc;
766 Node arglist;
767 {
768     Node p, actual;
769     Symbol formal;
770     Stack *savesp;
771     Integer count;
772     boolean chk;
773 
774     savesp = sp;
775     count = 0;
776     formal = proc->chain;
777     chk = (boolean) (not nosource(proc));
778     for (p = arglist; p != nil; p = p->value.arg[1]) {
779 	assert(p->op == O_COMMA);
780 	actual = p->value.arg[0];
781 	if (not chkparam(actual, formal, chk)) {
782 	    fprintf(stderr, " in call to %s", symname(proc));
783 	    sp = savesp;
784 	    enderrmsg();
785 	}
786 	passparam(actual, formal);
787 	if (formal != nil) {
788 	    formal = formal->chain;
789 	}
790 	++count;
791     }
792     if (chk) {
793 	if (formal != nil) {
794 	    sp = savesp;
795 	    error("not enough parameters to %s", symname(proc));
796 	}
797     }
798     return count;
799 }
800 
801 public procreturn(f)
802 Symbol f;
803 {
804     flushoutput();
805     putchar('\n');
806     printname(stdout, f);
807     printf(" returns successfully\n", symname(f));
808     popenv();
809     erecover();
810 }
811 
812 /*
813  * Push the current environment.
814  */
815 
816 private pushenv()
817 {
818     push(Address, pc);
819     push(Lineno, curline);
820     push(String, cursource);
821     push(Boolean, isstopped);
822     push(Symbol, curfunc);
823     push(Frame, curframe);
824     push(struct Frame, curframerec);
825     push(Word, reg(PROGCTR));
826     push(Word, reg(STKP));
827 }
828 
829 /*
830  * Pop back to the real world.
831  */
832 
833 public popenv()
834 {
835     register String filename;
836 
837     setreg(STKP, pop(Word));
838     setreg(PROGCTR, pop(Word));
839     curframerec = pop(struct Frame);
840     curframe = pop(Frame);
841     curfunc = pop(Symbol);
842     isstopped = pop(Boolean);
843     filename = pop(String);
844     curline = pop(Lineno);
845     pc = pop(Address);
846     setsource(filename);
847 }
848 
849 /*
850  * Flush the debuggee's standard output.
851  *
852  * This is VERY dependent on the use of stdio.
853  */
854 
855 public flushoutput()
856 {
857     register Symbol p, iob;
858     register Stack *savesp;
859 
860     p = lookup(identname("fflush", true));
861     while (p != nil and not isblock(p)) {
862 	p = p->next_sym;
863     }
864     if (p != nil) {
865 	iob = lookup(identname("_iob", true));
866 	if (iob != nil) {
867 	    pushenv();
868 	    pc = codeloc(p);
869 	    savesp = sp;
870 	    push(long, address(iob, nil) + sizeof(struct _iobuf));
871 	    setreg(STKP, reg(STKP) - sizeof(long));
872 	    dwrite(savesp, reg(STKP), sizeof(long));
873 	    sp = savesp;
874 	    beginproc(p, 1);
875 	    stepto(return_addr());
876 	    popenv();
877 	}
878     }
879 }
880