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