Skip to content

Commit

Permalink
Fix stacktraces on MacOS (#59690)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitamikhaylov committed Feb 9, 2024
1 parent b06e13f commit 50828da
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 6 deletions.
15 changes: 11 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,17 @@ endif()

include(cmake/cpu_features.cmake)

# Asynchronous unwind tables are needed for Query Profiler.
# They are already by default on some platforms but possibly not on all platforms.
# Enable it explicitly.
set (COMPILER_FLAGS "${COMPILER_FLAGS} -fasynchronous-unwind-tables")

# Query Profiler doesn't work on MacOS for several reasons
# - PHDR cache is not available
# - We use native functionality to get stacktraces which is not async signal safe
# and thus we don't need to generate asynchronous unwind tables
if (NOT OS_DARWIN)
# Asynchronous unwind tables are needed for Query Profiler.
# They are already by default on some platforms but possibly not on all platforms.
# Enable it explicitly.
set (COMPILER_FLAGS "${COMPILER_FLAGS} -fasynchronous-unwind-tables")
endif()

# Reproducible builds.
if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG")
Expand Down
4 changes: 4 additions & 0 deletions contrib/libunwind-cmake/unwind-override.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include <libunwind.h>

/// On MacOS this function will be replaced with a dynamic symbol
/// from the system library.
#if !defined(OS_DARWIN)
int backtrace(void ** buffer, int size)
{
return unw_backtrace(buffer, size);
}
#endif
2 changes: 1 addition & 1 deletion contrib/llvm-project
43 changes: 42 additions & 1 deletion src/Common/StackTrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <base/constexpr_helpers.h>
#include <base/demangle.h>

#include <Common/scope_guard_safe.h>
#include <Common/Dwarf.h>
#include <Common/Elf.h>
#include <Common/MemorySanitizer.h>
Expand All @@ -24,6 +25,15 @@

#include "config.h"

#include <boost/algorithm/string/split.hpp>

#if defined(OS_DARWIN)
/// This header contains functions like `backtrace` and `backtrace_symbols`
/// Which will be used for stack unwinding on Mac.
/// Read: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/backtrace.3.html
#include "execinfo.h"
#endif

namespace
{
/// Currently this variable is set up once on server startup.
Expand Down Expand Up @@ -262,6 +272,33 @@ void StackTrace::forEachFrame(
callback(current_inline_frame);
}

callback(current_frame);
}
#elif defined(OS_DARWIN)
UNUSED(fatal);

/// This function returns an array of string in a special (a little bit weird format)
/// The frame number, library name, address in hex, mangled symbol name, `+` sign, the offset.
char** strs = ::backtrace_symbols(frame_pointers.data(), static_cast<int>(size));
SCOPE_EXIT_SAFE({free(strs);});

for (size_t i = offset; i < size; ++i)
{
StackTrace::Frame current_frame;

std::vector<std::string> split;
boost::split(split, strs[i], isWhitespaceASCII);
split.erase(
std::remove_if(
split.begin(), split.end(),
[](const std::string & x) { return x.empty(); }),
split.end());
assert(split.size() == 6);

current_frame.virtual_addr = frame_pointers[i];
current_frame.physical_addr = frame_pointers[i];
current_frame.object = split[1];
current_frame.symbol = split[3];
callback(current_frame);
}
#else
Expand Down Expand Up @@ -306,7 +343,11 @@ StackTrace::StackTrace(const ucontext_t & signal_context)

void StackTrace::tryCapture()
{
#if defined(OS_DARWIN)
size = backtrace(frame_pointers.data(), capacity);
#else
size = unw_backtrace(frame_pointers.data(), capacity);
#endif
__msan_unpoison(frame_pointers.data(), size * sizeof(frame_pointers[0]));
}

Expand Down Expand Up @@ -376,7 +417,7 @@ toStringEveryLineImpl([[maybe_unused]] bool fatal, const StackTraceRefTriple & s
return callback("<Empty trace>");

size_t frame_index = stack_trace.offset;
#if defined(__ELF__) && !defined(OS_FREEBSD)
#if (defined(__ELF__) && !defined(OS_FREEBSD)) || defined(OS_DARWIN)
size_t inline_frame_index = 0;
auto callback_wrapper = [&](const StackTrace::Frame & frame)
{
Expand Down

0 comments on commit 50828da

Please sign in to comment.