date and time created 83/08/05 13:34:37 by sam
[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
316d2228 4static char sccsid[] = "@(#)runtime.vax.c 1.7 %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
41private Boolean walkingstack = false;
42
43/*
44 * Set a frame to the current activation record.
45 */
46
47private getcurframe(frp)
48register Frame frp;
49{
50 register int i;
51
52 checkref(frp);
53 frp->mask = reg(NREG);
54 frp->save_ap = reg(ARGP);
55 frp->save_fp = reg(FRP);
551efd5b 56 frp->save_pc = reg(PROGCTR) + 1;
52646e6f
ML
57 for (i = 0; i < NSAVEREG; i++) {
58 frp->save_reg[i] = reg(i);
59 }
60}
61
62/*
63 * Return a pointer to the next activation record up the stack.
64 * Return nil if there is none.
65 * Writes over space pointed to by given argument.
66 */
67
68#define bis(b, n) ((b & (1 << (n))) != 0)
69
70private Frame nextframe(frp)
71Frame frp;
72{
73 register Frame newfrp;
74 struct Frame frame;
75 register Integer i, j, mask;
381c0f0e 76 Address prev_frame, callpc;
316d2228 77 static Integer ntramp = 0;
52646e6f
ML
78
79 newfrp = frp;
381c0f0e
AF
80 prev_frame = frp->save_fp;
81
316d2228
ML
82/*
83 * The check for interrupt generated frames is taken from adb with only
84 * partial understanding. If you're in "sub" and on a sigxxx "sigsub"
85 * gets control, then the stack does NOT look like <main, sub, sigsub>.
381c0f0e
AF
86 *
87 * As best I can make out it looks like:
316d2228
ML
88 *
89 * <main, (machine check exception block + sub), sysframe, sigsub>.
90 *
91 * When the signal occurs an exception block and a frame for the routine
92 * in which it occured are pushed on the user stack. Then another frame
93 * is pushed corresponding to a call from the kernel to sigsub.
381c0f0e
AF
94 *
95 * The addr in sub at which the exception occured is not in sub.save_pc
316d2228
ML
96 * but in the machine check exception block. It is at the magic address
97 * fp + 76.
381c0f0e
AF
98 *
99 * The current approach ignores the sys_frame (what adb reports as sigtramp)
316d2228
ML
100 * and takes the pc for sub from the exception block. This allows the
101 * "where" command to report <main, sub, sigsub>, which seems reasonable.
381c0f0e 102 */
381c0f0e 103
316d2228
ML
104nextf:
105 dread(&frame, prev_frame, sizeof(struct Frame));
106 if (ntramp == 1) {
107 dread(&callpc, prev_frame + 76, sizeof(callpc));
108 } else {
109 callpc = frame.save_pc;
110 }
52646e6f
ML
111 if (frame.save_fp == nil) {
112 newfrp = nil;
316d2228 113 } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
381c0f0e
AF
114 ntramp++;
115 prev_frame = frame.save_fp;
116 goto nextf;
316d2228 117 } else {
381c0f0e 118 frame.save_pc = callpc;
316d2228 119 ntramp = 0;
52646e6f
ML
120 mask = ((frame.mask >> 16) & 0x0fff);
121 j = 0;
122 for (i = 0; i < NSAVEREG; i++) {
123 if (bis(mask, i)) {
124 newfrp->save_reg[i] = frame.save_reg[j];
125 ++j;
126 }
127 }
128 newfrp->condition_handler = frame.condition_handler;
129 newfrp->mask = mask;
130 newfrp->save_ap = frame.save_ap;
131 newfrp->save_fp = frame.save_fp;
132 newfrp->save_pc = frame.save_pc;
133 }
134 return newfrp;
135}
136
137/*
138 * Return the frame associated with the given function.
139 * If the function is nil, return the most recently activated frame.
140 *
141 * Static allocation for the frame.
142 */
143
144public Frame findframe(f)
145Symbol f;
146{
147 register Frame frp;
148 static struct Frame frame;
4fd956ac
ML
149 Symbol p;
150 Boolean done;
52646e6f
ML
151
152 frp = &frame;
153 getcurframe(frp);
154 if (f != nil) {
4fd956ac
ML
155 done = false;
156 do {
157 p = whatblock(frp->save_pc);
158 if (p == f) {
159 done = true;
160 } else if (p == program) {
161 done = true;
162 frp = nil;
163 } else {
164 frp = nextframe(frp);
165 if (frp == nil) {
166 done = true;
167 }
168 }
169 } while (not done);
52646e6f
ML
170 }
171 return frp;
172}
173
174/*
175 * Find the return address of the current procedure/function.
176 */
177
178public Address return_addr()
179{
180 Frame frp;
181 Address addr;
182 struct Frame frame;
183
184 frp = &frame;
185 getcurframe(frp);
186 frp = nextframe(frp);
187 if (frp == nil) {
188 addr = 0;
189 } else {
190 addr = frp->save_pc;
191 }
192 return addr;
193}
194
195/*
196 * Push the value associated with the current function.
197 */
198
199public pushretval(len, isindirect)
200Integer len;
201Boolean isindirect;
202{
203 Word r0;
204
205 r0 = reg(0);
206 if (isindirect) {
207 rpush((Address) r0, len);
208 } else {
209 switch (len) {
210 case sizeof(char):
211 push(char, r0);
212 break;
213
214 case sizeof(short):
215 push(short, r0);
216 break;
217
218 default:
219 if (len == sizeof(Word)) {
220 push(Word, r0);
221 } else if (len == 2*sizeof(Word)) {
222 push(Word, r0);
223 push(Word, reg(1));
224 } else {
225 panic("not indirect in pushretval?");
226 }
227 break;
228 }
229 }
230}
231
232/*
233 * Return the base address for locals in the given frame.
234 */
235
236public Address locals_base(frp)
237register Frame frp;
238{
239 return (frp == nil) ? reg(FRP) : frp->save_fp;
240}
241
242/*
243 * Return the base address for arguments in the given frame.
244 */
245
246public Address args_base(frp)
247register Frame frp;
248{
249 return (frp == nil) ? reg(ARGP) : frp->save_ap;
250}
251
252/*
253 * Return saved register n from the given frame.
254 */
255
256public Word savereg(n, frp)
257register Integer n;
258register Frame frp;
259{
260 register Word w;
261
262 if (frp == nil) {
263 w = reg(n);
264 } else {
265 switch (n) {
266 case ARGP:
267 w = frp->save_ap;
268 break;
269
270 case FRP:
271 w = frp->save_fp;
272 break;
273
274 case STKP:
275 w = reg(STKP);
276 break;
277
278 case PROGCTR:
279 w = frp->save_pc;
280 break;
281
282 default:
283 assert(n >= 0 and n < NSAVEREG);
284 w = frp->save_reg[n];
285 break;
286 }
287 }
288 return w;
289}
290
291/*
292 * Return the nth argument to the current procedure.
293 */
294
295public Word argn(n, frp)
296Integer n;
297Frame frp;
298{
299 Word w;
300
301 dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w));
302 return w;
303}
304
305/*
306 * Calculate the entry address for a procedure or function parameter,
307 * given the address of the descriptor.
308 */
309
310public Address fparamaddr(a)
311Address a;
312{
313 Address r;
314
315 dread(&r, a, sizeof(r));
316 return r;
317}
318
319/*
320 * Print a list of currently active blocks starting with most recent.
321 */
322
323public wherecmd()
324{
325 walkstack(false);
326}
327
328/*
329 * Dump the world to the given file.
330 * Like "where", but variables are dumped also.
331 */
332
333public dump()
334{
335 walkstack(true);
336}
337
338/*
339 * Walk the stack of active procedures printing information
340 * about each active procedure.
341 */
342
52646e6f
ML
343private walkstack(dumpvariables)
344Boolean dumpvariables;
345{
346 register Frame frp;
347 register Symbol f;
348 register Boolean save;
349 register Lineno line;
350 struct Frame frame;
351
352 if (notstarted(process)) {
353 error("program is not active");
354 } else {
355 save = walkingstack;
356 walkingstack = true;
357 frp = &frame;
358 getcurframe(frp);
359 f = whatblock(frp->save_pc);
360 do {
361 printf("%s", symname(f));
362 printparams(f, frp);
91df78fa 363 line = srcline(frp->save_pc - 1);
52646e6f
ML
364 if (line != 0) {
365 printf(", line %d", line);
91df78fa 366 printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
52646e6f
ML
367 } else {
368 printf(" at 0x%x\n", frp->save_pc);
369 }
370 if (dumpvariables) {
371 dumpvars(f, frp);
372 putchar('\n');
373 }
374 frp = nextframe(frp);
375 if (frp != nil) {
376 f = whatblock(frp->save_pc);
377 }
4fd956ac 378 } while (frp != nil and f != program);
52646e6f
ML
379 if (dumpvariables) {
380 printf("in \"%s\":\n", symname(program));
381 dumpvars(program, nil);
382 putchar('\n');
383 }
384 walkingstack = save;
385 }
386}
387
388/*
389 * Find the entry point of a procedure or function.
390 */
391
392public findbeginning(f)
393Symbol f;
394{
395 f->symvalue.funcv.beginaddr += 2;
396}
397
398/*
399 * Return the address corresponding to the first line in a function.
400 */
401
402public Address firstline(f)
403Symbol f;
404{
405 Address addr;
406
407 addr = codeloc(f);
408 while (linelookup(addr) == 0 and addr < objsize) {
409 ++addr;
410 }
411 if (addr == objsize) {
412 addr = -1;
413 }
414 return addr;
415}
416
417/*
418 * Catcher drops strike three ...
419 */
420
421public runtofirst()
422{
423 Address addr;
424
425 addr = pc;
426 while (linelookup(addr) == 0 and addr < objsize) {
427 ++addr;
428 }
429 if (addr < objsize) {
430 stepto(addr);
431 }
432}
433
434/*
435 * Return the address corresponding to the end of the program.
436 *
437 * We look for the entry to "exit".
438 */
439
440public Address lastaddr()
441{
442 register Symbol s;
443
444 s = lookup(identname("exit", true));
445 if (s == nil) {
446 panic("can't find exit");
447 }
448 return codeloc(s);
449}
450
451/*
452 * Decide if the given function is currently active.
453 *
454 * We avoid calls to "findframe" during a stack trace for efficiency.
455 * Presumably information evaluated while walking the stack is active.
456 */
457
458public Boolean isactive(f)
459Symbol f;
460{
461 register Boolean b;
462
463 if (isfinished(process)) {
464 b = false;
465 } else {
466 if (walkingstack or f == program or
467 (ismodule(f) and isactive(container(f)))) {
468 b = true;
469 } else {
470 b = (Boolean) (findframe(f) != nil);
471 }
472 }
473 return b;
474}
475
476/*
477 * Evaluate a call to a procedure.
478 */
479
480public callproc(procnode, arglist)
481Node procnode;
482Node arglist;
483{
484 Symbol proc;
485 Integer argc;
486
487 if (procnode->op != O_SYM) {
488 beginerrmsg();
489 fprintf(stderr, "can't call \"");
490 prtree(stderr, procnode);
491 fprintf(stderr, "\"");
492 enderrmsg();
493 }
494 assert(procnode->op == O_SYM);
495 proc = procnode->value.sym;
496 if (not isblock(proc)) {
497 error("\"%s\" is not a procedure or function", symname(proc));
498 }
499 pushenv();
500 pc = codeloc(proc);
501 argc = pushargs(proc, arglist);
502 beginproc(proc, argc);
503 isstopped = true;
504 event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
505 buildcmdlist(build(O_PROCRTN, proc)));
506 cont();
507 /* NOTREACHED */
508}
509
510/*
511 * Push the arguments on the process' stack. We do this by first
512 * evaluating them on the "eval" stack, then copying into the process'
513 * space.
514 */
515
516private Integer pushargs(proc, arglist)
517Symbol proc;
518Node arglist;
519{
520 Stack *savesp;
521 int argc, args_size;
522
523 savesp = sp;
524 argc = evalargs(proc, arglist);
525 args_size = sp - savesp;
526 setreg(STKP, reg(STKP) - args_size);
527 dwrite(savesp, reg(STKP), args_size);
528 sp = savesp;
529 return argc;
530}
531
532/*
533 * Evaluate arguments left-to-right.
534 */
535
536private Integer evalargs(proc, arglist)
537Symbol proc;
538Node arglist;
539{
540 Node p, exp;
541 Symbol arg;
542 Stack *savesp;
543 Address addr;
544 Integer count;
545
546 savesp = sp;
547 count = 0;
548 arg = proc->chain;
549 for (p = arglist; p != nil; p = p->value.arg[1]) {
550 if (p->op != O_COMMA) {
551 panic("evalargs: arglist missing comma");
552 }
553 if (arg == nil) {
554 sp = savesp;
555 error("too many parameters to %s", symname(proc));
556 }
557 exp = p->value.arg[0];
558 if (not compatible(arg->type, exp->nodetype)) {
559 sp = savesp;
560 error("expression for parameter %s is of wrong type", symname(arg));
561 }
562 if (arg->class == REF) {
563 if (exp->op != O_RVAL) {
564 sp = savesp;
565 error("variable expected for parameter \"%s\"", symname(arg));
566 }
567 addr = lval(exp->value.arg[0]);
568 push(Address, addr);
569 } else {
570 eval(exp);
571 }
572 arg = arg->chain;
573 ++count;
574 }
575 if (arg != nil) {
576 sp = savesp;
577 error("not enough parameters to %s", symname(proc));
578 }
579 return count;
580}
581
582public procreturn(f)
583Symbol f;
584{
585 flushoutput();
586 putchar('\n');
587 printname(stdout, f);
588 printf(" returns successfully\n", symname(f));
589 popenv();
590 erecover();
591}
592
593/*
594 * Push the current environment.
595 */
596
597private pushenv()
598{
599 push(Address, pc);
600 push(Lineno, curline);
601 push(String, cursource);
602 push(Boolean, isstopped);
603 push(Symbol, curfunc);
604 push(Word, reg(PROGCTR));
605 push(Word, reg(STKP));
606}
607
608/*
609 * Pop back to the real world.
610 */
611
612public popenv()
613{
614 register String filename;
615
616 setreg(STKP, pop(Word));
617 setreg(PROGCTR, pop(Word));
618 curfunc = pop(Symbol);
619 isstopped = pop(Boolean);
620 filename = pop(String);
621 curline = pop(Lineno);
622 pc = pop(Address);
623 setsource(filename);
624}
625
626/*
627 * Flush the debuggee's standard output.
628 *
629 * This is VERY dependent on the use of stdio.
630 */
631
632public flushoutput()
633{
634 register Symbol p, iob;
635 register Stack *savesp;
636
637 p = lookup(identname("fflush", true));
638 while (p != nil and not isblock(p)) {
639 p = p->next_sym;
640 }
641 if (p != nil) {
642 iob = lookup(identname("_iob", true));
643 if (iob != nil) {
644 pushenv();
645 pc = codeloc(p);
646 savesp = sp;
647 push(long, address(iob, nil) + sizeof(struct _iobuf));
648 setreg(STKP, reg(STKP) - sizeof(long));
649 dwrite(savesp, reg(STKP), sizeof(long));
650 sp = savesp;
651 beginproc(p, 1);
652 stepto(return_addr());
653 popenv();
654 }
655 }
656}