Skip to content

Instantly share code, notes, and snippets.

@lewissbaker
Forked from kennyyu/StackTrace.cpp
Created April 29, 2021 01:02
Show Gist options
  • Save lewissbaker/4784a07e916867835853ba267f8c93b1 to your computer and use it in GitHub Desktop.
Save lewissbaker/4784a07e916867835853ba267f8c93b1 to your computer and use it in GitHub Desktop.
ssize_t getAsyncStackTraceSafe(uintptr_t* addresses, size_t maxAddresses) {
size_t numFrames = 0;
// Start by walking the normal stack until we get to the frame right before
// the frame that holds the async root.
StackFrame* normalStackFrame = (StackFrame*)FOLLY_ASYNC_STACK_FRAME_POINTER();
StackFrame* normalStackFrameStop = nullptr;
const auto* asyncStackRoot = tryGetCurrentAsyncStackRoot();
AsyncStackFrame* asyncStackFrame = nullptr;
if (asyncStackRoot != nullptr) {
normalStackFrameStop = (StackFrame*)asyncStackRoot->getStackFramePointer();
asyncStackFrame = asyncStackRoot->topFrame;
}
// Walk normal stack-frames
walk_normal_stack:
while (numFrames < maxAddresses && normalStackFrame != nullptr) {
auto* nextStackFrame = normalStackFrame->parentFrame;
if (normalStackFrameStop != nullptr && nextStackFrame == normalStackFrameStop) {
// Reached end of normal stack-frame. Continue walking async stack frame.
goto walk_async_stack;
}
addresses[numFrames++] = reinterpret_cast<std::uintptr_t>(normalStackFrame->returnAddress);
normalStackFrame = nextStackFrame;
}
// Reached end of normal stack without hitting the stop stack-frame, or the buffer is full.
// Stop walking here.
goto walk_done;
walk_async_stack:
while (numFrames < maxAddresses && asyncStackFrame != nullptr) {
addresses[numFrames++] = reinterpret_cast<std::uintptr_t>(asyncStackFrame->getReturnAddress());
auto* nextAsyncFrame = asyncStackFrame->getParentFrame();
if (nextAsyncFrame == nullptr) {
// Reached end of async stack.
// The last async frame may have an AsyncStackRoot that points to the StackFrame that
// we should continue walking on. If so then continue walking the normal stack.
asyncStackRoot = asyncStackFrame->getStackRoot();
if (asyncStackRoot != nullptr) {
normalStackFrame = (StackFrame*)asyncStackRoot->getStackFramePointer();
if (normalStackFrame != nullptr) {
// Continue walking on the normal stack-frames
// Check if there is another stack root that indicates where we should stop
// walking the normal stack and resume walking another async stack.
asyncStackRoot = asyncStackRoot->getNextRoot();
if (asyncStackRoot != nullptr) {
normalStackFrameStop = (StackFrame*)asyncStackRoot->getStackFramePointer();
} else {
normalStackFrameStop = nullptr;
}
goto walk_normal_stack;
}
}
}
asyncStackFrame = nextAsyncFrame;
}
// Reached end of async stack with no chained on normal stack, or the buffer is full.
// Stop walking here.
walk_done:
return numFrames;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment