Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
gleocadie committed Nov 25, 2024
1 parent 31bf06f commit f1247d8
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 65 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.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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,27 @@

#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/blazesym.h"
#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 +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)
{
}

Expand Down Expand Up @@ -67,17 +68,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 +98,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 +133,9 @@ std::vector<ModuleInfo> 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;
Expand Down Expand Up @@ -196,67 +198,72 @@ 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
|| 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 = "<unknown>";
}

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

Expand Down Expand Up @@ -325,5 +332,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 @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
#include <string>
#include <memory>
#include <optional>
#include <utility>

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

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

extern "C"
{
#include "datadog/common.h"
Expand All @@ -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<ElfBuildIdImpl>(ptr, size)} {}

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 +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
Expand Down

0 comments on commit f1247d8

Please sign in to comment.