Skip to content

Commit 40e8072

Browse files
gleocadieveerbia
authored andcommitted
[Crashtracker] Use blazesym API to retrieve buildid (#6347)
1 parent ace0c79 commit 40e8072

File tree

7 files changed

+195
-82
lines changed

7 files changed

+195
-82
lines changed

build/cmake/FindLibdatadog.cmake

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@ endif()
44

55
include(FetchContent)
66

7-
set(LIBDATADOG_VERSION "v13.1.0" CACHE STRING "libdatadog version")
7+
set(LIBDATADOG_VERSION "v14.3.1" CACHE STRING "libdatadog version")
88

99
if (CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm64)
1010
if (DEFINED ENV{IsAlpine} AND "$ENV{IsAlpine}" MATCHES "true")
11-
set(SHA256_LIBDATADOG "9cddbc9ece4c2fe9a1f0ab5a7cfed218d617c5154f318e0bce9a6102b265c989" CACHE STRING "libdatadog sha256")
11+
set(SHA256_LIBDATADOG "57f83aff275628bb1af89c22bb4bd696726daf2a9e09b6cd0d966b29e65a7ad6" CACHE STRING "libdatadog sha256")
1212
set(FILE_TO_DOWNLOAD libdatadog-aarch64-alpine-linux-musl.tar.gz)
1313
else()
14-
set(SHA256_LIBDATADOG "db17a5873d82ef772f969582949b272dcd04044a0cd08b196d3820172a19814d" CACHE STRING "libdatadog sha256")
14+
set(SHA256_LIBDATADOG "36db8d50ccabb71571158ea13835c0f1d05d30b32135385f97c16343cfb6ddd4" CACHE STRING "libdatadog sha256")
1515
set(FILE_TO_DOWNLOAD libdatadog-aarch64-unknown-linux-gnu.tar.gz)
1616
endif()
1717
else()
1818
if (DEFINED ENV{IsAlpine} AND "$ENV{IsAlpine}" MATCHES "true")
19-
set(SHA256_LIBDATADOG "46d0e6445fa1b0fbe8d079e6fa997fa10a4fef4084fe10f4b5886c92effc7be8" CACHE STRING "libdatadog sha256")
19+
set(SHA256_LIBDATADOG "2f61fd21cf2f8147743e414b4a8c77250a17be3aecc42a69ffe54f0a603d5c92" CACHE STRING "libdatadog sha256")
2020
set(FILE_TO_DOWNLOAD libdatadog-${CMAKE_SYSTEM_PROCESSOR}-alpine-linux-musl.tar.gz)
2121
else()
22-
set(SHA256_LIBDATADOG "adaf79470fd0b06ce6d63ae8f231e555fa12b70d5bf82565a96a25f59ea8071d" CACHE STRING "libdatadog sha256")
22+
set(SHA256_LIBDATADOG "f01f05600591063eba4faf388f54c155ab4e6302e5776c7855e3734955f7daf7" CACHE STRING "libdatadog sha256")
2323
set(FILE_TO_DOWNLOAD libdatadog-${CMAKE_SYSTEM_PROCESSOR}-unknown-linux-gnu.tar.gz)
2424
endif()
2525
endif()

profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.cpp

+68-59
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,26 @@
55

66
#include <algorithm>
77
#include <cstdint>
8-
#include <vector>
98
#include <dirent.h>
10-
#include <string>
119
#include <memory>
10+
#include <string>
11+
#include <vector>
1212

13-
#include <libunwind.h>
14-
#include <libunwind-ptrace.h>
15-
#include <sys/ptrace.h>
16-
#include <sys/wait.h>
13+
#include "FfiHelper.h"
1714
#include <fstream>
18-
#include <sstream>
15+
#include <libunwind-ptrace.h>
16+
#include <libunwind.h>
1917
#include <map>
18+
#include <sstream>
2019
#include <string.h>
21-
#include "FfiHelper.h"
20+
#include <sys/ptrace.h>
21+
#include <sys/wait.h>
2222

2323
extern "C"
2424
{
2525
#include "datadog/common.h"
26-
#include "datadog/profiling.h"
2726
#include "datadog/crashtracker.h"
27+
#include "datadog/profiling.h"
2828
}
2929

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

38-
CrashReportingLinux::CrashReportingLinux(int32_t pid)
39-
: CrashReporting(pid)
38+
CrashReportingLinux::CrashReportingLinux(int32_t pid) :
39+
CrashReporting(pid)
4040
{
4141
}
4242

@@ -67,17 +67,17 @@ int32_t CrashReportingLinux::Initialize()
6767
return result;
6868
}
6969

70-
std::pair<std::string_view, uintptr_t> CrashReportingLinux::FindModule(uintptr_t ip)
70+
const ModuleInfo* CrashReportingLinux::FindModule(uintptr_t ip)
7171
{
7272
for (auto const& module : _modules)
7373
{
7474
if (ip >= module.startAddress && ip < module.endAddress)
7575
{
76-
return std::make_pair(module.path, module.baseAddress);
76+
return &module;
7777
}
7878
}
7979

80-
return std::make_pair("", 0);
80+
return nullptr;
8181
}
8282

8383
std::vector<ModuleInfo> CrashReportingLinux::GetModules()
@@ -97,10 +97,9 @@ std::vector<ModuleInfo> CrashReportingLinux::GetModules()
9797
std::getline(iss, path); // Skip whitespace at the start
9898

9999
// Trim path
100-
path.erase(path.begin(), std::find_if(path.begin(), path.end(), [](int ch)
101-
{
102-
return !std::isspace(ch);
103-
}));
100+
path.erase(path.begin(), std::find_if(path.begin(), path.end(), [](int ch) {
101+
return !std::isspace(ch);
102+
}));
104103

105104
if (path.empty())
106105
{
@@ -133,7 +132,8 @@ std::vector<ModuleInfo> CrashReportingLinux::GetModules()
133132
moduleBaseAddresses[path] = baseAddress;
134133
}
135134

136-
modules.push_back(ModuleInfo{ start, end, baseAddress, std::move(path) });
135+
auto buildId = ElfBuildId(path.data());
136+
modules.push_back(ModuleInfo{ start, end, baseAddress, std::move(path), std::move(buildId) });
137137
}
138138

139139
return modules;
@@ -196,67 +196,76 @@ std::vector<StackFrame> CrashReportingLinux::GetThreadFrames(int32_t tid, Resolv
196196
stackFrame.sp = sp;
197197
stackFrame.isSuspicious = false;
198198

199-
ResolveMethodData methodData;
200199

201-
auto [moduleName, moduleAddress] = FindModule(ip);
202-
stackFrame.moduleAddress = moduleAddress;
203-
204-
bool hasName = false;
205-
206-
unw_proc_info_t procInfo;
207-
result = unw_get_proc_info(&cursor, &procInfo);
208-
209-
if (result == 0)
200+
auto* module = FindModule(ip);
201+
if (module != nullptr)
210202
{
211-
stackFrame.symbolAddress = procInfo.start_ip;
203+
stackFrame.moduleAddress = module->baseAddress;
212204

213-
unw_word_t offset;
214-
result = unw_get_proc_name(&cursor, methodData.symbolName, sizeof(methodData.symbolName), &offset);
205+
bool hasName = false;
206+
207+
unw_proc_info_t procInfo;
208+
result = unw_get_proc_info(&cursor, &procInfo);
215209

216210
if (result == 0)
217211
{
218-
stackFrame.method = std::string(methodData.symbolName);
219-
hasName = true;
212+
stackFrame.symbolAddress = procInfo.start_ip;
220213

221-
auto demangleResult = ddog_crasht_demangle(libdatadog::to_char_slice(stackFrame.method), DDOG_CRASHT_DEMANGLE_OPTIONS_COMPLETE);
214+
ResolveMethodData methodData;
215+
unw_word_t offset;
216+
result = unw_get_proc_name(&cursor, methodData.symbolName, sizeof(methodData.symbolName), &offset);
222217

223-
if (demangleResult.tag == DDOG_CRASHT_STRING_WRAPPER_RESULT_OK)
218+
if (result == 0)
224219
{
225-
// TODO: There is currently no safe way to free the StringWrapper
226-
auto stringWrapper = demangleResult.ok;
220+
stackFrame.method = std::string(methodData.symbolName);
221+
hasName = true;
222+
223+
auto demangleResult = ddog_crasht_demangle(libdatadog::to_char_slice(stackFrame.method), DDOG_CRASHT_DEMANGLE_OPTIONS_COMPLETE);
227224

228-
if (stringWrapper.message.len > 0)
225+
if (demangleResult.tag == DDOG_CRASHT_STRING_WRAPPER_RESULT_OK)
229226
{
230-
stackFrame.method = std::string((char*)stringWrapper.message.ptr, stringWrapper.message.len);
227+
// TODO: There is currently no safe way to free the StringWrapper
228+
auto stringWrapper = demangleResult.ok;
229+
230+
if (stringWrapper.message.len > 0)
231+
{
232+
stackFrame.method = std::string((char*)stringWrapper.message.ptr, stringWrapper.message.len);
233+
}
231234
}
232235
}
233236
}
234-
}
235237

236-
if (!hasName)
237-
{
238-
std::ostringstream unknownModule;
239-
unknownModule << moduleName << "!<unknown>+" << std::hex << (ip - moduleAddress);
240-
stackFrame.method = unknownModule.str();
241-
}
238+
if (!hasName)
239+
{
240+
std::ostringstream unknownModule;
241+
unknownModule << module->path << "!<unknown>+" << std::hex << (ip - module->baseAddress);
242+
stackFrame.method = unknownModule.str();
243+
}
242244

243-
stackFrame.isSuspicious = false;
245+
stackFrame.isSuspicious = false;
244246

245-
fs::path modulePath(moduleName);
247+
stackFrame.buildId = module->build_id;
246248

247-
if (modulePath.has_filename())
248-
{
249-
const auto moduleFilename = modulePath.stem().string();
249+
fs::path modulePath(module->path);
250250

251-
if ((moduleFilename.rfind("Datadog", 0) == 0 && stackFrame.method != "dd_pthread_entry")
252-
|| moduleFilename == "libdatadog"
253-
|| moduleFilename == "datadog"
254-
|| moduleFilename == "libddwaf"
255-
|| moduleFilename == "ddwaf" )
251+
if (modulePath.has_filename())
256252
{
257-
stackFrame.isSuspicious = true;
253+
const auto moduleFilename = modulePath.stem().string();
254+
255+
if ((moduleFilename.rfind("Datadog", 0) == 0 && stackFrame.method != "dd_pthread_entry")
256+
|| moduleFilename == "libdatadog"
257+
|| moduleFilename == "datadog"
258+
|| moduleFilename == "libddwaf"
259+
|| moduleFilename == "ddwaf" )
260+
{
261+
stackFrame.isSuspicious = true;
262+
}
258263
}
259264
}
265+
else
266+
{
267+
stackFrame.method = "<unknown>";
268+
}
260269

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

@@ -325,5 +334,5 @@ std::string CrashReportingLinux::GetThreadName(int32_t tid)
325334
std::string threadName;
326335
std::getline(commFile, threadName);
327336
commFile.close();
328-
return threadName;
337+
return threadName;
329338
}

profiler/src/ProfilerEngine/Datadog.Profiler.Native.Linux/CrashReportingLinux.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#pragma once
55
#include "CrashReporting.h"
66

7+
#include <cstdint>
8+
#include <memory>
79
#include <string>
810

911
#include <libunwind.h>
@@ -14,6 +16,8 @@ struct ModuleInfo
1416
uintptr_t endAddress;
1517
uintptr_t baseAddress;
1618
std::string path;
19+
// defined in CrashReporting.h
20+
ElfBuildId build_id;
1721
};
1822

1923
class CrashReportingLinux : public CrashReporting
@@ -28,7 +32,7 @@ class CrashReportingLinux : public CrashReporting
2832
private:
2933
std::vector<std::pair<int32_t, std::string>> GetThreads() override;
3034
std::vector<StackFrame> GetThreadFrames(int32_t tid, ResolveManagedCallstack resolveManagedCallstack, void* context) override;
31-
std::pair<std::string_view, uintptr_t> FindModule(uintptr_t ip);
35+
const ModuleInfo* FindModule(uintptr_t ip);
3236
std::vector<ModuleInfo> GetModules();
3337
std::string GetSignalInfo(int32_t signal) override;
3438
std::string GetThreadName(int32_t tid);

profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,17 @@ int32_t CrashReporting::Initialize()
6969
return 1;
7070
}
7171

72+
#ifdef LINUX
73+
// temporary: will remove it when windows will target libdatadog >= 14.3.0
74+
auto otherResult = ddog_crasht_CrashInfo_set_procinfo(&_crashInfo, { _pid });
75+
76+
if (otherResult.tag == DDOG_CRASHT_RESULT_ERR)
77+
{
78+
SetLastError(otherResult.err);
79+
return 1;
80+
}
81+
#endif
82+
7283
return AddTag("severity", "crash");
7384
}
7485

@@ -222,12 +233,22 @@ int32_t CrashReporting::ResolveStacks(int32_t crashingThreadId, ResolveManagedCa
222233
.symbol_address = symbolAddress,
223234
};
224235

236+
#ifdef _WINDOWS
225237
if (frame.hasPdbInfo)
226238
{
227239
stackFrames[i].normalized_ip.typ = DDOG_CRASHT_NORMALIZED_ADDRESS_TYPES_PDB;
228240
stackFrames[i].normalized_ip.age = frame.pdbAge;
229241
stackFrames[i].normalized_ip.build_id = { (uint8_t*)&frame.pdbSig, 16 };
230242
}
243+
#else
244+
const auto buildId = frame.buildId.AsSpan();
245+
if (buildId.size() != 0)
246+
{
247+
stackFrames[i].normalized_ip.typ = DDOG_CRASHT_NORMALIZED_ADDRESS_TYPES_ELF;
248+
stackFrames[i].normalized_ip.build_id = {buildId.data(), buildId.size()};
249+
stackFrames[i].normalized_ip.file_offset = ip - moduleAddress;
250+
}
251+
#endif
231252
}
232253

233254
auto threadIdStr = std::to_string(threadId);

profiler/src/ProfilerEngine/Datadog.Profiler.Native/CrashReporting.h

+55
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,18 @@
88
#include <string>
99
#include <memory>
1010
#include <optional>
11+
#include <utility>
1112

1213
#include "cor.h"
1314
#include "corprof.h"
1415

16+
#include "shared/src/native-src/dd_span.hpp"
17+
1518
extern "C"
1619
{
20+
#ifdef LINUX
21+
#include "datadog/blazesym.h"
22+
#endif
1723
#include "datadog/common.h"
1824
#include "datadog/profiling.h"
1925
}
@@ -30,6 +36,51 @@ struct ResolveMethodData
3036
char symbolName[1024];
3137
};
3238

39+
#ifdef LINUX
40+
class ElfBuildId
41+
{
42+
private:
43+
struct ElfBuildIdImpl {
44+
ElfBuildIdImpl() : ElfBuildIdImpl(nullptr) {}
45+
ElfBuildIdImpl(const char* path) : _ptr{nullptr}, _size{0} {
46+
if (path != nullptr)
47+
{
48+
_ptr = blaze_read_elf_build_id(path, &_size);
49+
}
50+
};
51+
~ElfBuildIdImpl()
52+
{
53+
auto* ptr = std::exchange(_ptr, nullptr);
54+
if (ptr != nullptr && _size != 0)
55+
{
56+
_size = 0;
57+
::free(ptr);
58+
}
59+
}
60+
61+
ElfBuildIdImpl(ElfBuildIdImpl const&) = delete;
62+
ElfBuildIdImpl(ElfBuildIdImpl&&) = delete;
63+
ElfBuildIdImpl& operator=(ElfBuildIdImpl const&) = delete;
64+
ElfBuildIdImpl& operator=(ElfBuildIdImpl&&) = delete;
65+
66+
std::uint8_t* _ptr;
67+
std::size_t _size;
68+
};
69+
public:
70+
ElfBuildId() : ElfBuildId(nullptr) {}
71+
ElfBuildId(const char* path)
72+
: _impl{std::make_shared<ElfBuildIdImpl>(path)} {}
73+
74+
shared::span<std::uint8_t> AsSpan() const
75+
{
76+
return shared::span(_impl->_ptr, _impl->_size);
77+
}
78+
79+
private:
80+
std::shared_ptr<ElfBuildIdImpl> _impl;
81+
};
82+
#endif
83+
3384
struct StackFrame
3485
{
3586
uint64_t ip;
@@ -38,9 +89,13 @@ struct StackFrame
3889
uint64_t symbolAddress;
3990
uint64_t moduleAddress;
4091
bool isSuspicious;
92+
#ifdef _WINDOWS
4193
bool hasPdbInfo;
4294
DWORD pdbAge;
4395
GUID pdbSig;
96+
#else
97+
ElfBuildId buildId;
98+
#endif
4499
};
45100

46101
struct Tag

0 commit comments

Comments
 (0)