|
|
1.1 root 1:
2: /* Copyright (c) 1982 Regents of the University of California */
3:
4: static char sccsid[] = "@(#)runtime.c 1.9 8/14/83";
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"
22: #include <sys/param.h>
23:
24: #ifndef public
25: typedef struct Frame *Frame;
26:
27: #include "machine.h"
28: #endif
29:
30: #define NSAVEREG 12
31:
32: struct 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:
41: private Boolean walkingstack = false;
42:
43: /*
44: * Set a frame to the current activation record.
45: */
46:
47: private getcurframe(frp)
48: register 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);
56: frp->save_pc = reg(PROGCTR) + 1;
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:
70: private Frame nextframe(frp)
71: Frame frp;
72: {
73: register Frame newfrp;
74: struct Frame frame;
75: register Integer i, j, mask;
76: Address prev_frame, callpc;
77: static Integer ntramp = 0;
78:
79: newfrp = frp;
80: prev_frame = frp->save_fp;
81:
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>.
86: *
87: * As best I can make out it looks like:
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.
94: *
95: * The addr in sub at which the exception occured is not in sub.save_pc
96: * but in the machine check exception block. It is at the magic address
97: * fp + 84.
98: *
99: * The current approach ignores the sys_frame (what adb reports as sigtramp)
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.
102: */
103:
104: nextf:
105: dread(&frame, prev_frame, sizeof(struct Frame));
106: if (ntramp == 1) {
107: dread(&callpc, prev_frame + 84, sizeof(callpc));
108: } else {
109: callpc = frame.save_pc;
110: }
111: if (frame.save_fp == nil) {
112: newfrp = nil;
113: } else if (callpc > 0x80000000 - 0x200 * UPAGES ) {
114: ntramp++;
115: prev_frame = frame.save_fp;
116: goto nextf;
117: } else {
118: frame.save_pc = callpc;
119: ntramp = 0;
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:
144: public Frame findframe(f)
145: Symbol f;
146: {
147: register Frame frp;
148: static struct Frame frame;
149: Symbol p;
150: Boolean done;
151:
152: frp = &frame;
153: getcurframe(frp);
154: if (f != nil) {
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);
170: }
171: return frp;
172: }
173:
174: /*
175: * Find the return address of the current procedure/function.
176: */
177:
178: public 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:
199: public pushretval(len, isindirect)
200: Integer len;
201: Boolean 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:
236: public Address locals_base(frp)
237: register 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:
246: public Address args_base(frp)
247: register 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:
256: public Word savereg(n, frp)
257: register Integer n;
258: register 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:
295: public Word argn(n, frp)
296: Integer n;
297: Frame 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:
310: public Address fparamaddr(a)
311: Address 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:
323: public 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:
333: public dump()
334: {
335: walkstack(true);
336: }
337:
338: /*
339: * Walk the stack of active procedures printing information
340: * about each active procedure.
341: */
342:
343: private walkstack(dumpvariables)
344: Boolean 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));
362: if (not isinline(f)) {
363: printparams(f, frp);
364: }
365: line = srcline(frp->save_pc - 1);
366: if (line != 0) {
367: printf(", line %d", line);
368: printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1));
369: } else {
370: printf(" at 0x%x\n", frp->save_pc);
371: }
372: if (dumpvariables) {
373: dumpvars(f, frp);
374: putchar('\n');
375: }
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: }
383: }
384: } while (frp != nil and f != program);
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:
398: public findbeginning(f)
399: Symbol 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:
408: public Address firstline(f)
409: Symbol 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:
427: public 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:
446: public 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:
464: public Boolean isactive(f)
465: Symbol 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:
486: public callproc(procnode, arglist)
487: Node procnode;
488: Node 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:
522: private Integer pushargs(proc, arglist)
523: Symbol proc;
524: Node 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:
542: private Integer evalargs(proc, arglist)
543: Symbol proc;
544: Node 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:
588: public procreturn(f)
589: Symbol 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:
603: private 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:
618: public 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:
638: public 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.