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