Commit 30dcb7d8 authored by Chris Keeline's avatar Chris Keeline Committed by Facebook GitHub Bot

Fix fiber backtraces in gdb

Summary:
When we do the context switch onto the fiber, the stack frame points back to
the main context stack. While the fiber is running, this allows backtraces to
continue back onto the main context. When the fiber is suspended, we execute
code on the main context's stack, the pointers to this stack are now garbage,
backtracing in gdb runs into problems, such as garbage frames, gdb
crashes, and occasional cycles.

The fix here is to write a 0 to the saved return address in the last frame, when a fiber suspends.
gdb detects this and stops the trace
  #38 folly::fibers::FiberManager::activateFiber(folly::fibers::Fiber*) (this=0x0, fiber=0x0) at folly/fibers/FiberManagerInternal-inl.h:82
  #39 folly::fibers::FiberManager::runReadyFiber(folly::fibers::Fiber*) (this=0x0, fiber=0x0) at folly/fibers/FiberManagerInternal-inl.h:127
  #40 0x0000000000000000 in  ()

I gated the fix to linux since I'm not sure about the ABI for other platforms.

Reviewed By: yfeldblum

Differential Revision: D22774189

fbshipit-source-id: 2d4ad67a4a01bebc4ff1f9c285f6e3e95d13432c
parent d0302913
...@@ -59,7 +59,7 @@ class FiberImpl { ...@@ -59,7 +59,7 @@ class FiberImpl {
auto transfer = auto transfer =
boost::context::detail::jump_fcontext(mainContext_, nullptr); boost::context::detail::jump_fcontext(mainContext_, nullptr);
mainContext_ = transfer.fctx; mainContext_ = transfer.fctx;
fixStackUnwinding(); fixStackUnwinding(true);
auto context = reinterpret_cast<intptr_t>(transfer.data); auto context = reinterpret_cast<intptr_t>(transfer.data);
DCHECK_EQ(this, reinterpret_cast<FiberImpl*>(context)); DCHECK_EQ(this, reinterpret_cast<FiberImpl*>(context));
} }
...@@ -68,15 +68,26 @@ class FiberImpl { ...@@ -68,15 +68,26 @@ class FiberImpl {
static void fiberFunc(boost::context::detail::transfer_t transfer) { static void fiberFunc(boost::context::detail::transfer_t transfer) {
auto fiberImpl = reinterpret_cast<FiberImpl*>(transfer.data); auto fiberImpl = reinterpret_cast<FiberImpl*>(transfer.data);
fiberImpl->mainContext_ = transfer.fctx; fiberImpl->mainContext_ = transfer.fctx;
fiberImpl->fixStackUnwinding(); fiberImpl->fixStackUnwinding(false);
fiberImpl->func_(); fiberImpl->func_();
} }
void fixStackUnwinding() { void fixStackUnwinding(bool deactivate) {
if (kIsArchAmd64 && kIsLinux) { if (!kIsLinux) {
return;
}
auto stackBase = reinterpret_cast<void**>(stackBase_);
// Write a nullptr to the saved return address, when deactivating. Otherwise
// backtrace will point to the main context's stack. These pointers will no
// longer be valid once we switch to the main context.
if (deactivate) {
stackBase[-1] = nullptr;
return;
}
if (kIsArchAmd64) {
// Extract RBP and RIP from main context to stitch main context stack and // Extract RBP and RIP from main context to stitch main context stack and
// fiber stack. // fiber stack.
auto stackBase = reinterpret_cast<void**>(stackBase_);
auto mainContext = reinterpret_cast<void**>(mainContext_); auto mainContext = reinterpret_cast<void**>(mainContext_);
stackBase[-2] = mainContext[6]; stackBase[-2] = mainContext[6];
stackBase[-1] = mainContext[7]; stackBase[-1] = mainContext[7];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment