mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-09-19 19:19:05 +01:00
Faster locateSymbol by re-using dwfl across calls
This commit is contained in:
parent
4a64fc5c9c
commit
c0bfe87342
11
src/Common.h
11
src/Common.h
@ -105,3 +105,14 @@ struct TypeHierarchy {
|
|||||||
std::set<struct drgn_type*> thriftIssetStructTypes;
|
std::set<struct drgn_type*> thriftIssetStructTypes;
|
||||||
std::map<struct drgn_type*, std::vector<struct drgn_type*>> descendantClasses;
|
std::map<struct drgn_type*, std::vector<struct drgn_type*>> descendantClasses;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper for std::variant and std::visit
|
||||||
|
// https://en.cppreference.com/w/cpp/utility/variant/visit
|
||||||
|
template <class... Ts>
|
||||||
|
struct visitor : Ts... {
|
||||||
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Type deduction for the helper above
|
||||||
|
template <class... Ts>
|
||||||
|
visitor(Ts...) -> visitor<Ts...>;
|
||||||
|
@ -85,16 +85,28 @@ static bool isExecutableAddr(
|
|||||||
return it != end(exeAddrs) && addr >= it->first;
|
return it != end(exeAddrs) && addr >= it->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolService::SymbolService(std::variant<pid_t, fs::path> newTarget) {
|
SymbolService::SymbolService(pid_t pid) : target{pid} {
|
||||||
target = std::move(newTarget);
|
// Update target processes memory map
|
||||||
|
LoadExecutableAddressRange(pid, executableAddrs);
|
||||||
|
if (!loadModules()) {
|
||||||
|
throw std::runtime_error("Failed to load modules for process " +
|
||||||
|
std::to_string(pid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (target.index() == 0) {
|
SymbolService::SymbolService(fs::path executablePath)
|
||||||
// Update target processes memory map
|
: target{std::move(executablePath)} {
|
||||||
LoadExecutableAddressRange(std::get<pid_t>(target), executableAddrs);
|
if (!loadModules()) {
|
||||||
|
throw std::runtime_error("Failed to load modules for executable " +
|
||||||
|
executablePath.string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SymbolService::~SymbolService() {
|
SymbolService::~SymbolService() {
|
||||||
|
if (dwfl != nullptr) {
|
||||||
|
dwfl_end(dwfl);
|
||||||
|
}
|
||||||
|
|
||||||
if (prog != nullptr) {
|
if (prog != nullptr) {
|
||||||
drgn_program_destroy(prog);
|
drgn_program_destroy(prog);
|
||||||
}
|
}
|
||||||
@ -200,14 +212,42 @@ static int moduleCallback(Dwfl_Module* mod,
|
|||||||
return DWARF_CB_OK;
|
return DWARF_CB_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* Load modules from a live process */
|
||||||
* Resolve a symbol to its location in the target ELF binary.
|
bool SymbolService::loadModulesFromPid(pid_t target) {
|
||||||
*
|
if (int err = dwfl_linux_proc_report(dwfl, target)) {
|
||||||
* @param[in] symName - symbol to resolve
|
LOG(ERROR) << "dwfl_linux_proc_report: " << dwfl_errmsg(err);
|
||||||
* @return - A std::optional with the symbol's information
|
return false;
|
||||||
*/
|
}
|
||||||
std::optional<SymbolInfo> SymbolService::locateSymbol(
|
|
||||||
const std::string& symName, bool demangle) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load modules from an ELF binary */
|
||||||
|
bool SymbolService::loadModulesFromPath(const fs::path& target) {
|
||||||
|
auto* mod = dwfl_report_offline(dwfl, target.c_str(), target.c_str(), -1);
|
||||||
|
if (mod == nullptr) {
|
||||||
|
LOG(ERROR) << "dwfl_report_offline: " << dwfl_errmsg(dwfl_errno());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dwarf_Addr start = 0;
|
||||||
|
Dwarf_Addr end = 0;
|
||||||
|
if (dwfl_module_info(mod, nullptr, &start, &end, nullptr, nullptr, nullptr,
|
||||||
|
nullptr) == nullptr) {
|
||||||
|
LOG(ERROR) << "dwfl_module_info: " << dwfl_errmsg(dwfl_errno());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VLOG(1) << "Module info for " << target << ": start= " << std::hex << start
|
||||||
|
<< ", end=" << end;
|
||||||
|
|
||||||
|
// Add module's boundary to executableAddrs
|
||||||
|
executableAddrs = {{start, end}};
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SymbolService::loadModules() {
|
||||||
static char* debuginfo_path;
|
static char* debuginfo_path;
|
||||||
static const Dwfl_Callbacks proc_callbacks{
|
static const Dwfl_Callbacks proc_callbacks{
|
||||||
.find_elf = dwfl_linux_proc_find_elf,
|
.find_elf = dwfl_linux_proc_find_elf,
|
||||||
@ -216,55 +256,42 @@ std::optional<SymbolInfo> SymbolService::locateSymbol(
|
|||||||
.debuginfo_path = &debuginfo_path,
|
.debuginfo_path = &debuginfo_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
Dwfl* dwfl = dwfl_begin(&proc_callbacks);
|
dwfl = dwfl_begin(&proc_callbacks);
|
||||||
if (dwfl == nullptr) {
|
if (dwfl == nullptr) {
|
||||||
LOG(ERROR) << "dwfl_begin: " << dwfl_errmsg(dwfl_errno());
|
LOG(ERROR) << "dwfl_begin: " << dwfl_errmsg(dwfl_errno());
|
||||||
return std::nullopt;
|
return false;
|
||||||
}
|
}
|
||||||
BOOST_SCOPE_EXIT_ALL(&) {
|
|
||||||
dwfl_end(dwfl);
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (target.index()) {
|
dwfl_report_begin(dwfl);
|
||||||
case 0: {
|
|
||||||
auto pid = std::get<pid_t>(target);
|
|
||||||
if (int err = dwfl_linux_proc_report(dwfl, pid)) {
|
|
||||||
LOG(ERROR) << "dwfl_linux_proc_report: " << dwfl_errmsg(err);
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
const auto& exe = std::get<fs::path>(target);
|
|
||||||
Dwfl_Module* mod =
|
|
||||||
dwfl_report_offline(dwfl, exe.c_str(), exe.c_str(), -1);
|
|
||||||
if (mod == nullptr) {
|
|
||||||
LOG(ERROR) << "dwfl_report_offline: " << dwfl_errmsg(dwfl_errno());
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dwarf_Addr start = 0;
|
bool ok = std::visit(
|
||||||
Dwarf_Addr end = 0;
|
visitor{[this](pid_t target) { return loadModulesFromPid(target); },
|
||||||
if (dwfl_module_info(mod, nullptr, &start, &end, nullptr, nullptr,
|
[this](const fs::path& target) {
|
||||||
nullptr, nullptr) == nullptr) {
|
return loadModulesFromPath(target);
|
||||||
LOG(ERROR) << "dwfl_module_info: " << dwfl_errmsg(dwfl_errno());
|
}},
|
||||||
return std::nullopt;
|
target);
|
||||||
}
|
|
||||||
|
|
||||||
VLOG(1) << "Module info for " << exe << ": start= " << std::hex << start
|
if (!ok) {
|
||||||
<< ", end=" << end;
|
// The loadModules* function above already logged the error message
|
||||||
|
return false;
|
||||||
// Add module's boundary to executableAddrs
|
|
||||||
executableAddrs = {{start, end}};
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwfl_report_end(dwfl, nullptr, nullptr) != 0) {
|
if (dwfl_report_end(dwfl, nullptr, nullptr) != 0) {
|
||||||
LOG(ERROR) << "dwfl_report_end: " << dwfl_errmsg(-1);
|
LOG(ERROR) << "dwfl_report_end: " << dwfl_errmsg(-1);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a symbol to its location in the target ELF binary.
|
||||||
|
*
|
||||||
|
* @param[in] symName - symbol to resolve
|
||||||
|
* @return - A std::optional with the symbol's information
|
||||||
|
*/
|
||||||
|
std::optional<SymbolInfo> SymbolService::locateSymbol(
|
||||||
|
const std::string& symName, bool demangle) {
|
||||||
ModParams m = {.symName = symName,
|
ModParams m = {.symName = symName,
|
||||||
.sym = {},
|
.sym = {},
|
||||||
.value = 0,
|
.value = 0,
|
||||||
@ -331,46 +358,6 @@ static int buildIDCallback(Dwfl_Module* mod,
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> SymbolService::locateBuildID() {
|
std::optional<std::string> SymbolService::locateBuildID() {
|
||||||
static char* debuginfoPath;
|
|
||||||
static const Dwfl_Callbacks procCallbacks = {
|
|
||||||
.find_elf = dwfl_linux_proc_find_elf,
|
|
||||||
.find_debuginfo = dwfl_standard_find_debuginfo,
|
|
||||||
.section_address = dwfl_offline_section_address,
|
|
||||||
.debuginfo_path = &debuginfoPath,
|
|
||||||
};
|
|
||||||
|
|
||||||
Dwfl* dwfl = dwfl_begin(&procCallbacks);
|
|
||||||
if (dwfl == nullptr) {
|
|
||||||
LOG(ERROR) << "dwfl_begin: " << dwfl_errmsg(dwfl_errno());
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_SCOPE_EXIT_ALL(&) {
|
|
||||||
dwfl_end(dwfl);
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (target.index()) {
|
|
||||||
case 0: {
|
|
||||||
auto pid = std::get<pid_t>(target);
|
|
||||||
if (auto err = dwfl_linux_proc_report(dwfl, pid)) {
|
|
||||||
LOG(ERROR) << "dwfl_linux_proc_report: " << dwfl_errmsg(err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
const auto& exe = std::get<fs::path>(target);
|
|
||||||
if (dwfl_report_offline(dwfl, exe.c_str(), exe.c_str(), -1) == nullptr) {
|
|
||||||
LOG(ERROR) << "dwfl_report_offline: " << dwfl_errmsg(dwfl_errno());
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dwfl_report_end(dwfl, nullptr, nullptr) != 0) {
|
|
||||||
LOG(ERROR) << "dwfl_report_end: " << dwfl_errmsg(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::string> buildID;
|
std::optional<std::string> buildID;
|
||||||
dwfl_getmodules(dwfl, buildIDCallback, (void*)&buildID, 0);
|
dwfl_getmodules(dwfl, buildIDCallback, (void*)&buildID, 0);
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
struct Dwfl;
|
||||||
struct drgn_program;
|
struct drgn_program;
|
||||||
struct irequest;
|
struct irequest;
|
||||||
|
|
||||||
@ -38,7 +39,10 @@ struct SymbolInfo {
|
|||||||
|
|
||||||
class SymbolService {
|
class SymbolService {
|
||||||
public:
|
public:
|
||||||
SymbolService(std::variant<pid_t, fs::path>);
|
SymbolService(pid_t);
|
||||||
|
SymbolService(fs::path);
|
||||||
|
SymbolService(const SymbolService&) = delete;
|
||||||
|
SymbolService& operator=(const SymbolService&) = delete;
|
||||||
~SymbolService();
|
~SymbolService();
|
||||||
|
|
||||||
struct drgn_program* getDrgnProgram();
|
struct drgn_program* getDrgnProgram();
|
||||||
@ -60,9 +64,14 @@ class SymbolService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::variant<pid_t, fs::path> target{0};
|
std::variant<pid_t, fs::path> target;
|
||||||
|
struct Dwfl* dwfl{nullptr};
|
||||||
struct drgn_program* prog{nullptr};
|
struct drgn_program* prog{nullptr};
|
||||||
|
|
||||||
|
bool loadModules();
|
||||||
|
bool loadModulesFromPid(pid_t);
|
||||||
|
bool loadModulesFromPath(const fs::path&);
|
||||||
|
|
||||||
std::vector<std::pair<uint64_t, uint64_t>> executableAddrs{};
|
std::vector<std::pair<uint64_t, uint64_t>> executableAddrs{};
|
||||||
bool hardDisableDrgn = false;
|
bool hardDisableDrgn = false;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user