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