standardize sccs keyword lines
[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
92167553 4static char sccsid[] = "@(#)runtime.vax.c 1.8 %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));
92167553
ML
362 if (not isinline(f)) {
363 printparams(f, frp);
364 }
91df78fa 365 line = srcline(frp->save_pc - 1);
52646e6f
ML
366 if (line != 0) {
367 printf(", line %d", line);
91df78fa 368 printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
52646e6f
ML
369 } else {
370 printf(" at 0x%x\n", frp->save_pc);
371 }
372 if (dumpvariables) {
373 dumpvars(f, frp);
374 putchar('\n');
375 }
92167553
ML
376 if (isinline(f)) {
377 f = container(f);
378 } else {
379 frp = nextframe(frp);
380 if (frp != nil) {
381 f = whatblock(frp->save_pc);
382 }
52646e6f 383 }
4fd956ac 384 } while (frp != nil and f != program);
52646e6f
ML
385 if (dumpvariables) {
386 printf("in \"%s\":\n", symname(program));
387 dumpvars(program, nil);
388 putchar('\n');
389 }
390 walkingstack = save;
391 }
392}
393
394/*
395 * Find the entry point of a procedure or function.
396 */
397
398public findbeginning(f)
399Symbol f;
400{
401 f->symvalue.funcv.beginaddr += 2;
402}
403
404/*
405 * Return the address corresponding to the first line in a function.
406 */
407
408public Address firstline(f)
409Symbol f;
410{
411 Address addr;
412
413 addr = codeloc(f);
414 while (linelookup(addr) == 0 and addr < objsize) {
415 ++addr;
416 }
417 if (addr == objsize) {
418 addr = -1;
419 }
420 return addr;
421}
422
423/*
424 * Catcher drops strike three ...
425 */
426
427public runtofirst()
428{
429 Address addr;
430
431 addr = pc;
432 while (linelookup(addr) == 0 and addr < objsize) {
433 ++addr;
434 }
435 if (addr < objsize) {
436 stepto(addr);
437 }
438}
439
440/*
441 * Return the address corresponding to the end of the program.
442 *
443 * We look for the entry to "exit".
444 */
445
446public Address lastaddr()
447{
448 register Symbol s;
449
450 s = lookup(identname("exit", true));
451 if (s == nil) {
452 panic("can't find exit");
453 }
454 return codeloc(s);
455}
456
457/*
458 * Decide if the given function is currently active.
459 *
460 * We avoid calls to "findframe" during a stack trace for efficiency.
461 * Presumably information evaluated while walking the stack is active.
462 */
463
464public Boolean isactive(f)
465Symbol f;
466{
467 register Boolean b;
468
469 if (isfinished(process)) {
470 b = false;
471 } else {
472 if (walkingstack or f == program or
473 (ismodule(f) and isactive(container(f)))) {
474 b = true;
475 } else {
476 b = (Boolean) (findframe(f) != nil);
477 }
478 }
479 return b;
480}
481
482/*
483 * Evaluate a call to a procedure.
484 */
485
486public callproc(procnode, arglist)
487Node procnode;
488Node arglist;
489{
490 Symbol proc;
491 Integer argc;
492
493 if (procnode->op != O_SYM) {
494 beginerrmsg();
495 fprintf(stderr, "can't call \"");
496 prtree(stderr, procnode);
497 fprintf(stderr, "\"");
498 enderrmsg();
499 }
500 assert(procnode->op == O_SYM);
501 proc = procnode->value.sym;
502 if (not isblock(proc)) {
503 error("\"%s\" is not a procedure or function", symname(proc));
504 }
505 pushenv();
506 pc = codeloc(proc);
507 argc = pushargs(proc, arglist);
508 beginproc(proc, argc);
509 isstopped = true;
510 event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
511 buildcmdlist(build(O_PROCRTN, proc)));
512 cont();
513 /* NOTREACHED */
514}
515
516/*
517 * Push the arguments on the process' stack. We do this by first
518 * evaluating them on the "eval" stack, then copying into the process'
519 * space.
520 */
521
522private Integer pushargs(proc, arglist)
523Symbol proc;
524Node arglist;
525{
526 Stack *savesp;
527 int argc, args_size;
528
529 savesp = sp;
530 argc = evalargs(proc, arglist);
531 args_size = sp - savesp;
532 setreg(STKP, reg(STKP) - args_size);
533 dwrite(savesp, reg(STKP), args_size);
534 sp = savesp;
535 return argc;
536}
537
538/*
539 * Evaluate arguments left-to-right.
540 */
541
542private Integer evalargs(proc, arglist)
543Symbol proc;
544Node arglist;
545{
546 Node p, exp;
547 Symbol arg;
548 Stack *savesp;
549 Address addr;
550 Integer count;
551
552 savesp = sp;
553 count = 0;
554 arg = proc->chain;
555 for (p = arglist; p != nil; p = p->value.arg[1]) {
556 if (p->op != O_COMMA) {
557 panic("evalargs: arglist missing comma");
558 }
559 if (arg == nil) {
560 sp = savesp;
561 error("too many parameters to %s", symname(proc));
562 }
563 exp = p->value.arg[0];
564 if (not compatible(arg->type, exp->nodetype)) {
565 sp = savesp;
566 error("expression for parameter %s is of wrong type", symname(arg));
567 }
568 if (arg->class == REF) {
569 if (exp->op != O_RVAL) {
570 sp = savesp;
571 error("variable expected for parameter \"%s\"", symname(arg));
572 }
573 addr = lval(exp->value.arg[0]);
574 push(Address, addr);
575 } else {
576 eval(exp);
577 }
578 arg = arg->chain;
579 ++count;
580 }
581 if (arg != nil) {
582 sp = savesp;
583 error("not enough parameters to %s", symname(proc));
584 }
585 return count;
586}
587
588public procreturn(f)
589Symbol f;
590{
591 flushoutput();
592 putchar('\n');
593 printname(stdout, f);
594 printf(" returns successfully\n", symname(f));
595 popenv();
596 erecover();
597}
598
599/*
600 * Push the current environment.
601 */
602
603private pushenv()
604{
605 push(Address, pc);
606 push(Lineno, curline);
607 push(String, cursource);
608 push(Boolean, isstopped);
609 push(Symbol, curfunc);
610 push(Word, reg(PROGCTR));
611 push(Word, reg(STKP));
612}
613
614/*
615 * Pop back to the real world.
616 */
617
618public popenv()
619{
620 register String filename;
621
622 setreg(STKP, pop(Word));
623 setreg(PROGCTR, pop(Word));
624 curfunc = pop(Symbol);
625 isstopped = pop(Boolean);
626 filename = pop(String);
627 curline = pop(Lineno);
628 pc = pop(Address);
629 setsource(filename);
630}
631
632/*
633 * Flush the debuggee's standard output.
634 *
635 * This is VERY dependent on the use of stdio.
636 */
637
638public flushoutput()
639{
640 register Symbol p, iob;
641 register Stack *savesp;
642
643 p = lookup(identname("fflush", true));
644 while (p != nil and not isblock(p)) {
645 p = p->next_sym;
646 }
647 if (p != nil) {
648 iob = lookup(identname("_iob", true));
649 if (iob != nil) {
650 pushenv();
651 pc = codeloc(p);
652 savesp = sp;
653 push(long, address(iob, nil) + sizeof(struct _iobuf));
654 setreg(STKP, reg(STKP) - sizeof(long));
655 dwrite(savesp, reg(STKP), sizeof(long));
656 sp = savesp;
657 beginproc(p, 1);
658 stepto(return_addr());
659 popenv();
660 }
661 }
662}