aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/frame.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-19 19:29:25 +0000
committerrsc <devnull@localhost>2004-04-19 19:29:25 +0000
commita84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch)
tree59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/frame.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/frame.c')
-rw-r--r--src/libmach/frame.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/libmach/frame.c b/src/libmach/frame.c
new file mode 100644
index 00000000..6e448519
--- /dev/null
+++ b/src/libmach/frame.c
@@ -0,0 +1,130 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+typedef struct LocRegs LocRegs;
+struct LocRegs
+{
+ Regs r;
+ Regs *oldregs;
+ Map *map;
+ ulong *val;
+};
+
+static int
+locregrw(Regs *regs, char *name, ulong *val, int isr)
+{
+ int i;
+ LocRegs *lr;
+
+ lr = (LocRegs*)regs;
+ i = windindex(name);
+ if(i == -1)
+ return lr->oldregs->rw(lr->oldregs, name, val, isr);
+ if(isr){
+ *val = lr->val[i];
+ return 0;
+ }else{
+ werrstr("saved registers are immutable");
+ return -1;
+ }
+}
+
+int
+stacktrace(Map *map, Regs *regs, Tracer trace)
+{
+ char *rname;
+ int i, ipc, ret;
+ ulong nextpc, pc, v;
+ ulong *cur, *next;
+ LocRegs lr;
+ Symbol s, *sp;
+
+ /*
+ * Allocate location arrays.
+ */
+ ret = -1;
+ cur = malloc(mach->nwindreg*sizeof(cur[0]));
+ next = malloc(mach->nwindreg*sizeof(cur[0]));
+ if(cur==nil || next==nil)
+ goto out;
+
+ /*
+ * Initialize current registers using regs.
+ */
+ if(rget(regs, mach->pc, &pc) < 0){
+ werrstr("cannot fetch initial pc: %r");
+ goto out;
+ }
+
+ for(i=0; i<mach->nwindreg; i++){
+ rname = mach->windreg[i];
+ if(rget(regs, rname, &v) < 0)
+ v = ~(ulong)0;
+ cur[i] = v;
+ }
+
+ ipc = windindex(mach->pc);
+ ret = 0;
+
+ /* set up cur[i]==next[i] for unwindframe */
+ memmove(next, cur, mach->nwindreg*sizeof(next[0]));
+ for(;;){
+ sp = &s;
+ if(findsym(locaddr(pc), CTEXT, &s) < 0)
+ sp = nil;
+
+ lr.r.rw = locregrw;
+ lr.oldregs = regs;
+ lr.val = cur;
+ lr.map = map;
+ if((i = unwindframe(map, &lr.r, next)) >= 0)
+ nextpc = next[ipc];
+ else
+ nextpc = ~(ulong)0;
+ if((*trace)(map, &lr.r, pc, nextpc, sp, ++ret) <= 0)
+ break;
+ if(i < 0)
+ break;
+ if(sp && strcmp(sp->name, "main") == 0)
+ break;
+ pc = nextpc;
+ memmove(cur, next, mach->nwindreg*sizeof(cur[0]));
+ }
+
+out:
+ free(cur);
+ free(next);
+ return ret;
+}
+
+int
+windindex(char *reg)
+{
+ char **p;
+ int i;
+
+ p = mach->windreg;
+ for(i=0; i<mach->nwindreg; i++)
+ if(strcmp(p[i], reg) == 0)
+ return i;
+ werrstr("%s is not a winding register", reg);
+ return -1;
+}
+
+Loc*
+windreglocs(void)
+{
+ int i;
+ Loc *loc;
+
+ loc = malloc(mach->nwindreg*sizeof(loc[0]));
+ if(loc == nil)
+ return nil;
+ for(i=0; i<mach->nwindreg; i++){
+ loc[i].type = LREG;
+ loc[i].reg = mach->windreg[i];
+ }
+ return loc;
+}