/* * machine-dependent code for * looking in stack frames * sequent/32032 version */ #include "defs.h" #include "space.h" #include <sys/param.h> #include "regs.h" #include <a.out.h> #include "sym.h" #include <signal.h> int maxargs = 20; /* * stuff in the stack frame */ #define F_HACKPC 48 /* signal handler hack */ #define F_ARG1 8 /* first argument */ #define F_PC 4 #define F_FP 0 /* * how to find out the number of arguments to a procedure call: * look at the instruction after the call (cxp) * it should be an adjspb with an immediate operand * the operand (the following byte) is the (negative) number of * bytes to be popped off the stack after the call; * i.e. the amount of space taken by parameters */ #define adjspbi(x) (((x) & 0xffff) == 0xa57c) #define adjoff(x) ((((x) & 0xff0000) >> 16) | 0xffffff00) /* * return an address for a local variable * no register vars, unfortunately, as we can't provide an address * gn is the procedure; ln the local name */ extern WORD expv; extern int expsp; localaddr(gn, ln) char *gn, *ln; { WORD fp; ADDR laddr(); if (gn) { if (findrtn(gn) == 0) error("function not found"); } else { findsym((WORD)atow(rget(PC)), INSTSP); if (cursym == NULL) error("function not found"); } if (findframe(&fp) == 0) error("function not found"); if (ln == NULL) { expsp = 0; expv = fp; return; } while (localsym()) { if (strcmp(ln, cursym->y_name) != 0) continue; expv = laddr(cursym, fp, fp + F_ARG1); if (cursym->y_ltype == S_RSYM) expsp = REGSP; else expsp = NOSP; return; } error("local var not found"); /* NOTREACHED */ } /* * print a stack traceback * give locals if possible */ ctrace(modif) char modif; { register ADDR fp, ap, callpc; register int narg; ADDR ofp; ADDR newpc; WORD w; if (adrflg) { fp = adrval; callpc = atow(aget(fp + F_PC, CORF|DATASP)); } else { fp = (ADDR)rtow(rget(FP)); callpc = (ADDR)rtow(rget(PC)); } clrraddr(); ofp = fp; while (cntval--) { chkerr(); findsym(callpc, INSTSP); if (cursym == NULL) printf("?("); else if (strcmp("start", cursym->y_name) == 0) break; else printf("%s(", cursym->y_name); if (strcmp("sigcode", cursym->y_name) == 0) { printf(") from %R\n", callpc); callpc = ltow(lget(ofp + F_HACKPC, CORF|DATASP)); /* ignore saved r0 r1 r2 for now */ continue; } newpc = atow(aget(fp + F_PC, CORF|DATASP)); w = ltow(lget(newpc, SYMF|INSTSP)); if (!adjspbi(w)) narg = 0; else narg = -adjoff(w)/4; for (ap = fp + F_ARG1; --narg >= 0; ap += SZREG) { printf("%R", ltow(lget(ap, CORF|DATASP))); if (narg != 0) printc(','); } printf(") from %R\n", callpc); if (modif == 'C') locals(fp, fp + F_ARG1); setraddr(callpc, fp); callpc = newpc; ofp = fp; fp = atow(aget(fp + F_FP, CORF|DATASP)); if (fp == 0) break; } clrraddr(); } static locals(fp, ap) ADDR fp, ap; { WORD val; register int sp; ADDR laddr(); while (localsym()) { sp = CORF | DATASP; if (cursym->y_ltype == S_RSYM) sp = CORF | REGSP; val = ltow(lget(laddr(cursym, fp, ap), sp)); if (errflg == 0) printf("%8t%s/%10t%R\n", cursym->y_name, val); else { printf("%8t%s/%10t?\n", cursym->y_name); errflg = 0; } } } ADDR laddr(sp, fp, ap) struct sym *sp; ADDR fp, ap; { switch (sp->y_ltype) { case S_STSYM: return (sp->y_value); case S_LSYM: return (fp - sp->y_value); case S_PSYM: return (ap + sp->y_value); case S_RSYM: return (sp->y_value * SZREG); } error("bad local symbol"); /* NOTREACHED */ } int findframe(fpp) ADDR *fpp; { register ADDR fp, pc; struct sym *svcur; svcur = cursym; fp = rtow(rget(FP)); pc = rtow(rget(PC)); if (errflg) return (0); clrraddr(); for (;;) { findsym(pc, INSTSP); if (cursym == svcur) break; if (cursym && strcmp(cursym->y_name, "start") == 0) { clrraddr(); return (0); } setraddr(cursym->y_value, fp); pc = atow(aget(fp + F_PC, CORF|DATASP)); fp = atow(aget(fp + F_FP, CORF|DATASP)); /* sigtramp? */ if (errflg) { clrraddr(); return (0); } } *fpp = fp; return (1); } /* * set addresses for saved registers for this frame * the mask is that from an `enter' instruction */ extern ADDR raddr[]; setraddr(pc, fp) ADDR pc; register ADDR fp; { register int r; register int i; int roff; register int mask; if ((mask = regmask(pc, &roff)) == 0) return; fp += roff; for (r = 7, i = 0; mask; r--) if (mask & (1 << r)) { if (MINREG <= r && r <= MAXREG) raddr[r - MINREG] = fp + i * SZREG; i++; mask &=~ (1 << r); } } clrraddr() { register int i; for (i = 0; i <= MAXREG - MINREG; i++) raddr[i] = 0; } /* * find the mask of saved registers for this routine * * pc is the entry point. * if the code was run through c2, the first instruction will be `enter'; * grab the mask. * set *rp to the number of bytes of local storage on the stack * (the registers are pushed AFTER local storage) * if it wasn't put through c2, the first instruction will be a branch. * the instruction branched to will be the `enter.' * * awful but how else to do it? */ #define enter(w) (((w)&0xff) == 0x82) #define entmsk(w) (((w)>>8) & 0xff) #define br(w) (((w)&0xff) == 0xea) int regmask(pc, rp) ADDR pc; int *rp; { register WORD w; long disp(); *rp = 0; w = ltow(lget(pc, SYMF|INSTSP)); if (enter(w)) { *rp = disp(pc + 2); return (entmsk(w)); } if (!br(w)) return (0); w = ltow(lget(pc + disp(pc + 1), SYMF|INSTSP)); if (enter(w)) return (entmsk(w)); return (0); } static disp(pc) ADDR pc; { register WORD w; w = ltow(lget(pc, SYMF|INSTSP)); if ((w & 0x80) == 0) { w &= 0x7f; if (w & 0x40) w |= 0xffffffc0; } else if ((w & 0x40) == 0) { w = ((w << 8) & 0x3f00) | ((w >> 8) & 0xff); if (w & 0x2000) w |= 0xffffc000; } else { w = ((w << 24) & 0x3f000000) | ((w << 8) & 0xff0000) | ((w >> 8) & 0xff00) | ((w >> 24) & 0xff); if (w & 0x20000000) w |= 0xc0000000; } return (w); }