fixed string/character constant glitch
[unix-history] / usr / src / old / dbx / runtime.vax.c
CommitLineData
52646e6f
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
91df78fa 3static char sccsid[] = "@(#)runtime.vax.c 1.3 %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);
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
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;
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
124public 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
145public pushretval(len, isindirect)
146Integer len;
147Boolean 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
182public Address locals_base(frp)
183register 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
192public Address args_base(frp)
193register 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
202public Word savereg(n, frp)
203register Integer n;
204register 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
241public Word argn(n, frp)
242Integer n;
243Frame 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
256public Address fparamaddr(a)
257Address 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
269public 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
279public 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
291private walkstack(dumpvariables)
292Boolean 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);
91df78fa 311 line = srcline(frp->save_pc - 1);
52646e6f
ML
312 if (line != 0) {
313 printf(", line %d", line);
91df78fa 314 printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
52646e6f
ML
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
340public findbeginning(f)
341Symbol 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
350public Address firstline(f)
351Symbol 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
369public 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
388public 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
406public Boolean isactive(f)
407Symbol 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
428public callproc(procnode, arglist)
429Node procnode;
430Node 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
464private Integer pushargs(proc, arglist)
465Symbol proc;
466Node 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
484private Integer evalargs(proc, arglist)
485Symbol proc;
486Node 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
530public procreturn(f)
531Symbol 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
545private 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
560public 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
580public 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}