diff options
author | marcel <marcel@FreeBSD.org> | 2003-07-12 04:35:09 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2003-07-12 04:35:09 +0000 |
commit | d67caeb89db630bf5035e1e435148797619e110b (patch) | |
tree | 7b2a075cb606e8913871a3e5f82b6cb68735878e /sys | |
parent | 8c227c87ca84d5742057ac0e31620740cdea7f0e (diff) | |
download | FreeBSD-src-d67caeb89db630bf5035e1e435148797619e110b.zip FreeBSD-src-d67caeb89db630bf5035e1e435148797619e110b.tar.gz |
Add logic to trace across/over a trapframe. We have ABI markers in
our unwind information for functions that are entry points into the
kernel. When stepping to the next frame, the unwinder will let us
know when sych a marker was encountered. We use this to stop the
current unwind session, query the trapframe and restart a new
unwind session based on the new trapframe.
The implementation is a bit sloppy, but at this time there are
bigger fish to fry.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ia64/ia64/db_trace.c | 23 | ||||
-rw-r--r-- | sys/ia64/ia64/unwind.c | 20 | ||||
-rw-r--r-- | sys/ia64/include/unwind.h | 1 |
3 files changed, 38 insertions, 6 deletions
diff --git a/sys/ia64/ia64/db_trace.c b/sys/ia64/ia64/db_trace.c index 4e164b2..744c9e2 100644 --- a/sys/ia64/ia64/db_trace.c +++ b/sys/ia64/ia64/db_trace.c @@ -49,19 +49,23 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif) { struct unw_regstate rs; + struct trapframe *tf; const char *name; db_expr_t offset; - uint64_t bsp, cfm, ip, pfs, reg; + uint64_t bsp, cfm, ip, pfs, reg, sp; c_db_sym_t sym; int args, error, i; - error = unw_create(&rs, &ddb_regs); + tf = &ddb_regs; + error = unw_create(&rs, tf); while (!error && count--) { error = unw_get_cfm(&rs, &cfm); if (!error) error = unw_get_bsp(&rs, &bsp); if (!error) error = unw_get_ip(&rs, &ip); + if (!error) + error = unw_get_sp(&rs, &sp); if (error) break; @@ -98,6 +102,21 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count, db_printsym(ip, DB_STGY_PROC); db_printf("\n"); + + if (error != EOVERFLOW) + continue; + if (sp < IA64_RR_BASE(5)) + break; + + tf = (struct trapframe *)(sp + 16); + if ((tf->tf_flags & FRAME_SYSCALL) != 0 || + tf->tf_special.iip < IA64_RR_BASE(5)) + break; + + /* XXX ask if we should unwind across the trapframe. */ + db_printf("--- trapframe at %p\n", tf); + unw_delete(&rs); + error = unw_create(&rs, tf); } unw_delete(&rs); diff --git a/sys/ia64/ia64/unwind.c b/sys/ia64/ia64/unwind.c index cfc5af7..592a773 100644 --- a/sys/ia64/ia64/unwind.c +++ b/sys/ia64/ia64/unwind.c @@ -282,16 +282,19 @@ void unw_delete(struct unw_regstate *rs) { - uwx_free(rs->env); + if (rs->env != NULL) + uwx_free(rs->env); } int unw_step(struct unw_regstate *rs) { - int uwxerr; + int err; - uwxerr = uwx_step(rs->env); - return ((uwxerr) ? EINVAL : 0); /* XXX */ + err = uwx_step(rs->env); + if (err == UWX_ABI_FRAME) + return (EOVERFLOW); + return ((err != 0) ? EINVAL : 0); /* XXX */ } int @@ -322,6 +325,15 @@ unw_get_ip(struct unw_regstate *s, uint64_t *r) } int +unw_get_sp(struct unw_regstate *s, uint64_t *r) +{ + int uwxerr; + + uwxerr = uwx_get_reg(s->env, UWX_REG_SP, r); + return ((uwxerr) ? EINVAL : 0); /* XXX */ +} + +int unw_table_add(uint64_t base, uint64_t start, uint64_t end) { struct unw_table *ut; diff --git a/sys/ia64/include/unwind.h b/sys/ia64/include/unwind.h index 794a85d..4ae85ec 100644 --- a/sys/ia64/include/unwind.h +++ b/sys/ia64/include/unwind.h @@ -44,6 +44,7 @@ int unw_step(struct unw_regstate *s); int unw_get_bsp(struct unw_regstate *s, uint64_t *r); int unw_get_cfm(struct unw_regstate *s, uint64_t *r); int unw_get_ip(struct unw_regstate *s, uint64_t *r); +int unw_get_sp(struct unw_regstate *s, uint64_t *r); int unw_table_add(uint64_t, uint64_t, uint64_t); void unw_table_remove(uint64_t); |