From f1247d8be94475c22a1204160ee48052ff736f24 Mon Sep 17 00:00:00 2001 From: Gregory LEOCADIE Date: Mon, 25 Nov 2024 12:10:54 +0100 Subject: [PATCH] WIP --- build/cmake/FindLibdatadog.cmake | 10 +- .../CrashReportingLinux.cpp | 125 +++++++++--------- .../CrashReportingLinux.h | 6 +- .../CrashReporting.cpp | 9 ++ .../Datadog.Profiler.Native/CrashReporting.h | 47 +++++++ 5 files changed, 132 insertions(+), 65 deletions(-) diff --git a/build/cmake/FindLibdatadog.cmake b/build/cmake/FindLibdatadog.cmake index 46a839460547..05af984c5e48 100644 --- a/build/cmake/FindLibdatadog.cmake +++ b/build/cmake/FindLibdatadog.cmake @@ -4,22 +4,22 @@ endif() include(FetchContent) -set(LIBDATADOG_VERSION "v13.1.0" CACHE STRING "libdatadog version") +set(LIBDATADOG_VERSION "v14.1.0" CACHE STRING "libdatadog version") if (CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm64) if (DEFINED ENV{IsAlpine} AND "$ENV{IsAlpine}" MATCHES "true") - set(SHA256_LIBDATADOG "9cddbc9ece4c2fe9a1f0ab5a7cfed218d617c5154f318e0bce9a6102b265c989" CACHE STRING "libdatadog sha256") + set(SHA256_LIBDATADOG "fc6be3383d3a115804c43e2c66dd176c63f33b362d987d9b1211034e2b549c2d" CACHE STRING "libdatadog sha256") set(FILE_TO_DOWNLOAD libdatadog-aarch64-alpine-linux-musl.tar.gz) else() - set(SHA256_LIBDATADOG "db17a5873d82ef772f969582949b272dcd04044a0cd08b196d3820172a19814d" CACHE STRING "libdatadog sha256") + set(SHA256_LIBDATADOG "1a9bc4d99d23f7baf403b6b7527f9b9d76bdb166dc34656150561dcb148cc90b" CACHE STRING "libdatadog sha256") set(FILE_TO_DOWNLOAD libdatadog-aarch64-unknown-linux-gnu.tar.gz) endif() else() if (DEFINED ENV{IsAlpine} AND "$ENV{IsAlpine}" MATCHES "true") - set(SHA256_LIBDATADOG "46d0e6445fa1b0fbe8d079e6fa997fa10a4fef4084fe10f4b5886c92effc7be8" CACHE STRING "libdatadog sha256") + set(SHA256_LIBDATADOG "8244831681332dfa939eefe6923fe6a8beaffff48cb336f836b55a438078add1" CACHE STRING "libdatadog sha256") set(FILE_TO_DOWNLOAD libdatadog-${CMAKE_SYSTEM_PROCESSOR}-alpine-linux-musl.tar.gz) else() - set(SHA256_LIBDATADOG "adaf79470fd0b06ce6d63ae8f231e555fa12b70d5bf82565a96a25f59ea8071d" CACHE STRING "libdatadog sha256") + set(SHA256_LIBDATADOG "76fcb3bfe3b3971d77f6dd4968ffe6bd5f6a1ada82e2e990a78919107dc2ee40" CACHE STRING "libdatadog sha256") set(FILE_TO_DOWNLOAD libdatadog-${CMAKE_SYSTEM_PROCESSOR}-unknown-linux-gnu.tar.gz) endif() endif() diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.cpp index a4f26a44d742..9802de97f808 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.cpp @@ -5,26 +5,27 @@ #include #include -#include #include -#include #include +#include +#include -#include -#include -#include -#include +#include "FfiHelper.h" #include -#include +#include +#include #include +#include #include -#include "FfiHelper.h" +#include +#include extern "C" { +#include "datadog/blazesym.h" #include "datadog/common.h" -#include "datadog/profiling.h" #include "datadog/crashtracker.h" +#include "datadog/profiling.h" } #include @@ -35,8 +36,8 @@ CrashReporting* CrashReporting::Create(int32_t pid) return (CrashReporting*)crashReporting; } -CrashReportingLinux::CrashReportingLinux(int32_t pid) - : CrashReporting(pid) +CrashReportingLinux::CrashReportingLinux(int32_t pid) : + CrashReporting(pid) { } @@ -67,17 +68,17 @@ int32_t CrashReportingLinux::Initialize() return result; } -std::pair CrashReportingLinux::FindModule(uintptr_t ip) +const ModuleInfo* CrashReportingLinux::FindModule(uintptr_t ip) { for (auto const& module : _modules) { if (ip >= module.startAddress && ip < module.endAddress) { - return std::make_pair(module.path, module.baseAddress); + return &module; } } - return std::make_pair("", 0); + return nullptr; } std::vector CrashReportingLinux::GetModules() @@ -97,10 +98,9 @@ std::vector CrashReportingLinux::GetModules() std::getline(iss, path); // Skip whitespace at the start // Trim path - path.erase(path.begin(), std::find_if(path.begin(), path.end(), [](int ch) - { - return !std::isspace(ch); - })); + path.erase(path.begin(), std::find_if(path.begin(), path.end(), [](int ch) { + return !std::isspace(ch); + })); if (path.empty()) { @@ -133,7 +133,9 @@ std::vector CrashReportingLinux::GetModules() moduleBaseAddresses[path] = baseAddress; } - modules.push_back(ModuleInfo{ start, end, baseAddress, std::move(path) }); + std::size_t len = 0; + auto* buffer = blaze_read_elf_build_id(path.data(), &len); + modules.push_back(ModuleInfo{ start, end, baseAddress, std::move(path), ElfBuildId(buffer, len)}); } return modules; @@ -196,67 +198,72 @@ std::vector CrashReportingLinux::GetThreadFrames(int32_t tid, Resolv stackFrame.sp = sp; stackFrame.isSuspicious = false; - ResolveMethodData methodData; - auto [moduleName, moduleAddress] = FindModule(ip); - stackFrame.moduleAddress = moduleAddress; - - bool hasName = false; - - unw_proc_info_t procInfo; - result = unw_get_proc_info(&cursor, &procInfo); - - if (result == 0) + auto* module = FindModule(ip); + if (module != nullptr) { - stackFrame.symbolAddress = procInfo.start_ip; + stackFrame.moduleAddress = module->baseAddress; - unw_word_t offset; - result = unw_get_proc_name(&cursor, methodData.symbolName, sizeof(methodData.symbolName), &offset); + bool hasName = false; + + unw_proc_info_t procInfo; + result = unw_get_proc_info(&cursor, &procInfo); if (result == 0) { - stackFrame.method = std::string(methodData.symbolName); - hasName = true; + stackFrame.symbolAddress = procInfo.start_ip; - auto demangleResult = ddog_crasht_demangle(libdatadog::to_char_slice(stackFrame.method), DDOG_CRASHT_DEMANGLE_OPTIONS_COMPLETE); + ResolveMethodData methodData; + unw_word_t offset; + result = unw_get_proc_name(&cursor, methodData.symbolName, sizeof(methodData.symbolName), &offset); - if (demangleResult.tag == DDOG_CRASHT_STRING_WRAPPER_RESULT_OK) + if (result == 0) { - // TODO: There is currently no safe way to free the StringWrapper - auto stringWrapper = demangleResult.ok; + stackFrame.method = std::string(methodData.symbolName); + hasName = true; + + auto demangleResult = ddog_crasht_demangle(libdatadog::to_char_slice(stackFrame.method), DDOG_CRASHT_DEMANGLE_OPTIONS_COMPLETE); - if (stringWrapper.message.len > 0) + if (demangleResult.tag == DDOG_CRASHT_STRING_WRAPPER_RESULT_OK) { - stackFrame.method = std::string((char*)stringWrapper.message.ptr, stringWrapper.message.len); + // TODO: There is currently no safe way to free the StringWrapper + auto stringWrapper = demangleResult.ok; + + if (stringWrapper.message.len > 0) + { + stackFrame.method = std::string((char*)stringWrapper.message.ptr, stringWrapper.message.len); + } } } } - } - if (!hasName) - { - std::ostringstream unknownModule; - unknownModule << moduleName << "!+" << std::hex << (ip - moduleAddress); - stackFrame.method = unknownModule.str(); - } + if (!hasName) + { + std::ostringstream unknownModule; + unknownModule << module->path << "!+" << std::hex << (ip - module->baseAddress); + stackFrame.method = unknownModule.str(); + } - stackFrame.isSuspicious = false; + stackFrame.isSuspicious = false; - fs::path modulePath(moduleName); + stackFrame.buildId = module->build_id; - if (modulePath.has_filename()) - { - const auto moduleFilename = modulePath.stem().string(); + fs::path modulePath(module->path); - if (moduleFilename.rfind("Datadog", 0) == 0 - || moduleFilename == "libdatadog" - || moduleFilename == "datadog" - || moduleFilename == "libddwaf" - || moduleFilename == "ddwaf" ) + if (modulePath.has_filename()) { - stackFrame.isSuspicious = true; + const auto moduleFilename = modulePath.stem().string(); + + if (moduleFilename.rfind("Datadog", 0) == 0 || moduleFilename == "libdatadog" || moduleFilename == "datadog" || moduleFilename == "libddwaf" || moduleFilename == "ddwaf") + { + stackFrame.isSuspicious = true; + } } } + else + { + stackFrame.method = ""; + } frames.push_back(std::move(stackFrame)); @@ -325,5 +332,5 @@ std::string CrashReportingLinux::GetThreadName(int32_t tid) std::string threadName; std::getline(commFile, threadName); commFile.close(); - return threadName; + return threadName; } \ No newline at end of file diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.h index c8266de6a426..2ed89584e7d9 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.h @@ -4,6 +4,8 @@ #pragma once #include "CrashReporting.h" +#include +#include #include #include @@ -14,6 +16,8 @@ struct ModuleInfo uintptr_t endAddress; uintptr_t baseAddress; std::string path; + // defined in CrashReporting.h + ElfBuildId build_id; }; class CrashReportingLinux : public CrashReporting @@ -28,7 +32,7 @@ class CrashReportingLinux : public CrashReporting private: std::vector> GetThreads() override; std::vector GetThreadFrames(int32_t tid, ResolveManagedCallstack resolveManagedCallstack, void* context) override; - std::pair FindModule(uintptr_t ip); + const ModuleInfo* FindModule(uintptr_t ip); std::vector GetModules(); std::string GetSignalInfo(int32_t signal) override; std::string GetThreadName(int32_t tid); diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.cpp index 9174c7e9fc76..bc1b07723bb2 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.cpp @@ -222,12 +222,21 @@ int32_t CrashReporting::ResolveStacks(int32_t crashingThreadId, ResolveManagedCa .symbol_address = symbolAddress, }; +#ifdef _WINDOWS if (frame.hasPdbInfo) { stackFrames[i].normalized_ip.typ = DDOG_CRASHT_NORMALIZED_ADDRESS_TYPES_PDB; stackFrames[i].normalized_ip.age = frame.pdbAge; stackFrames[i].normalized_ip.build_id = { (uint8_t*)&frame.pdbSig, 16 }; } +#else + const auto buildId = frame.buildId.AsSpan(); + if (buildId.size() != 0) + { + stackFrames[i].normalized_ip.typ = DDOG_CRASHT_NORMALIZED_ADDRESS_TYPES_ELF; + stackFrames[i].normalized_ip.build_id = {buildId.data(), buildId.size()}; + } +#endif } auto threadIdStr = std::to_string(threadId); diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.h index 3126cdf03c59..a67a11216a85 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.h @@ -8,10 +8,13 @@ #include #include #include +#include #include "cor.h" #include "corprof.h" +#include "shared/src/native-src/dd_span.hpp" + extern "C" { #include "datadog/common.h" @@ -30,6 +33,46 @@ struct ResolveMethodData char symbolName[1024]; }; +#ifdef LINUX +class ElfBuildId +{ +private: + struct ElfBuildIdImpl { + ElfBuildIdImpl() : ElfBuildIdImpl(nullptr, 0) {} + ElfBuildIdImpl(std::uint8_t* ptr, std::size_t size) : _ptr{ptr}, _size{size} {}; + ~ElfBuildIdImpl() + { + auto* ptr = std::exchange(_ptr, nullptr); + if (ptr != nullptr && _size != 0) + { + _size = 0; + ::free(ptr); + } + } + + ElfBuildIdImpl(ElfBuildIdImpl const&) = delete; + ElfBuildIdImpl(ElfBuildIdImpl&&) = delete; + ElfBuildIdImpl& operator=(ElfBuildIdImpl const&) = delete; + ElfBuildIdImpl& operator=(ElfBuildIdImpl&&) = delete; + + std::uint8_t* _ptr; + std::size_t _size; + }; +public: + ElfBuildId() : ElfBuildId(nullptr, 0) {} + ElfBuildId(std::uint8_t* ptr, std::size_t size) + : _impl{std::make_shared(ptr, size)} {} + + shared::span AsSpan() const + { + return shared::span(_impl->_ptr, _impl->_size); + } + +private: + std::shared_ptr _impl; +}; +#endif + struct StackFrame { uint64_t ip; @@ -38,9 +81,13 @@ struct StackFrame uint64_t symbolAddress; uint64_t moduleAddress; bool isSuspicious; +#ifdef _WINDOWS bool hasPdbInfo; DWORD pdbAge; GUID pdbSig; +#else + ElfBuildId buildId; +#endif }; struct Tag