summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2003-07-12 04:35:09 +0000
committermarcel <marcel@FreeBSD.org>2003-07-12 04:35:09 +0000
commitd67caeb89db630bf5035e1e435148797619e110b (patch)
tree7b2a075cb606e8913871a3e5f82b6cb68735878e /sys
parent8c227c87ca84d5742057ac0e31620740cdea7f0e (diff)
downloadFreeBSD-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.c23
-rw-r--r--sys/ia64/ia64/unwind.c20
-rw-r--r--sys/ia64/include/unwind.h1
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);
OpenPOWER on IntegriCloud