diff options
author | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
commit | a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch) | |
tree | 59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/frame.c | |
parent | 0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff) | |
download | plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2 plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip |
libmach
Diffstat (limited to 'src/libmach/frame.c')
-rw-r--r-- | src/libmach/frame.c | 130 |
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; +} |