Commit f335efc8 authored by Milian Wolff's avatar Milian Wolff
Browse files

WIP: Include the build-id in the heaptrack output and use it to find libs

parent 44fe3887
......@@ -14,11 +14,11 @@ if(NOT CMAKE_BUILD_TYPE)
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)
set(HEAPTRACK_FILE_FORMAT_VERSION 1)
set(HEAPTRACK_FILE_FORMAT_VERSION 2)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
......
......@@ -65,6 +65,11 @@ string demangle(const char* function)
return ret;
}
bool fileIsReadable(const string& path)
{
return access(path.c_str(), R_OK) == 0;
}
struct AddressInformation
{
string function;
......@@ -269,18 +274,25 @@ struct AccumulatedTraceData
// 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
......@@ -292,7 +304,9 @@ struct AccumulatedTraceData
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
{
......@@ -367,17 +381,22 @@ int main(int /*argc*/, char** /*argv*/)
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)) {
......
......@@ -25,6 +25,7 @@
#include "libheaptrack.h"
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
......@@ -396,7 +397,53 @@ private:
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;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment