Page MenuHomeFreeBSD

D23355.id67435.diff
No OneTemporary

D23355.id67435.diff

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

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)

Event Timeline