Cache elf and mach-o file objects
This commit is contained in:
parent
69875cde19
commit
daed105fef
@ -7,7 +7,9 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
@ -410,6 +412,25 @@ namespace detail {
|
||||
}
|
||||
return symbol_table;
|
||||
}
|
||||
|
||||
Result<maybe_owned<elf>, internal_error> open_elf_cached(const std::string& object_path) {
|
||||
if(get_cache_mode() == cache_mode::prioritize_memory) {
|
||||
return elf::open_elf(object_path)
|
||||
.transform([](elf&& obj) { return maybe_owned<elf>{detail::make_unique<elf>(std::move(obj))}; });
|
||||
} else {
|
||||
std::mutex m;
|
||||
std::unique_lock<std::mutex> lock{m};
|
||||
// TODO: Re-evaluate storing the error
|
||||
static std::unordered_map<std::string, Result<elf, internal_error>> cache;
|
||||
auto it = cache.find(object_path);
|
||||
if(it == cache.end()) {
|
||||
auto res = cache.insert({ object_path, elf::open_elf(object_path) });
|
||||
VERIFY(res.second);
|
||||
it = res.first;
|
||||
}
|
||||
return it->second.transform([](elf& obj) { return maybe_owned<elf>(&obj); });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -73,6 +73,8 @@ namespace detail {
|
||||
public:
|
||||
static NODISCARD Result<elf, internal_error> open_elf(const std::string& object_path);
|
||||
|
||||
elf(elf&&) = default;
|
||||
|
||||
public:
|
||||
Result<std::uintptr_t, internal_error> get_module_image_base();
|
||||
private:
|
||||
@ -117,6 +119,8 @@ namespace detail {
|
||||
template<std::size_t Bits>
|
||||
Result<optional<symtab_info>, internal_error> get_symtab_impl(bool dynamic);
|
||||
};
|
||||
|
||||
NODISCARD Result<maybe_owned<elf>, internal_error> open_elf_cached(const std::string& object_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -669,6 +669,27 @@ namespace detail {
|
||||
return is_fat_magic(magic.unwrap_value());
|
||||
}
|
||||
}
|
||||
|
||||
Result<maybe_owned<mach_o>, internal_error> open_mach_o_cached(const std::string& object_path) {
|
||||
if(get_cache_mode() == cache_mode::prioritize_memory) {
|
||||
return mach_o::open_mach_o(object_path)
|
||||
.transform([](mach_o&& obj) {
|
||||
return maybe_owned<mach_o>{detail::make_unique<mach_o>(std::move(obj))};
|
||||
});
|
||||
} else {
|
||||
std::mutex m;
|
||||
std::unique_lock<std::mutex> lock{m};
|
||||
// TODO: Re-evaluate storing the error
|
||||
static std::unordered_map<std::string, Result<mach_o, internal_error>> cache;
|
||||
auto it = cache.find(object_path);
|
||||
if(it == cache.end()) {
|
||||
auto res = cache.insert({ object_path, mach_o::open_mach_o(object_path) });
|
||||
VERIFY(res.second);
|
||||
it = res.first;
|
||||
}
|
||||
return it->second.transform([](mach_o& obj) { return maybe_owned<mach_o>(&obj); });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -137,6 +137,8 @@ namespace detail {
|
||||
};
|
||||
|
||||
Result<bool, internal_error> macho_is_fat(const std::string& object_path);
|
||||
|
||||
NODISCARD Result<maybe_owned<mach_o>, internal_error> open_mach_o_cached(const std::string& object_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,12 +30,12 @@ namespace detail {
|
||||
if(it == cache.end()) {
|
||||
// arguably it'd be better to release the lock while computing this, but also arguably it's good to not
|
||||
// have two threads try to do the same computation
|
||||
auto obj = elf::open_elf(object_path);
|
||||
auto elf_object = open_elf_cached(object_path);
|
||||
// TODO: Cache the error
|
||||
if(!obj) {
|
||||
return obj.unwrap_error();
|
||||
if(!elf_object) {
|
||||
return elf_object.unwrap_error();
|
||||
}
|
||||
auto base = obj.unwrap_value().get_module_image_base();
|
||||
auto base = elf_object.unwrap_value()->get_module_image_base();
|
||||
if(base.is_error()) {
|
||||
return std::move(base).unwrap_error();
|
||||
}
|
||||
@ -57,12 +57,12 @@ namespace detail {
|
||||
if(it == cache.end()) {
|
||||
// arguably it'd be better to release the lock while computing this, but also arguably it's good to not
|
||||
// have two threads try to do the same computation
|
||||
auto obj = mach_o::open_mach_o(object_path);
|
||||
auto mach_o_object = open_mach_o_cached(object_path);
|
||||
// TODO: Cache the error
|
||||
if(!obj) {
|
||||
return obj.unwrap_error();
|
||||
if(!mach_o_object) {
|
||||
return mach_o_object.unwrap_error();
|
||||
}
|
||||
auto base = obj.unwrap_value().get_text_vmaddr();
|
||||
auto base = mach_o_object.unwrap_value()->get_text_vmaddr();
|
||||
if(!base) {
|
||||
return std::move(base).unwrap_error();
|
||||
}
|
||||
|
||||
@ -46,11 +46,11 @@ namespace libdwarf {
|
||||
// the path doesn't exist
|
||||
std::unordered_map<std::string, uint64_t> symbols;
|
||||
this->symbols = symbols;
|
||||
auto obj = mach_o::open_mach_o(object_path);
|
||||
if(!obj) {
|
||||
auto mach_o_object = open_mach_o_cached(object_path);
|
||||
if(!mach_o_object) {
|
||||
return this->symbols.unwrap();
|
||||
}
|
||||
const auto& symbol_table = obj.unwrap_value().symbol_table();
|
||||
const auto& symbol_table = mach_o_object.unwrap_value()->symbol_table();
|
||||
if(!symbol_table) {
|
||||
return this->symbols.unwrap();
|
||||
}
|
||||
@ -110,11 +110,11 @@ namespace libdwarf {
|
||||
debug_map_resolver(const std::string& source_object_path) {
|
||||
// load mach-o
|
||||
// TODO: Cache somehow?
|
||||
auto obj = mach_o::open_mach_o(source_object_path);
|
||||
if(!obj) {
|
||||
auto mach_o_object = open_mach_o_cached(source_object_path);
|
||||
if(!mach_o_object) {
|
||||
return;
|
||||
}
|
||||
mach_o& source_mach = obj.unwrap_value();
|
||||
mach_o& source_mach = *mach_o_object.unwrap_value();
|
||||
auto source_debug_map = source_mach.get_debug_map();
|
||||
if(!source_debug_map) {
|
||||
return;
|
||||
|
||||
@ -127,12 +127,12 @@ namespace libdwarf {
|
||||
if(result.is_error()) {
|
||||
result.drop_error();
|
||||
} else if(result.unwrap_value()) {
|
||||
auto obj = mach_o::open_mach_o(object_path);
|
||||
if(!obj) {
|
||||
auto mach_o_object = open_mach_o_cached(object_path);
|
||||
if(!mach_o_object) {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
universal_number = obj.unwrap_value().get_fat_index();
|
||||
universal_number = mach_o_object.unwrap_value()->get_fat_index();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -96,9 +96,9 @@ namespace libdwarf {
|
||||
const auto& object_name = group.first;
|
||||
// TODO PERF: Potentially a duplicate open and parse with module base stuff (and debug map resolver)
|
||||
#if IS_LINUX
|
||||
auto object = elf::open_elf(object_name);
|
||||
auto object = open_elf_cached(object_name);
|
||||
#elif IS_APPLE
|
||||
auto object = mach_o::open_mach_o(object_name);
|
||||
auto object = open_mach_o_cached(object_name);
|
||||
#endif
|
||||
auto resolver = get_resolver(object_name);
|
||||
for(const auto& entry : group.second) {
|
||||
@ -116,7 +116,9 @@ namespace libdwarf {
|
||||
}
|
||||
#if IS_LINUX || IS_APPLE
|
||||
if(frame.frame.symbol.empty() && object.has_value()) {
|
||||
frame.frame.symbol = object.unwrap_value().lookup_symbol(dlframe.object_address).value_or("");
|
||||
frame.frame.symbol = object
|
||||
.unwrap_value()
|
||||
->lookup_symbol(dlframe.object_address).value_or("");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -127,6 +127,24 @@ namespace detail {
|
||||
return has_value() ? static_cast<T>(std::move(value_)) : static_cast<T>(std::forward<U>(default_value));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
NODISCARD auto transform(F&& f) & -> Result<decltype(f(std::declval<T&>())), E> {
|
||||
if(has_value()) {
|
||||
return f(unwrap_value());
|
||||
} else {
|
||||
return unwrap_error();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
NODISCARD auto transform(F&& f) && -> Result<decltype(f(std::declval<T&&>())), E> {
|
||||
if(has_value()) {
|
||||
return f(std::move(unwrap_value()));
|
||||
} else {
|
||||
return unwrap_error();
|
||||
}
|
||||
}
|
||||
|
||||
void drop_error() const {
|
||||
if(is_error()) {
|
||||
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
||||
|
||||
@ -279,6 +279,11 @@ namespace detail {
|
||||
|
||||
using file_wrapper = raii_wrapper<std::FILE*, void(*)(std::FILE*)>;
|
||||
|
||||
template<class T, class... Args>
|
||||
auto make_unique(Args&&... args) -> typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class maybe_owned {
|
||||
std::unique_ptr<T> owned;
|
||||
@ -289,6 +294,9 @@ namespace detail {
|
||||
T* operator->() {
|
||||
return ptr;
|
||||
}
|
||||
T& operator*() {
|
||||
return *ptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user