Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144382587
D23355.id67435.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D23355.id67435.diff
View Options
Index: share/man/man9/stack.9
===================================================================
--- share/man/man9/stack.9
+++ share/man/man9/stack.9
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 6, 2017
+.Dd January 24, 2020
.Dt STACK 9
.Os
.Sh NAME
@@ -65,10 +65,8 @@
.Fn stack_sbuf_print_ddb "struct sbuf sb*" "const struct stack *st"
.Ft void
.Fn stack_save "struct stack *st"
-.Ft void
-.Fn stack_save_td "struct stack *st" "struct thread *td"
.Ft int
-.Fn stack_save_td_running "struct stack *st" "struct thread *td"
+.Fn stack_save_td "struct stack *st" "struct thread *td"
.Sh DESCRIPTION
The
.Nm
@@ -93,18 +91,15 @@
Memory associated with a trace is freed by calling
.Fn stack_destroy .
.Pp
-A trace of the current kernel thread's call stack may be captured using
+A trace of the current thread's kernel call stack may be captured using
.Fn stack_save .
.Fn stack_save_td
-and
-.Fn stack_save_td_running
-can also be used to capture the stack of a caller-specified thread.
-Callers of these functions must own the thread lock of the specified thread.
+can be used to capture the kernel stack of a caller-specified thread.
+Callers of these functions must own the thread lock of the specified thread,
+and the thread's stack must not be swapped out.
.Fn stack_save_td
-can capture the stack of a kernel thread that is not running or
-swapped out at the time of the call.
-.Fn stack_save_td_running
-can capture the stack of a running kernel thread.
+can capture the kernel stack of a running thread, though note that this is
+not implemented on all platforms.
.Pp
.Fn stack_print
and
@@ -157,11 +152,11 @@
does not contain space to record additional frames, and a non-zero value is
returned.
.Pp
-.Fn stack_save_td_running
+.Fn stack_save_td
returns 0 when the stack capture was successful and a non-zero error number
otherwise.
In particular,
-.Er EAGAIN
+.Er EBUSY
is returned if the thread was running in user mode at the time that the
capture was attempted, and
.Er EOPNOTSUPP
Index: sys/amd64/amd64/trap.c
===================================================================
--- sys/amd64/amd64/trap.c
+++ sys/amd64/amd64/trap.c
@@ -52,7 +52,6 @@
#include "opt_hwpmc_hooks.h"
#include "opt_isa.h"
#include "opt_kdb.h"
-#include "opt_stack.h"
#include <sys/param.h>
#include <sys/bus.h>
@@ -228,11 +227,6 @@
(*pmc_intr)(frame) != 0)
return;
#endif
-
-#ifdef STACK
- if (stack_nmi_handler(frame) != 0)
- return;
-#endif
}
if ((frame->tf_rflags & PSL_I) == 0) {
Index: sys/arm/arm/stack_machdep.c
===================================================================
--- sys/arm/arm/stack_machdep.c
+++ sys/arm/arm/stack_machdep.c
@@ -68,8 +68,12 @@
{
struct unwind_state state;
- KASSERT(!TD_IS_SWAPPED(td), ("stack_save_td: swapped"));
- KASSERT(!TD_IS_RUNNING(td), ("stack_save_td: running"));
+ THREAD_LOCK_ASSERT(td, MA_OWNED);
+ KASSERT(!TD_IS_SWAPPED(td),
+ ("stack_save_td: thread %p is swapped", td));
+
+ if (TD_IS_RUNNING(td))
+ return (EOPNOTSUPP);
state.registers[FP] = td->td_pcb->pcb_regs.sf_r11;
state.registers[SP] = td->td_pcb->pcb_regs.sf_sp;
@@ -78,14 +82,3 @@
stack_capture(st, &state);
}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
- if (td == curthread) {
- stack_save(st);
- return (0);
- }
- return (EOPNOTSUPP);
-}
Index: sys/arm64/arm64/stack_machdep.c
===================================================================
--- sys/arm64/arm64/stack_machdep.c
+++ sys/arm64/arm64/stack_machdep.c
@@ -60,10 +60,12 @@
{
struct unwind_state frame;
- if (TD_IS_SWAPPED(td))
- panic("stack_save_td: swapped");
+ THREAD_LOCK_ASSERT(td, MA_OWNED);
+ KASSERT(!TD_IS_SWAPPED(td),
+ ("stack_save_td: thread %p is swapped", td));
+
if (TD_IS_RUNNING(td))
- panic("stack_save_td: running");
+ return (EOPNOTSUPP);
frame.sp = td->td_pcb->pcb_sp;
frame.fp = td->td_pcb->pcb_x[29];
@@ -71,25 +73,3 @@
stack_capture(st, &frame);
}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
- return (EOPNOTSUPP);
-}
-
-void
-stack_save(struct stack *st)
-{
- struct unwind_state frame;
- uint64_t sp;
-
- __asm __volatile("mov %0, sp" : "=&r" (sp));
-
- frame.sp = sp;
- frame.fp = (uint64_t)__builtin_frame_address(0);
- frame.pc = (uint64_t)stack_save;
-
- stack_capture(st, &frame);
-}
Index: sys/i386/i386/trap.c
===================================================================
--- sys/i386/i386/trap.c
+++ sys/i386/i386/trap.c
@@ -52,7 +52,6 @@
#include "opt_hwpmc_hooks.h"
#include "opt_isa.h"
#include "opt_kdb.h"
-#include "opt_stack.h"
#include "opt_trap.h"
#include <sys/param.h>
@@ -248,11 +247,6 @@
(*pmc_intr)(frame) != 0)
return;
#endif
-
-#ifdef STACK
- if (stack_nmi_handler(frame) != 0)
- return;
-#endif
}
if (type == T_MCHK) {
Index: sys/kern/kern_proc.c
===================================================================
--- sys/kern/kern_proc.c
+++ sys/kern/kern_proc.c
@@ -2669,17 +2669,12 @@
sizeof(kkstp->kkst_trace), SBUF_FIXEDLEN);
thread_lock(td);
kkstp->kkst_tid = td->td_tid;
- if (TD_IS_SWAPPED(td)) {
+ if (TD_IS_SWAPPED(td))
kkstp->kkst_state = KKST_STATE_SWAPPED;
- } else if (TD_IS_RUNNING(td)) {
- if (stack_save_td_running(st, td) == 0)
- kkstp->kkst_state = KKST_STATE_STACKOK;
- else
- kkstp->kkst_state = KKST_STATE_RUNNING;
- } else {
+ else if (stack_save_td(st, td) == 0)
kkstp->kkst_state = KKST_STATE_STACKOK;
- stack_save_td(st, td);
- }
+ else
+ kkstp->kkst_state = KKST_STATE_RUNNING;
thread_unlock(td);
PROC_UNLOCK(p);
stack_sbuf_print(&sb, st);
Index: sys/kern/subr_kdb.c
===================================================================
--- sys/kern/subr_kdb.c
+++ sys/kern/subr_kdb.c
@@ -433,9 +433,8 @@
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);
+ if (stack_save_td(&st, td) == 0)
+ stack_print_ddb(&st);
}
#endif
}
Index: sys/kern/subr_sleepqueue.c
===================================================================
--- sys/kern/subr_sleepqueue.c
+++ sys/kern/subr_sleepqueue.c
@@ -1246,7 +1246,7 @@
goto loop_end;
/* Note the td_lock is equal to the sleepq_lock here. */
- stack_save_td(st[stack_idx], td);
+ (void)stack_save_td(st[stack_idx], td);
sbuf_printf(td_infos[stack_idx], "%d: %s %p",
td->td_tid, td->td_name, td);
Index: sys/kern/tty_info.c
===================================================================
--- sys/kern/tty_info.c
+++ sys/kern/tty_info.c
@@ -340,12 +340,8 @@
if (tty_info_kstacks) {
if (TD_IS_SWAPPED(td))
sterr = ENOENT;
- else if (TD_IS_RUNNING(td))
- sterr = stack_save_td_running(&stack, td);
- else {
- stack_save_td(&stack, td);
- sterr = 0;
- }
+ else
+ sterr = stack_save_td(&stack, td);
}
#endif
thread_unlock(td);
Index: sys/mips/mips/stack_machdep.c
===================================================================
--- sys/mips/mips/stack_machdep.c
+++ sys/mips/mips/stack_machdep.c
@@ -132,32 +132,14 @@
{
u_register_t pc, sp;
- if (TD_IS_SWAPPED(td))
- panic("stack_save_td: swapped");
+ THREAD_LOCK_ASSERT(td, MA_OWNED);
+ KASSERT(!TD_IS_SWAPPED(td),
+ ("stack_save_td: thread %p is swapped", td));
+
if (TD_IS_RUNNING(td))
- panic("stack_save_td: running");
+ return (EOPNOTSUPP);
pc = td->td_pcb->pcb_regs.pc;
sp = td->td_pcb->pcb_regs.sp;
stack_capture(st, pc, sp);
}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
- return (EOPNOTSUPP);
-}
-
-void
-stack_save(struct stack *st)
-{
- u_register_t pc, sp;
-
- if (curthread == NULL)
- panic("stack_save: curthread == NULL");
-
- pc = curthread->td_pcb->pcb_regs.pc;
- sp = curthread->td_pcb->pcb_regs.sp;
- stack_capture(st, pc, sp);
-}
Index: sys/powerpc/powerpc/stack_machdep.c
===================================================================
--- sys/powerpc/powerpc/stack_machdep.c
+++ sys/powerpc/powerpc/stack_machdep.c
@@ -91,27 +91,13 @@
{
vm_offset_t frame;
- if (TD_IS_SWAPPED(td))
- panic("stack_save_td: swapped");
+ THREAD_LOCK_ASSERT(td, MA_OWNED);
+ KASSERT(!TD_IS_SWAPPED(td),
+ ("stack_save_td: thread %p is swapped", td));
+
if (TD_IS_RUNNING(td))
- panic("stack_save_td: running");
+ return (EOPNOTSUPP);
frame = td->td_pcb->pcb_sp;
stack_capture(st, frame);
}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
- return (EOPNOTSUPP);
-}
-
-void
-stack_save(struct stack *st)
-{
- register_t frame;
-
- frame = (register_t)__builtin_frame_address(0);
- stack_capture(st, frame);
-}
Index: sys/riscv/riscv/stack_machdep.c
===================================================================
--- sys/riscv/riscv/stack_machdep.c
+++ sys/riscv/riscv/stack_machdep.c
@@ -65,10 +65,12 @@
{
struct unwind_state frame;
- if (TD_IS_SWAPPED(td))
- panic("stack_save_td: swapped");
+ THREAD_LOCK_ASSERT(td, MA_OWNED);
+ KASSERT(!TD_IS_SWAPPED(td),
+ ("stack_save_td: thread %p is swapped", td));
+
if (TD_IS_RUNNING(td))
- panic("stack_save_td: running");
+ return (EOPNOTSUPP);
frame.sp = td->td_pcb->pcb_sp;
frame.fp = td->td_pcb->pcb_s[0];
@@ -76,25 +78,3 @@
stack_capture(st, &frame);
}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
- return (EOPNOTSUPP);
-}
-
-void
-stack_save(struct stack *st)
-{
- struct unwind_state frame;
- uint64_t sp;
-
- __asm __volatile("mv %0, sp" : "=&r" (sp));
-
- frame.sp = sp;
- frame.fp = (uint64_t)__builtin_frame_address(0);
- frame.pc = (uint64_t)stack_save;
-
- stack_capture(st, &frame);
-}
Index: sys/sparc64/sparc64/stack_machdep.c
===================================================================
--- sys/sparc64/sparc64/stack_machdep.c
+++ sys/sparc64/sparc64/stack_machdep.c
@@ -76,21 +76,16 @@
stack_save_td(struct stack *st, struct thread *td)
{
- if (TD_IS_SWAPPED(td))
- panic("stack_save_td: swapped");
+ THREAD_LOCK_ASSERT(td, MA_OWNED);
+ KASSERT(!TD_IS_SWAPPED(td),
+ ("stack_save_td: thread %p is swapped", td));
+
if (TD_IS_RUNNING(td))
- panic("stack_save_td: running");
+ return (EOPNOTSUPP);
stack_capture(st, (struct frame *)(td->td_pcb->pcb_sp + SPOFF));
}
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
- return (EOPNOTSUPP);
-}
-
void
stack_save(struct stack *st)
{
Index: sys/sys/stack.h
===================================================================
--- sys/sys/stack.h
+++ sys/sys/stack.h
@@ -67,7 +67,6 @@
/* MD Routines. */
struct thread;
void stack_save(struct stack *);
-void stack_save_td(struct stack *, struct thread *);
-int stack_save_td_running(struct stack *, struct thread *);
+int stack_save_td(struct stack *, struct thread *);
#endif
Index: sys/x86/include/apicvar.h
===================================================================
--- sys/x86/include/apicvar.h
+++ sys/x86/include/apicvar.h
@@ -123,20 +123,20 @@
#define IPI_AST 0 /* Generate software trap. */
#define IPI_PREEMPT 1
#define IPI_HARDCLOCK 2
-#define IPI_BITMAP_LAST IPI_HARDCLOCK
+#define IPI_TRACE 3 /* Collect stack trace. */
+#define IPI_BITMAP_LAST IPI_TRACE
#define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST)
#define IPI_STOP (APIC_IPI_INTS + 6) /* Stop CPU until restarted. */
#define IPI_SUSPEND (APIC_IPI_INTS + 7) /* Suspend CPU until restarted. */
#define IPI_DYN_FIRST (APIC_IPI_INTS + 8)
-#define IPI_DYN_LAST (253) /* IPIs allocated at runtime */
+#define IPI_DYN_LAST (254) /* IPIs allocated at runtime */
/*
* IPI_STOP_HARD does not need to occupy a slot in the IPI vector space since
* it is delivered using an NMI anyways.
*/
-#define IPI_NMI_FIRST 254
-#define IPI_TRACE 254 /* Interrupt for tracing. */
+#define IPI_NMI_FIRST 255
#define IPI_STOP_HARD 255 /* Stop CPU with a NMI. */
/*
Index: sys/x86/include/stack.h
===================================================================
--- sys/x86/include/stack.h
+++ sys/x86/include/stack.h
@@ -55,7 +55,7 @@
#endif /* __amd64__ */
#ifdef _KERNEL
-int stack_nmi_handler(struct trapframe *);
+void stack_capture_intr(void);
#endif
#endif /* !_X86_STACK_H */
Index: sys/x86/x86/mp_x86.c
===================================================================
--- sys/x86/x86/mp_x86.c
+++ sys/x86/x86/mp_x86.c
@@ -75,6 +75,7 @@
#include <machine/psl.h>
#include <machine/smp.h>
#include <machine/specialreg.h>
+#include <machine/stack.h>
#include <x86/ucode.h>
static MALLOC_DEFINE(M_CPUS, "cpus", "CPU items");
@@ -1284,6 +1285,9 @@
td->td_intr_nesting_level++;
oldframe = td->td_intr_frame;
td->td_intr_frame = &frame;
+ if (ipi_bitmap & (1 << IPI_TRACE)) {
+ stack_capture_intr();
+ }
if (ipi_bitmap & (1 << IPI_PREEMPT)) {
#ifdef COUNT_IPIS
(*ipi_preempt_counts[cpu])++;
Index: sys/x86/x86/stack_machdep.c
===================================================================
--- sys/x86/x86/stack_machdep.c
+++ sys/x86/x86/stack_machdep.c
@@ -63,15 +63,10 @@
typedef struct amd64_frame *x86_frame_t;
#endif
-#ifdef STACK
-static struct stack *nmi_stack;
-static volatile struct thread *nmi_pending;
-
-#ifdef SMP
-static struct mtx nmi_lock;
-MTX_SYSINIT(nmi_lock, &nmi_lock, "stack_nmi", MTX_SPIN);
-#endif
-#endif
+static struct stack *stack_intr_stack;
+static struct thread *stack_intr_td;
+static struct mtx intr_lock;
+MTX_SYSINIT(intr_lock, &intr_lock, "stack intr", MTX_DEF);
static void
stack_capture(struct thread *td, struct stack *st, register_t fp)
@@ -97,74 +92,67 @@
}
}
-int
-stack_nmi_handler(struct trapframe *tf)
-{
-
-#ifdef STACK
- /* Don't consume an NMI that wasn't meant for us. */
- if (nmi_stack == NULL || curthread != nmi_pending)
- return (0);
-
- if (!TRAPF_USERMODE(tf) && (TF_FLAGS(tf) & PSL_I) != 0)
- stack_capture(curthread, nmi_stack, TF_FP(tf));
- else
- /* We were running in usermode or had interrupts disabled. */
- nmi_stack->depth = 0;
-
- atomic_store_rel_ptr((long *)&nmi_pending, (long)NULL);
- return (1);
-#else
- return (0);
-#endif
-}
-
void
-stack_save_td(struct stack *st, struct thread *td)
+stack_capture_intr(void)
{
+ struct thread *td;
- if (TD_IS_SWAPPED(td))
- panic("stack_save_td: swapped");
- if (TD_IS_RUNNING(td))
- panic("stack_save_td: running");
-
- stack_capture(td, st, PCB_FP(td->td_pcb));
+ td = curthread;
+ stack_capture(td, stack_intr_stack, TF_FP(td->td_intr_frame));
+ atomic_store_rel_ptr((void *)&stack_intr_td, (uintptr_t)td);
}
int
-stack_save_td_running(struct stack *st, struct thread *td)
+stack_save_td(struct stack *st, struct thread *td)
{
+ int cpuid, error;
+ bool done;
-#ifdef STACK
THREAD_LOCK_ASSERT(td, MA_OWNED);
- MPASS(TD_IS_RUNNING(td));
+ KASSERT(!TD_IS_SWAPPED(td),
+ ("stack_save_td: thread %p is swapped", td));
+ if (TD_IS_RUNNING(td))
+ PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
if (td == curthread) {
stack_save(st);
return (0);
}
-#ifdef SMP
- mtx_lock_spin(&nmi_lock);
-
- nmi_stack = st;
- nmi_pending = td;
- ipi_cpu(td->td_oncpu, IPI_TRACE);
- while ((void *)atomic_load_acq_ptr((long *)&nmi_pending) != NULL)
- cpu_spinwait();
- nmi_stack = NULL;
-
- mtx_unlock_spin(&nmi_lock);
-
- if (st->depth == 0)
- return (EAGAIN);
-#else /* !SMP */
- KASSERT(0, ("curthread isn't running"));
-#endif /* SMP */
- return (0);
-#else /* !STACK */
- return (EOPNOTSUPP);
-#endif /* STACK */
+ for (done = false, error = 0; !done;) {
+ if (!TD_IS_RUNNING(td)) {
+ /*
+ * The thread will not start running so long as we hold
+ * its lock.
+ */
+ stack_capture(td, st, PCB_FP(td->td_pcb));
+ error = 0;
+ break;
+ }
+
+ thread_unlock(td);
+ cpuid = atomic_load_int(&td->td_oncpu);
+ if (cpuid == NOCPU) {
+ cpu_spinwait();
+ } else {
+ mtx_lock(&intr_lock);
+ stack_intr_td = NULL;
+ stack_intr_stack = st;
+ ipi_cpu(cpuid, IPI_TRACE);
+ while (atomic_load_acq_ptr((void *)&stack_intr_td) ==
+ (uintptr_t)NULL)
+ cpu_spinwait();
+ if (stack_intr_td == td) {
+ done = true;
+ error = st->depth > 0 ? 0 : EBUSY;
+ }
+ stack_intr_td = NULL;
+ mtx_unlock(&intr_lock);
+ }
+ thread_lock(td);
+ }
+
+ return (error);
}
void
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 9, 4:07 AM (58 m, 39 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28534533
Default Alt Text
D23355.id67435.diff (15 KB)
Attached To
Mode
D23355: Reimplement stack capture of running threads.
Attached
Detach File
Event Timeline
Log In to Comment