Skip to content

Commit

Permalink
[Crashtracker] Use blazesym API to retrieve buildid (#6347)
Browse files Browse the repository at this point in the history
  • Loading branch information
gleocadie authored and veerbia committed Dec 16, 2024
1 parent ace0c79 commit 40e8072
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 82 deletions.
10 changes: 5 additions & 5 deletions build/cmake/FindLibdatadog.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ endif()

include(FetchContent)

set(LIBDATADOG_VERSION "v13.1.0" CACHE STRING "libdatadog version")
set(LIBDATADOG_VERSION "v14.3.1" 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 "57f83aff275628bb1af89c22bb4bd696726daf2a9e09b6cd0d966b29e65a7ad6" 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 "36db8d50ccabb71571158ea13835c0f1d05d30b32135385f97c16343cfb6ddd4" 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 "2f61fd21cf2f8147743e414b4a8c77250a17be3aecc42a69ffe54f0a603d5c92" 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 "f01f05600591063eba4faf388f54c155ab4e6302e5776c7855e3734955f7daf7" CACHE STRING "libdatadog sha256")
set(FILE_TO_DOWNLOAD libdatadog-${CMAKE_SYSTEM_PROCESSOR}-unknown-linux-gnu.tar.gz)
endif()
endif()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,26 @@

#include <algorithm>
#include <cstdint>
#include <vector>
#include <dirent.h>
#include <string>
#include <memory>
#include <string>
#include <vector>

#include <libunwind.h>
#include <libunwind-ptrace.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include "FfiHelper.h"
#include <fstream>
#include <sstream>
#include <libunwind-ptrace.h>
#include <libunwind.h>
#include <map>
#include <sstream>
#include <string.h>
#include "FfiHelper.h"
#include <sys/ptrace.h>
#include <sys/wait.h>

extern "C"
{
#include "datadog/common.h"
#include "datadog/profiling.h"
#include "datadog/crashtracker.h"
#include "datadog/profiling.h"
}

#include <shared/src/native-src/dd_filesystem.hpp>
Expand All @@ -35,8 +35,8 @@ CrashReporting* CrashReporting::Create(int32_t pid)
return (CrashReporting*)crashReporting;
}

CrashReportingLinux::CrashReportingLinux(int32_t pid)
: CrashReporting(pid)
CrashReportingLinux::CrashReportingLinux(int32_t pid) :
CrashReporting(pid)
{
}

Expand Down Expand Up @@ -67,17 +67,17 @@ int32_t CrashReportingLinux::Initialize()
return result;
}

std::pair<std::string_view, uintptr_t> 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<ModuleInfo> CrashReportingLinux::GetModules()
Expand All @@ -97,10 +97,9 @@ std::vector<ModuleInfo> 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())
{
Expand Down Expand Up @@ -133,7 +132,8 @@ std::vector<ModuleInfo> CrashReportingLinux::GetModules()
moduleBaseAddresses[path] = baseAddress;
}

modules.push_back(ModuleInfo{ start, end, baseAddress, std::move(path) });
auto buildId = ElfBuildId(path.data());
modules.push_back(ModuleInfo{ start, end, baseAddress, std::move(path), std::move(buildId) });
}

return modules;
Expand Down Expand Up @@ -196,67 +196,76 @@ std::vector<StackFrame> 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 << "!<unknown>+" << std::hex << (ip - moduleAddress);
stackFrame.method = unknownModule.str();
}
if (!hasName)
{
std::ostringstream unknownModule;
unknownModule << module->path << "!<unknown>+" << 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 && stackFrame.method != "dd_pthread_entry")
|| 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 && stackFrame.method != "dd_pthread_entry")
|| moduleFilename == "libdatadog"
|| moduleFilename == "datadog"
|| moduleFilename == "libddwaf"
|| moduleFilename == "ddwaf" )
{
stackFrame.isSuspicious = true;
}
}
}
else
{
stackFrame.method = "<unknown>";
}

frames.push_back(std::move(stackFrame));

Expand Down Expand Up @@ -325,5 +334,5 @@ std::string CrashReportingLinux::GetThreadName(int32_t tid)
std::string threadName;
std::getline(commFile, threadName);
commFile.close();
return threadName;
return threadName;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#pragma once
#include "CrashReporting.h"

#include <cstdint>
#include <memory>
#include <string>

#include <libunwind.h>
Expand All @@ -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
Expand All @@ -28,7 +32,7 @@ class CrashReportingLinux : public CrashReporting
private:
std::vector<std::pair<int32_t, std::string>> GetThreads() override;
std::vector<StackFrame> GetThreadFrames(int32_t tid, ResolveManagedCallstack resolveManagedCallstack, void* context) override;
std::pair<std::string_view, uintptr_t> FindModule(uintptr_t ip);
const ModuleInfo* FindModule(uintptr_t ip);
std::vector<ModuleInfo> GetModules();
std::string GetSignalInfo(int32_t signal) override;
std::string GetThreadName(int32_t tid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ int32_t CrashReporting::Initialize()
return 1;
}

#ifdef LINUX
// temporary: will remove it when windows will target libdatadog >= 14.3.0
auto otherResult = ddog_crasht_CrashInfo_set_procinfo(&_crashInfo, { _pid });

if (otherResult.tag == DDOG_CRASHT_RESULT_ERR)
{
SetLastError(otherResult.err);
return 1;
}
#endif

return AddTag("severity", "crash");
}

Expand Down Expand Up @@ -222,12 +233,22 @@ 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()};
stackFrames[i].normalized_ip.file_offset = ip - moduleAddress;
}
#endif
}

auto threadIdStr = std::to_string(threadId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@
#include <string>
#include <memory>
#include <optional>
#include <utility>

#include "cor.h"
#include "corprof.h"

#include "shared/src/native-src/dd_span.hpp"

extern "C"
{
#ifdef LINUX
#include "datadog/blazesym.h"
#endif
#include "datadog/common.h"
#include "datadog/profiling.h"
}
Expand All @@ -30,6 +36,51 @@ struct ResolveMethodData
char symbolName[1024];
};

#ifdef LINUX
class ElfBuildId
{
private:
struct ElfBuildIdImpl {
ElfBuildIdImpl() : ElfBuildIdImpl(nullptr) {}
ElfBuildIdImpl(const char* path) : _ptr{nullptr}, _size{0} {
if (path != nullptr)
{
_ptr = blaze_read_elf_build_id(path, &_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) {}
ElfBuildId(const char* path)
: _impl{std::make_shared<ElfBuildIdImpl>(path)} {}

shared::span<std::uint8_t> AsSpan() const
{
return shared::span(_impl->_ptr, _impl->_size);
}

private:
std::shared_ptr<ElfBuildIdImpl> _impl;
};
#endif

struct StackFrame
{
uint64_t ip;
Expand All @@ -38,9 +89,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
Expand Down
Loading

0 comments on commit 40e8072

Please sign in to comment.