diff options
author | max42 <max42@yandex-team.com> | 2023-07-29 00:02:16 +0300 |
---|---|---|
committer | max42 <max42@yandex-team.com> | 2023-07-29 00:02:16 +0300 |
commit | 73b89de71748a21e102d27b9f3ed1bf658766cb5 (patch) | |
tree | 188bbd2d622fa91cdcbb1b6d6d77fbc84a0646f5 /library/cpp/yt/backtrace | |
parent | 528e321bcc2a2b67b53aeba58c3bd88305a141ee (diff) | |
download | ydb-73b89de71748a21e102d27b9f3ed1bf658766cb5.tar.gz |
YT-19210: expose YQL shared library for YT.
After this, a new target libyqlplugin.so appears. in open-source cmake build.
Diff in open-source YDB repo looks like the following: https://paste.yandex-team.ru/f302bdb4-7ef2-4362-91c7-6ca45f329264
Diffstat (limited to 'library/cpp/yt/backtrace')
38 files changed, 1212 insertions, 0 deletions
diff --git a/library/cpp/yt/backtrace/CMakeLists.darwin-x86_64.txt b/library/cpp/yt/backtrace/CMakeLists.darwin-x86_64.txt new file mode 100644 index 0000000000..dbc5fa609f --- /dev/null +++ b/library/cpp/yt/backtrace/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,23 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(cursors) + +add_library(cpp-yt-backtrace) +target_compile_options(cpp-yt-backtrace PRIVATE + -Wdeprecated-this-capture +) +target_link_libraries(cpp-yt-backtrace PUBLIC + contrib-libs-cxxsupp + yutil + cpp-yt-string +) +target_sources(cpp-yt-backtrace PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/backtrace.cpp + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/symbolizers/dynload/dynload_symbolizer.cpp +) diff --git a/library/cpp/yt/backtrace/CMakeLists.linux-aarch64.txt b/library/cpp/yt/backtrace/CMakeLists.linux-aarch64.txt new file mode 100644 index 0000000000..358ab6a86f --- /dev/null +++ b/library/cpp/yt/backtrace/CMakeLists.linux-aarch64.txt @@ -0,0 +1,24 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(cursors) + +add_library(cpp-yt-backtrace) +target_compile_options(cpp-yt-backtrace PRIVATE + -Wdeprecated-this-capture +) +target_link_libraries(cpp-yt-backtrace PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + yutil + cpp-yt-string +) +target_sources(cpp-yt-backtrace PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/backtrace.cpp + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/symbolizers/dynload/dynload_symbolizer.cpp +) diff --git a/library/cpp/yt/backtrace/CMakeLists.linux-x86_64.txt b/library/cpp/yt/backtrace/CMakeLists.linux-x86_64.txt new file mode 100644 index 0000000000..358ab6a86f --- /dev/null +++ b/library/cpp/yt/backtrace/CMakeLists.linux-x86_64.txt @@ -0,0 +1,24 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(cursors) + +add_library(cpp-yt-backtrace) +target_compile_options(cpp-yt-backtrace PRIVATE + -Wdeprecated-this-capture +) +target_link_libraries(cpp-yt-backtrace PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + yutil + cpp-yt-string +) +target_sources(cpp-yt-backtrace PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/backtrace.cpp + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/symbolizers/dynload/dynload_symbolizer.cpp +) diff --git a/library/cpp/yt/backtrace/CMakeLists.txt b/library/cpp/yt/backtrace/CMakeLists.txt new file mode 100644 index 0000000000..f8b31df0c1 --- /dev/null +++ b/library/cpp/yt/backtrace/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/library/cpp/yt/backtrace/CMakeLists.windows-x86_64.txt b/library/cpp/yt/backtrace/CMakeLists.windows-x86_64.txt new file mode 100644 index 0000000000..8b4a651f33 --- /dev/null +++ b/library/cpp/yt/backtrace/CMakeLists.windows-x86_64.txt @@ -0,0 +1,20 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(cursors) + +add_library(cpp-yt-backtrace) +target_link_libraries(cpp-yt-backtrace PUBLIC + contrib-libs-cxxsupp + yutil + cpp-yt-string +) +target_sources(cpp-yt-backtrace PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/backtrace.cpp + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/symbolizers/dummy/dummy_symbolizer.cpp +) diff --git a/library/cpp/yt/backtrace/backtrace-inl.h b/library/cpp/yt/backtrace/backtrace-inl.h new file mode 100644 index 0000000000..b78eeffd75 --- /dev/null +++ b/library/cpp/yt/backtrace/backtrace-inl.h @@ -0,0 +1,36 @@ +#pragma once +#ifndef BACKTRACE_INL_H_ +#error "Direct inclusion of this file is not allowed, include backtrace.h" +// For the sake of sane code completion. +#include "backtrace.h" +#endif + +#include <util/system/compiler.h> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +template <class TCursor> +Y_NO_INLINE TBacktrace GetBacktrace( + TCursor* cursor, + TBacktraceBuffer buffer, + int framesToSkip) +{ + // Account for the current frame. + ++framesToSkip; + size_t frameCount = 0; + while (frameCount < buffer.size() && !cursor->IsFinished()) { + if (framesToSkip > 0) { + --framesToSkip; + } else { + buffer[frameCount++] = cursor->GetCurrentIP(); + } + cursor->MoveNext(); + } + return {buffer.begin(), frameCount}; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/backtrace.cpp b/library/cpp/yt/backtrace/backtrace.cpp new file mode 100644 index 0000000000..153a0a5dd0 --- /dev/null +++ b/library/cpp/yt/backtrace/backtrace.cpp @@ -0,0 +1,18 @@ +#include "backtrace.h" + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +TString SymbolizeBacktrace(TBacktrace backtrace) +{ + TString result; + SymbolizeBacktrace( + backtrace, + [&] (TStringBuf str) { result += str; }); + return result; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/backtrace.h b/library/cpp/yt/backtrace/backtrace.h new file mode 100644 index 0000000000..ea70d9558c --- /dev/null +++ b/library/cpp/yt/backtrace/backtrace.h @@ -0,0 +1,45 @@ +#pragma once + +#include <library/cpp/yt/memory/range.h> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +using TBacktrace = TRange<const void*>; +using TBacktraceBuffer = TMutableRange<const void*>; + +//! Obtains a backtrace via a given cursor. +/*! + * \param buffer is the buffer where the backtrace is written to + * \param framesToSkip is the number of top frames to skip + * \returns the portion of #buffer that has actually been filled + */ +template <class TCursor> +TBacktrace GetBacktrace( + TCursor* cursor, + TBacktraceBuffer buffer, + int framesToSkip); + +//! Symbolizes a backtrace invoking a given callback for each frame. +/*! + * \param backtrace Backtrace to symbolize + * \param frameCallback Callback to invoke per each frame + */ +void SymbolizeBacktrace( + TBacktrace backtrace, + const std::function<void(TStringBuf)>& frameCallback); + +//! Symbolizes a backtrace to a string. +/*! + * \param backtrace Backtrace to symbolize + */ +TString SymbolizeBacktrace(TBacktrace backtrace); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace + +#define BACKTRACE_INL_H_ +#include "backtrace-inl.h" +#undef BACKTRACE_INL_H_ diff --git a/library/cpp/yt/backtrace/cursors/CMakeLists.darwin-x86_64.txt b/library/cpp/yt/backtrace/cursors/CMakeLists.darwin-x86_64.txt new file mode 100644 index 0000000000..6c6f5d1c50 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,9 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(libunwind) diff --git a/library/cpp/yt/backtrace/cursors/CMakeLists.linux-aarch64.txt b/library/cpp/yt/backtrace/cursors/CMakeLists.linux-aarch64.txt new file mode 100644 index 0000000000..6c6f5d1c50 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/CMakeLists.linux-aarch64.txt @@ -0,0 +1,9 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(libunwind) diff --git a/library/cpp/yt/backtrace/cursors/CMakeLists.linux-x86_64.txt b/library/cpp/yt/backtrace/cursors/CMakeLists.linux-x86_64.txt new file mode 100644 index 0000000000..6c6f5d1c50 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/CMakeLists.linux-x86_64.txt @@ -0,0 +1,9 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(libunwind) diff --git a/library/cpp/yt/backtrace/cursors/CMakeLists.txt b/library/cpp/yt/backtrace/cursors/CMakeLists.txt new file mode 100644 index 0000000000..f8b31df0c1 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/library/cpp/yt/backtrace/cursors/CMakeLists.windows-x86_64.txt b/library/cpp/yt/backtrace/cursors/CMakeLists.windows-x86_64.txt new file mode 100644 index 0000000000..961a9a908b --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/CMakeLists.windows-x86_64.txt @@ -0,0 +1,9 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(dummy) diff --git a/library/cpp/yt/backtrace/cursors/dummy/CMakeLists.txt b/library/cpp/yt/backtrace/cursors/dummy/CMakeLists.txt new file mode 100644 index 0000000000..03d4a7153c --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/dummy/CMakeLists.txt @@ -0,0 +1,11 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +endif() diff --git a/library/cpp/yt/backtrace/cursors/dummy/CMakeLists.windows-x86_64.txt b/library/cpp/yt/backtrace/cursors/dummy/CMakeLists.windows-x86_64.txt new file mode 100644 index 0000000000..40a6e7d0a8 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/dummy/CMakeLists.windows-x86_64.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(backtrace-cursors-dummy) +target_link_libraries(backtrace-cursors-dummy PUBLIC + contrib-libs-cxxsupp + yutil +) +target_sources(backtrace-cursors-dummy PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/cursors/dummy/dummy_cursor.cpp +) diff --git a/library/cpp/yt/backtrace/cursors/dummy/dummy_cursor.cpp b/library/cpp/yt/backtrace/cursors/dummy/dummy_cursor.cpp new file mode 100644 index 0000000000..ea6e0bc08e --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/dummy/dummy_cursor.cpp @@ -0,0 +1,22 @@ +#include "dummy_cursor.h" + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +bool TDummyCursor::IsFinished() const +{ + return true; +} + +const void* TDummyCursor::GetCurrentIP() const +{ + return nullptr; +} + +void TDummyCursor::MoveNext() +{ } + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/dummy/dummy_cursor.h b/library/cpp/yt/backtrace/cursors/dummy/dummy_cursor.h new file mode 100644 index 0000000000..b47d7d2aba --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/dummy/dummy_cursor.h @@ -0,0 +1,17 @@ +#pragma once + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +class TDummyCursor +{ +public: + bool IsFinished() const; + const void* GetCurrentIP() const; + void MoveNext(); +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/dummy/ya.make b/library/cpp/yt/backtrace/cursors/dummy/ya.make new file mode 100644 index 0000000000..49fd7be050 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/dummy/ya.make @@ -0,0 +1,9 @@ +LIBRARY() + +INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) + +SRCS( + dummy_cursor.cpp +) + +END() diff --git a/library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.cpp b/library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.cpp new file mode 100644 index 0000000000..290d30c3ce --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.cpp @@ -0,0 +1,146 @@ +#include "frame_pointer_cursor.h" + +#include <util/generic/size_literals.h> + +#include <array> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +TFramePointerCursor::TFramePointerCursor( + TSafeMemoryReader* memoryReader, + const TFramePointerCursorContext& context) + : MemoryReader_(memoryReader) + , Rip_(reinterpret_cast<const void*>(context.Rip)) + , Rbp_(reinterpret_cast<const void*>(context.Rbp)) + , StartRsp_(reinterpret_cast<const void*>(context.Rsp)) +{ } + +bool TFramePointerCursor::IsFinished() const +{ + return Finished_; +} + +const void* TFramePointerCursor::GetCurrentIP() const +{ + return Rip_; +} + +void TFramePointerCursor::MoveNext() +{ + if (Finished_) { + return; + } + + auto add = [] (auto ptr, auto delta) { + return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(ptr) + delta); + }; + + auto checkPtr = [&] (auto ptr) { + ui8 data; + return MemoryReader_->Read(ptr, &data); + }; + + // We try unwinding stack manually by following frame pointers. + // + // We assume that stack does not span more than 4mb. + + if (First_) { + First_ = false; + + // For the first frame there are three special cases where naive + // unwinding would skip the caller frame. + // + // 1) Right after call instruction, rbp points to frame of a caller. + // 2) Right after "push rbp" instruction. + // 3) Right before ret instruction, rbp points to frame of a caller. + // + // We read current instruction and try to detect such cases. + // + // 55 push %rbp + // 48 89 e5 mov %rsp, %rbp + // c3 retq + + std::array<ui8, 3> data; + if (!MemoryReader_->Read(Rip_, &data)) { + Finished_ = true; + return; + } + + if (data[0] == 0xc3 || data[0] == 0x55) { + void* savedRip; + if (!MemoryReader_->Read(StartRsp_, &savedRip)) { + Finished_ = true; + return; + } + + // Avoid infinite loop. + if (Rip_ == savedRip) { + Finished_ = true; + return; + } + + // Detect garbage pointer. + if (!checkPtr(savedRip)) { + Finished_ = true; + return; + } + + Rip_ = savedRip; + return; + } + + if (data[0] == 0x48 && data[1] == 0x89 && data[2] == 0xe5) { + void* savedRip; + if (!MemoryReader_->Read(add(StartRsp_, 8), &savedRip)) { + Finished_ = true; + return; + } + + // Avoid infinite loop. + if (Rip_ == savedRip) { + Finished_ = true; + return; + } + + // Detect garbage pointer. + if (!checkPtr(savedRip)) { + Finished_ = true; + return; + } + + Rip_ = savedRip; + return; + } + } + + const void* savedRbp; + const void* savedRip; + if (!MemoryReader_->Read(Rbp_, &savedRbp) || !MemoryReader_->Read(add(Rbp_, 8), &savedRip)) { + Finished_ = true; + return; + } + + if (!checkPtr(savedRbp)) { + Finished_ = true; + return; + } + + if (!checkPtr(savedRip)) { + Finished_ = true; + return; + } + + if (savedRbp < StartRsp_ || savedRbp > add(StartRsp_, 4_MB)) { + Finished_ = true; + return; + } + + Rip_ = savedRip; + Rbp_ = savedRbp; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.h b/library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.h new file mode 100644 index 0000000000..7a6eaf431b --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.h @@ -0,0 +1,39 @@ +#pragma once + +#include <library/cpp/yt/memory/safe_memory_reader.h> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +struct TFramePointerCursorContext +{ + ui64 Rip; + ui64 Rsp; + ui64 Rbp; +}; + +class TFramePointerCursor +{ +public: + TFramePointerCursor( + TSafeMemoryReader* memoryReader, + const TFramePointerCursorContext& context); + + bool IsFinished() const; + const void* GetCurrentIP() const; + void MoveNext(); + +private: + TSafeMemoryReader* MemoryReader_; + bool Finished_ = false; + bool First_ = true; + + const void* Rip_ = nullptr; + const void* Rbp_ = nullptr; + const void* StartRsp_ = nullptr; +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/frame_pointer/ya.make b/library/cpp/yt/backtrace/cursors/frame_pointer/ya.make new file mode 100644 index 0000000000..cb85d70315 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/frame_pointer/ya.make @@ -0,0 +1,9 @@ +LIBRARY() + +INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) + +SRCS( + frame_pointer_cursor.cpp +) + +END() diff --git a/library/cpp/yt/backtrace/cursors/interop/interop.cpp b/library/cpp/yt/backtrace/cursors/interop/interop.cpp new file mode 100644 index 0000000000..b4e6cfbe6e --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/interop/interop.cpp @@ -0,0 +1,102 @@ +#include "interop.h" + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +TFramePointerCursorContext FramePointerCursorContextFromUcontext(const ucontext_t& ucontext) +{ +#if defined(_linux_) + return { + .Rip = static_cast<ui64>(ucontext.uc_mcontext.gregs[REG_RIP]), + .Rsp = static_cast<ui64>(ucontext.uc_mcontext.gregs[REG_RSP]), + .Rbp = static_cast<ui64>(ucontext.uc_mcontext.gregs[REG_RBP]), + }; +#elif defined(_darwin_) + return { + .Rip = static_cast<ui64>(ucontext.uc_mcontext->__ss.__rip), + .Rsp = static_cast<ui64>(ucontext.uc_mcontext->__ss.__rsp), + .Rbp = static_cast<ui64>(ucontext.uc_mcontext->__ss.__rbp), + }; +#else + #error Unsupported platform +#endif +} + +std::optional<unw_context_t> TrySynthesizeLibunwindContextFromMachineContext( + const TContMachineContext& machineContext) +{ + unw_context_t unwindContext; + if (unw_getcontext(&unwindContext) != 0) { + return {}; + } + + // Some dirty hacks follow. + struct TUnwindContextRegisters + { + ui64 Rax; + ui64 Rbx; + ui64 Rcx; + ui64 Rdx; + ui64 Rdi; + ui64 Rsi; + ui64 Rbp; + ui64 Rsp; + ui64 R8; + ui64 R9; + ui64 R10; + ui64 R11; + ui64 R12; + ui64 R13; + ui64 R14; + ui64 R15; + ui64 Rip; + ui64 Rflags; + ui64 CS; + ui64 FS; + ui64 GS; + }; + + struct TMachineContextRegisters + { + ui64 Rbx; + ui64 Rbp; + ui64 R12; + ui64 R13; + ui64 R14; + ui64 R15; + ui64 Rsp; + ui64 Rip; + }; + + static_assert(sizeof(TContMachineContext) >= sizeof(TMachineContextRegisters)); + static_assert(sizeof(unw_context_t) >= sizeof(TUnwindContextRegisters)); + const auto* machineContextRegisters = reinterpret_cast<const TMachineContextRegisters*>(&machineContext); + auto* unwindContextRegisters = reinterpret_cast<TUnwindContextRegisters*>(&unwindContext); + #define XX(register) unwindContextRegisters->register = machineContextRegisters->register; + XX(Rbx) + XX(Rbp) + XX(R12) + XX(R13) + XX(R14) + XX(R15) + XX(Rsp) + XX(Rip) + #undef XX + return unwindContext; +} + +TFramePointerCursorContext FramePointerCursorContextFromLibunwindCursor( + const unw_cursor_t& cursor) +{ + TFramePointerCursorContext context{}; + auto& mutableCursor = const_cast<unw_cursor_t&>(cursor); + YT_VERIFY(unw_get_reg(&mutableCursor, UNW_REG_IP, &context.Rip) == 0); + YT_VERIFY(unw_get_reg(&mutableCursor, UNW_X86_64_RSP, &context.Rsp) == 0); + YT_VERIFY(unw_get_reg(&mutableCursor, UNW_X86_64_RBP, &context.Rbp) == 0); + return context; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/interop/interop.h b/library/cpp/yt/backtrace/cursors/interop/interop.h new file mode 100644 index 0000000000..62e7177107 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/interop/interop.h @@ -0,0 +1,25 @@ +#pragma once + +#include <library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.h> + +#include <contrib/libs/libunwind/include/libunwind.h> + +#include <util/system/context.h> + +#include <optional> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +TFramePointerCursorContext FramePointerCursorContextFromUcontext(const ucontext_t& ucontext); + +std::optional<unw_context_t> TrySynthesizeLibunwindContextFromMachineContext( + const TContMachineContext& machineContext); + +TFramePointerCursorContext FramePointerCursorContextFromLibunwindCursor( + const unw_cursor_t& uwCursor); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/interop/ya.make b/library/cpp/yt/backtrace/cursors/interop/ya.make new file mode 100644 index 0000000000..6637f6a9b4 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/interop/ya.make @@ -0,0 +1,14 @@ +LIBRARY() + +INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) + +SRCS( + interop.cpp +) + +PEERDIR( + library/cpp/yt/backtrace/cursors/frame_pointer + contrib/libs/libunwind +) + +END() diff --git a/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.darwin-x86_64.txt b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.darwin-x86_64.txt new file mode 100644 index 0000000000..fdea07f78c --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,21 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(backtrace-cursors-libunwind) +target_compile_options(backtrace-cursors-libunwind PRIVATE + -Wdeprecated-this-capture +) +target_link_libraries(backtrace-cursors-libunwind PUBLIC + contrib-libs-cxxsupp + yutil + contrib-libs-libunwind +) +target_sources(backtrace-cursors-libunwind PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.cpp +) diff --git a/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.linux-aarch64.txt b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.linux-aarch64.txt new file mode 100644 index 0000000000..9d7858cc27 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.linux-aarch64.txt @@ -0,0 +1,22 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(backtrace-cursors-libunwind) +target_compile_options(backtrace-cursors-libunwind PRIVATE + -Wdeprecated-this-capture +) +target_link_libraries(backtrace-cursors-libunwind PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + yutil + contrib-libs-libunwind +) +target_sources(backtrace-cursors-libunwind PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.cpp +) diff --git a/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.linux-x86_64.txt b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.linux-x86_64.txt new file mode 100644 index 0000000000..9d7858cc27 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.linux-x86_64.txt @@ -0,0 +1,22 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(backtrace-cursors-libunwind) +target_compile_options(backtrace-cursors-libunwind PRIVATE + -Wdeprecated-this-capture +) +target_link_libraries(backtrace-cursors-libunwind PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + yutil + contrib-libs-libunwind +) +target_sources(backtrace-cursors-libunwind PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.cpp +) diff --git a/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.txt b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.txt new file mode 100644 index 0000000000..606ff46b4b --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/libunwind/CMakeLists.txt @@ -0,0 +1,15 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.cpp b/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.cpp new file mode 100644 index 0000000000..f814753034 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.cpp @@ -0,0 +1,70 @@ +#include "libunwind_cursor.h" + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +TLibunwindCursor::TLibunwindCursor() +{ + if (unw_getcontext(&Context_) != 0) { + Finished_ = true; + return; + } + + Initialize(); +} + +TLibunwindCursor::TLibunwindCursor(const unw_context_t& context) + : Context_(context) +{ + Initialize(); +} + +void TLibunwindCursor::Initialize() +{ + if (unw_init_local(&Cursor_, &Context_) != 0) { + Finished_ = true; + return; + } + + ReadCurrentIP(); +} + +bool TLibunwindCursor::IsFinished() const +{ + return Finished_; +} + +const void* TLibunwindCursor::GetCurrentIP() const +{ + return CurrentIP_; +} + +void TLibunwindCursor::MoveNext() +{ + if (Finished_) { + return; + } + + if (unw_step(&Cursor_) <= 0) { + Finished_ = true; + return; + } + + ReadCurrentIP(); +} + +void TLibunwindCursor::ReadCurrentIP() +{ + unw_word_t ip = 0; + if (unw_get_reg(&Cursor_, UNW_REG_IP, &ip) < 0) { + Finished_ = true; + return; + } + + CurrentIP_ = reinterpret_cast<const void*>(ip); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.h b/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.h new file mode 100644 index 0000000000..08b01d07ef --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/libunwind/libunwind_cursor.h @@ -0,0 +1,33 @@ +#pragma once + +#include <contrib/libs/libunwind/include/libunwind.h> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +class TLibunwindCursor +{ +public: + TLibunwindCursor(); + explicit TLibunwindCursor(const unw_context_t& context); + + bool IsFinished() const; + const void* GetCurrentIP() const; + void MoveNext(); + +private: + unw_context_t Context_; + unw_cursor_t Cursor_; + + bool Finished_ = false; + + const void* CurrentIP_ = nullptr; + + void Initialize(); + void ReadCurrentIP(); +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/cursors/libunwind/ya.make b/library/cpp/yt/backtrace/cursors/libunwind/ya.make new file mode 100644 index 0000000000..8f3a8c5284 --- /dev/null +++ b/library/cpp/yt/backtrace/cursors/libunwind/ya.make @@ -0,0 +1,13 @@ +LIBRARY() + +INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) + +SRCS( + libunwind_cursor.cpp +) + +PEERDIR( + contrib/libs/libunwind +) + +END() diff --git a/library/cpp/yt/backtrace/symbolizers/dummy/dummy_symbolizer.cpp b/library/cpp/yt/backtrace/symbolizers/dummy/dummy_symbolizer.cpp new file mode 100644 index 0000000000..19cb41e795 --- /dev/null +++ b/library/cpp/yt/backtrace/symbolizers/dummy/dummy_symbolizer.cpp @@ -0,0 +1,25 @@ +#include <library/cpp/yt/backtrace/backtrace.h> + +#include <library/cpp/yt/string/raw_formatter.h> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +void SymbolizeBacktrace( + TBacktrace backtrace, + const std::function<void(TStringBuf)>& frameCallback) +{ + for (int index = 0; index < std::ssize(backtrace); ++index) { + TRawFormatter<1024> formatter; + formatter.AppendNumber(index + 1, 10, 2); + formatter.AppendString(". "); + formatter.AppendNumberAsHexWithPadding(reinterpret_cast<uintptr_t>(backtrace[index]), 12); + formatter.AppendString("\n"); + frameCallback(formatter.GetBuffer()); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/symbolizers/dwarf/dwarf_symbolizer.cpp b/library/cpp/yt/backtrace/symbolizers/dwarf/dwarf_symbolizer.cpp new file mode 100644 index 0000000000..f5d02aaa33 --- /dev/null +++ b/library/cpp/yt/backtrace/symbolizers/dwarf/dwarf_symbolizer.cpp @@ -0,0 +1,64 @@ +#include <library/cpp/yt/backtrace/backtrace.h> + +#include <library/cpp/dwarf_backtrace/backtrace.h> + +#include <library/cpp/yt/string/raw_formatter.h> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +void SymbolizeBacktrace( + TBacktrace backtrace, + const std::function<void(TStringBuf)>& frameCallback) +{ + auto error = NDwarf::ResolveBacktrace({backtrace.begin(), backtrace.size()}, [&] (const NDwarf::TLineInfo& info) { + TRawFormatter<1024> formatter; + formatter.AppendNumber(info.Index + 1, 10, 2); + formatter.AppendString(". "); + formatter.AppendString("0x"); + const int width = (sizeof(void*) == 8 ? 12 : 8); + // 12 for x86_64 because higher bits are always zeroed. + formatter.AppendNumber(info.Address, 16, width, '0'); + formatter.AppendString(" in "); + formatter.AppendString(info.FunctionName); + const int bytesToAppendEstimate = 4 + info.FileName.Size() + 1 + 4 /* who cares about line numbers > 9999 */ + 1; + if (formatter.GetBytesRemaining() < bytesToAppendEstimate) { + const int offset = formatter.GetBytesRemaining() - bytesToAppendEstimate; + if (formatter.GetBytesWritten() + offset >= 0) { + formatter.Advance(offset); + } + } + formatter.AppendString(" at "); + formatter.AppendString(info.FileName); + formatter.AppendChar(':'); + formatter.AppendNumber(info.Line); + if (formatter.GetBytesRemaining() == 0) { + formatter.Revert(1); + } + formatter.AppendString("\n"); + frameCallback(formatter.GetBuffer()); + // Call the callback exactly `frameCount` times, + // even if there are inline functions and one frame resolved to several lines. + // It needs for case when caller uses `frameCount` less than 100 for pretty formatting. + if (info.Index + 1 == std::ssize(backtrace)) { + return NDwarf::EResolving::Break; + } + return NDwarf::EResolving::Continue; + }); + if (error) { + TRawFormatter<1024> formatter; + formatter.AppendString("*** Error symbolizing backtrace via Dwarf\n"); + formatter.AppendString("*** Code: "); + formatter.AppendNumber(error->Code); + formatter.AppendString("\n"); + formatter.AppendString("*** Message: "); + formatter.AppendString(error->Message); + formatter.AppendString("\n"); + frameCallback(formatter.GetBuffer()); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/symbolizers/dwarf/ya.make b/library/cpp/yt/backtrace/symbolizers/dwarf/ya.make new file mode 100644 index 0000000000..bffeb676d8 --- /dev/null +++ b/library/cpp/yt/backtrace/symbolizers/dwarf/ya.make @@ -0,0 +1,18 @@ +LIBRARY() + +SRCS( + GLOBAL dwarf_symbolizer.cpp +) + +PEERDIR( + library/cpp/dwarf_backtrace + library/cpp/yt/backtrace +) + +END() + +IF (BUILD_TYPE == "DEBUG" OR BUILD_TYPE == "PROFILE") + RECURSE_FOR_TESTS( + unittests + ) +ENDIF() diff --git a/library/cpp/yt/backtrace/symbolizers/dynload/dynload_symbolizer.cpp b/library/cpp/yt/backtrace/symbolizers/dynload/dynload_symbolizer.cpp new file mode 100644 index 0000000000..37ebda8e48 --- /dev/null +++ b/library/cpp/yt/backtrace/symbolizers/dynload/dynload_symbolizer.cpp @@ -0,0 +1,113 @@ +#include <library/cpp/yt/backtrace/backtrace.h> + +#include <library/cpp/yt/string/raw_formatter.h> + +#include <util/system/compiler.h> + +#include <dlfcn.h> +#include <cxxabi.h> + +namespace NYT::NBacktrace { + +//////////////////////////////////////////////////////////////////////////////// + +namespace { + +int GetSymbolInfo(const void* pc, char* buffer, int length) +{ + TBaseFormatter formatter(buffer, length); + + // See http://www.codesourcery.com/cxx-abi/abi.html#mangling + // And, yes, dladdr() is not async signal safe. We can substitute it + // with hand-written symbolization code from google-glog in case of any trouble. + Dl_info info; + if (!dladdr(pc, &info)) { + return 0; + } + + /* + * typedef struct { + * const char *dli_fname; // Pathname of shared object that + * // contains address + * void *dli_fbase; // Address at which shared object + * // is loaded + * const char *dli_sname; // Name of nearest symbol with address + * // lower than addr + * void *dli_saddr; // Exact address of symbol named + * // in dli_sname + * } Dl_info; + * + * If no symbol matching addr could be found, then dli_sname and dli_saddr are set to NULL. + */ + + if (info.dli_sname && info.dli_saddr) { + formatter.AppendString("<"); + int demangleStatus = 0; + + if (info.dli_sname[0] == '_' && info.dli_sname[1] == 'Z') { + // This is also not async signal safe. + // But (ta-dah!) we can replace it with symbolization code from google-glob. + char* demangledName = abi::__cxa_demangle(info.dli_sname, 0, 0, &demangleStatus); + if (demangleStatus == 0) { + formatter.AppendString(demangledName); + } else { + formatter.AppendString(info.dli_sname); + } + free(demangledName); + } else { + formatter.AppendString(info.dli_sname); + } + formatter.AppendString("+"); + formatter.AppendNumber((char*)pc - (char*)info.dli_saddr); + formatter.AppendString(">"); + formatter.AppendString(" "); + } + + if (info.dli_fname && info.dli_fbase) { + formatter.AppendString("("); + formatter.AppendString(info.dli_fname); + formatter.AppendString("+"); + formatter.AppendNumber((char*)pc - (char*)info.dli_fbase); + formatter.AppendString(")"); + } + return formatter.GetBytesWritten(); +} + +void DumpStackFrameInfo(TBaseFormatter* formatter, const void* pc) +{ + formatter->AppendString("@ "); + const int width = (sizeof(void*) == 8 ? 12 : 8) + 2; + // +2 for "0x"; 12 for x86_64 because higher bits are always zeroed. + formatter->AppendNumberAsHexWithPadding(reinterpret_cast<uintptr_t>(pc), width); + formatter->AppendString(" "); + // Get the symbol from the previous address of PC, + // because PC may be in the next function. + formatter->Advance(GetSymbolInfo( + reinterpret_cast<const char*>(pc) - 1, + formatter->GetCursor(), + formatter->GetBytesRemaining())); + if (formatter->GetBytesRemaining() == 0) { + formatter->Revert(1); + } + formatter->AppendString("\n"); +} + +} // namespace + +Y_WEAK void SymbolizeBacktrace( + TBacktrace backtrace, + const std::function<void(TStringBuf)>& frameCallback) +{ + for (int i = 0; i < std::ssize(backtrace); ++i) { + TRawFormatter<1024> formatter; + formatter.Reset(); + formatter.AppendNumber(i + 1, 10, 2); + formatter.AppendString(". "); + DumpStackFrameInfo(&formatter, backtrace[i]); + frameCallback(formatter.GetBuffer()); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/unittests/backtrace_ut.cpp b/library/cpp/yt/backtrace/unittests/backtrace_ut.cpp new file mode 100644 index 0000000000..5992b69277 --- /dev/null +++ b/library/cpp/yt/backtrace/unittests/backtrace_ut.cpp @@ -0,0 +1,61 @@ +#include <gtest/gtest.h> + +#include <gmock/gmock.h> + +#include <library/cpp/yt/memory/safe_memory_reader.h> + +#include <library/cpp/yt/backtrace/cursors/frame_pointer/frame_pointer_cursor.h> + +#include <library/cpp/yt/backtrace/cursors/interop/interop.h> + +#include <util/system/compiler.h> + +#include <contrib/libs/libunwind/include/libunwind.h> + +namespace NYT::NBacktrace { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +template <int Depth, class TFn> +Y_NO_INLINE void RunInDeepStack(TFn cb) +{ + if constexpr (Depth == 0) { + cb(); + } else { + std::vector<int> touchMem; + touchMem.push_back(0); + + RunInDeepStack<Depth-1>(cb); + + DoNotOptimizeAway(touchMem); + } +} + +TEST(TFramePointerCursor, FramePointerCursor) +{ + std::vector<const void*> backtrace; + RunInDeepStack<64>([&] { + unw_context_t unwContext; + ASSERT_TRUE(unw_getcontext(&unwContext) == 0); + + unw_cursor_t unwCursor; + ASSERT_TRUE(unw_init_local(&unwCursor, &unwContext) == 0); + + TSafeMemoryReader reader; + auto fpCursorContext = NBacktrace::FramePointerCursorContextFromLibunwindCursor(unwCursor); + NBacktrace::TFramePointerCursor fpCursor(&reader, fpCursorContext); + + while (!fpCursor.IsFinished()) { + backtrace.push_back(fpCursor.GetCurrentIP()); + fpCursor.MoveNext(); + } + }); + + ASSERT_THAT(backtrace, testing::SizeIs(testing::Ge(64u))); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT::NBacktrace diff --git a/library/cpp/yt/backtrace/unittests/ya.make b/library/cpp/yt/backtrace/unittests/ya.make new file mode 100644 index 0000000000..89e55a95ef --- /dev/null +++ b/library/cpp/yt/backtrace/unittests/ya.make @@ -0,0 +1,20 @@ +GTEST() + +INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) + +PEERDIR( + library/cpp/testing/gtest + library/cpp/yt/backtrace + library/cpp/yt/backtrace/cursors/interop + library/cpp/yt/backtrace/cursors/frame_pointer + library/cpp/yt/backtrace/cursors/libunwind + library/cpp/yt/memory +) + +IF (BUILD_TYPE == "DEBUG" OR BUILD_TYPE == "PROFILE") + SRCS( + backtrace_ut.cpp + ) +ENDIF() + +END() diff --git a/library/cpp/yt/backtrace/ya.make b/library/cpp/yt/backtrace/ya.make new file mode 100644 index 0000000000..d294082e06 --- /dev/null +++ b/library/cpp/yt/backtrace/ya.make @@ -0,0 +1,44 @@ +LIBRARY() + +INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) + +SRCS( + backtrace.cpp +) + +IF (OS_WINDOWS) + SRCS( + symbolizers/dummy/dummy_symbolizer.cpp + ) +ELSE() + SRCS( + symbolizers/dynload/dynload_symbolizer.cpp + ) +ENDIF() + +PEERDIR( + library/cpp/yt/string +) + +END() + +RECURSE( + cursors/dummy + cursors/frame_pointer +) + +IF (NOT OS_WINDOWS) + RECURSE( + cursors/libunwind + ) +ENDIF() + +IF (OS_LINUX) + RECURSE( + symbolizers/dwarf + ) + + RECURSE_FOR_TESTS( + unittests + ) +ENDIF() |