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