endif()
set(HEAPTRACK_VERSION_MAJOR 1)
-set(HEAPTRACK_VERSION_MINOR 0)
+set(HEAPTRACK_VERSION_MINOR 1)
set(HEAPTRACK_VERSION_PATCH 0)
set(HEAPTRACK_LIB_VERSION 1.0.0)
set(HEAPTRACK_LIB_SOVERSION 1)
return ipId;
}
+ bool fileIsReadable(const string& path) const
+ {
+ return access(path.c_str(), R_OK) == 0;
+ }
+
std::string findDebugFile(const std::string& input) const
{
// TODO: also try to find a debug file by build-id
// TODO: also lookup in (user-configurable) debug path
std::string file = input + ".debug";
- if (access(file.c_str(), R_OK) == 0) {
- return file;
- } else {
- return input;
+ return fileIsReadable(file) ? file : input;
+ }
+
+ std::string findBuildIdFile(const string& buildId) const
+ {
+ if (buildId.empty()) {
+ return {};
}
+ // TODO: also lookup in (user-configurable) debug path
+ const auto path = "/usr/lib/debug/.build-id/" + buildId.substr(0, 2) + '/' + buildId.substr(2) + ".debug";
+ cerr << path << endl;
+ return fileIsReadable(path) ? path : string();
}
/**
* Prevent the same file from being initialized multiple times.
* This drastically cuts the memory consumption down
*/
- backtrace_state* findBacktraceState(const std::string& originalFileName, uintptr_t addressStart)
+ backtrace_state* findBacktraceState(const std::string& originalFileName, const string& buildId, uintptr_t addressStart)
{
if (boost::algorithm::starts_with(originalFileName, "linux-vdso.so")) {
// prevent warning, since this will always fail
return it->second;
}
- const auto fileName = findDebugFile(originalFileName);
+ // TODO: also lookup in (user-configurable) sysroot path
+ const auto buildIdFile = findBuildIdFile(buildId);
+ const auto fileName = buildIdFile.empty() ? findDebugFile(originalFileName) : buildIdFile;
struct CallbackData
{
if (fileName == "-") {
data.clearModules();
} else {
- if (fileName == "x") {
- fileName = exe;
- }
- std::string internedString;
- const auto moduleIndex = data.intern(fileName, &internedString);
+ string buildId;
+ reader >> buildId;
+
uintptr_t addressStart = 0;
if (!(reader >> addressStart)) {
cerr << "failed to parse line: " << reader.line() << endl;
return 1;
}
- auto state = data.findBacktraceState(internedString, addressStart);
+
+ if (fileName == "x") {
+ fileName = exe;
+ }
+ std::string internedString;
+ const auto moduleIndex = data.intern(fileName, &internedString);
+
+ auto state = data.findBacktraceState(internedString, buildId, addressStart);
uintptr_t vAddr = 0;
uintptr_t memSize = 0;
while ((reader >> vAddr) && (reader >> memSize)) {
#include "libheaptrack.h"
+#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
debugLog<VerboseOutput>("dlopen_notify_callback: %s %zx", fileName, info->dlpi_addr);
- if (fprintf(heaptrack->s_data->out, "m %s %zx", fileName, info->dlpi_addr) < 0) {
+ const auto MAX_BUILD_ID_SIZE = 20u;
+ unsigned raw_build_id_size = 0;
+ unsigned char raw_build_id[MAX_BUILD_ID_SIZE] = {};
+
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ const auto& phdr = info->dlpi_phdr[i];
+ if (raw_build_id_size == 0 && phdr.p_type == PT_NOTE) {
+ auto segmentAddr = phdr.p_vaddr + info->dlpi_addr;
+ const auto segmentEnd = segmentAddr + phdr.p_memsz;
+ const ElfW(Nhdr)* nhdr = nullptr;
+ while (segmentAddr < segmentEnd) {
+ nhdr = reinterpret_cast<ElfW(Nhdr)*>(segmentAddr);
+ if (nhdr->n_type == NT_GNU_BUILD_ID) {
+ break;
+ }
+ segmentAddr += sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz;
+ }
+ if (nhdr->n_type == NT_GNU_BUILD_ID) {
+ const auto buildIdAddr = segmentAddr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz;
+ if (buildIdAddr + nhdr->n_descsz <= segmentEnd && nhdr->n_descsz <= MAX_BUILD_ID_SIZE) {
+ const auto* buildId = reinterpret_cast<const unsigned char*>(buildIdAddr);
+ raw_build_id_size = nhdr->n_descsz;
+ std::memcpy(raw_build_id, buildId, raw_build_id_size);
+ break;
+ }
+ }
+ }
+ }
+
+ if (fprintf(heaptrack->s_data->out, "m %s ", fileName) < 0) {
+ heaptrack->writeError();
+ return 1;
+ }
+ if (raw_build_id_size == 0) {
+ if (fprintf(heaptrack->s_data->out, "- ") < 0) {
+ heaptrack->writeError();
+ return 1;
+ }
+ } else {
+ for (unsigned i = 0; i < raw_build_id_size; ++i) {
+ if (fprintf(heaptrack->s_data->out, "%02x", raw_build_id[i]) < 0) {
+ heaptrack->writeError();
+ return 1;
+ }
+ }
+ }
+ if (fprintf(heaptrack->s_data->out, " %zx", info->dlpi_addr) < 0) {
heaptrack->writeError();
return 1;
}