From 823d930fbc1ceb24032bbf91c6b002cda89b8b89 Mon Sep 17 00:00:00 2001 From: jhb Date: Mon, 21 May 2012 21:14:09 +0000 Subject: [PATCH] MFC 234190,234196,234280: - Extend the KDB interface to add a per-debugger callback to print a backtrace for an arbitrary thread (rather than the calling thread). A kdb_backtrace_thread() wrapper function uses the configured debugger if possible, otherwise it falls back to using stack(9) if that is available. - Replace a direct call to db_trace_thread() in propagate_priority() with a call to kdb_backtrace_thread() instead. git-svn-id: svn://svn.freebsd.org/base/stable/9@235741 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/ddb/db_main.c | 16 +++++++++++++++- sys/gdb/gdb_main.c | 2 +- sys/kern/subr_kdb.c | 27 ++++++++++++++++++++++++++- sys/kern/subr_turnstile.c | 6 ++---- sys/sys/kdb.h | 14 +++++++++----- 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/sys/ddb/db_main.c b/sys/ddb/db_main.c index 837510817..6e9286cbc 100644 --- a/sys/ddb/db_main.c +++ b/sys/ddb/db_main.c @@ -51,8 +51,10 @@ SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW, 0, "DDB settings"); static dbbe_init_f db_init; static dbbe_trap_f db_trap; static dbbe_trace_f db_trace_self_wrapper; +static dbbe_trace_thread_f db_trace_thread_wrapper; -KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trap); +KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper, + db_trap); vm_offset_t ksym_start, ksym_end; @@ -246,3 +248,15 @@ db_trace_self_wrapper(void) db_trace_self(); (void)kdb_jmpbuf(prev_jb); } + +static void +db_trace_thread_wrapper(struct thread *td) +{ + jmp_buf jb; + void *prev_jb; + + prev_jb = kdb_jmpbuf(jb); + if (setjmp(jb) == 0) + db_trace_thread(td, -1); + (void)kdb_jmpbuf(prev_jb); +} diff --git a/sys/gdb/gdb_main.c b/sys/gdb/gdb_main.c index 8f3c271e0..4ed327210 100644 --- a/sys/gdb/gdb_main.c +++ b/sys/gdb/gdb_main.c @@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$"); static dbbe_init_f gdb_init; static dbbe_trap_f gdb_trap; -KDB_BACKEND(gdb, gdb_init, NULL, gdb_trap); +KDB_BACKEND(gdb, gdb_init, NULL, NULL, gdb_trap); static struct gdb_dbgport null_gdb_dbgport; DATA_SET(gdb_dbgport_set, null_gdb_dbgport); diff --git a/sys/kern/subr_kdb.c b/sys/kern/subr_kdb.c index c122ca273..dcead53cb 100644 --- a/sys/kern/subr_kdb.c +++ b/sys/kern/subr_kdb.c @@ -73,7 +73,7 @@ struct trapframe *kdb_frame = NULL; static int kdb_break_to_debugger = KDB_BREAK_TO_DEBUGGER; static int kdb_alt_break_to_debugger = KDB_ALT_BREAK_TO_DEBUGGER; -KDB_BACKEND(null, NULL, NULL, NULL); +KDB_BACKEND(null, NULL, NULL, NULL, NULL); SET_DECLARE(kdb_dbbe_set, struct kdb_dbbe); static int kdb_sysctl_available(SYSCTL_HANDLER_ARGS); @@ -371,12 +371,37 @@ kdb_backtrace(void) struct stack st; printf("KDB: stack backtrace:\n"); + stack_zero(&st); stack_save(&st); stack_print_ddb(&st); } #endif } +/* + * Similar to kdb_backtrace() except that it prints a backtrace of an + * arbitrary thread rather than the calling thread. + */ +void +kdb_backtrace_thread(struct thread *td) +{ + + if (kdb_dbbe != NULL && kdb_dbbe->dbbe_trace_thread != NULL) { + printf("KDB: stack backtrace of thread %d:\n", td->td_tid); + kdb_dbbe->dbbe_trace_thread(td); + } +#ifdef STACK + else { + struct stack st; + + printf("KDB: stack backtrace of thread %d:\n", td->td_tid); + stack_zero(&st); + stack_save_td(&st, td); + stack_print_ddb(&st); + } +#endif +} + /* * Set/change the current backend. */ diff --git a/sys/kern/subr_turnstile.c b/sys/kern/subr_turnstile.c index 0407920f2..238f0f99d 100644 --- a/sys/kern/subr_turnstile.c +++ b/sys/kern/subr_turnstile.c @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -78,7 +79,6 @@ __FBSDID("$FreeBSD$"); #include #ifdef DDB -#include #include #include #include @@ -216,9 +216,7 @@ propagate_priority(struct thread *td) printf( "Sleeping thread (tid %d, pid %d) owns a non-sleepable lock\n", td->td_tid, td->td_proc->p_pid); -#ifdef DDB - db_trace_thread(td, -1); -#endif + kdb_backtrace_thread(td); panic("sleeping thread"); } diff --git a/sys/sys/kdb.h b/sys/sys/kdb.h index 61ee0973e..1c0bf0656 100644 --- a/sys/sys/kdb.h +++ b/sys/sys/kdb.h @@ -31,31 +31,34 @@ #include +struct pcb; +struct thread; +struct trapframe; + typedef int dbbe_init_f(void); typedef void dbbe_trace_f(void); +typedef void dbbe_trace_thread_f(struct thread *); typedef int dbbe_trap_f(int, int); struct kdb_dbbe { const char *dbbe_name; dbbe_init_f *dbbe_init; dbbe_trace_f *dbbe_trace; + dbbe_trace_thread_f *dbbe_trace_thread; dbbe_trap_f *dbbe_trap; int dbbe_active; }; -#define KDB_BACKEND(name, init, trace, trap) \ +#define KDB_BACKEND(name, init, trace, trace_thread, trap) \ static struct kdb_dbbe name##_dbbe = { \ .dbbe_name = #name, \ .dbbe_init = init, \ .dbbe_trace = trace, \ + .dbbe_trace_thread = trace_thread, \ .dbbe_trap = trap \ }; \ DATA_SET(kdb_dbbe_set, name##_dbbe) -struct pcb; -struct thread; -struct trapframe; - extern int kdb_active; /* Non-zero while in debugger. */ extern int debugger_on_panic; /* enter the debugger on panic. */ extern struct kdb_dbbe *kdb_dbbe; /* Default debugger backend or NULL. */ @@ -67,6 +70,7 @@ int kdb_alt_break(int, int *); int kdb_alt_break_gdb(int, int *); int kdb_break(void); void kdb_backtrace(void); +void kdb_backtrace_thread(struct thread *); int kdb_dbbe_select(const char *); void kdb_enter(const char *, const char *); void kdb_init(void); -- 2.45.0