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