diff --git a/src/binary/elf.cpp b/src/binary/elf.cpp index 17c13cb..19a438f 100644 --- a/src/binary/elf.cpp +++ b/src/binary/elf.cpp @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include @@ -410,6 +412,25 @@ namespace detail { } return symbol_table; } + + Result, 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{detail::make_unique(std::move(obj))}; }); + } else { + std::mutex m; + std::unique_lock lock{m}; + // TODO: Re-evaluate storing the error + static std::unordered_map> 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(&obj); }); + } + } } } diff --git a/src/binary/elf.hpp b/src/binary/elf.hpp index 63af72d..ffe9d92 100644 --- a/src/binary/elf.hpp +++ b/src/binary/elf.hpp @@ -73,6 +73,8 @@ namespace detail { public: static NODISCARD Result open_elf(const std::string& object_path); + elf(elf&&) = default; + public: Result get_module_image_base(); private: @@ -117,6 +119,8 @@ namespace detail { template Result, internal_error> get_symtab_impl(bool dynamic); }; + + NODISCARD Result, internal_error> open_elf_cached(const std::string& object_path); } } diff --git a/src/binary/mach-o.cpp b/src/binary/mach-o.cpp index 90823c6..fdf73a5 100644 --- a/src/binary/mach-o.cpp +++ b/src/binary/mach-o.cpp @@ -669,6 +669,27 @@ namespace detail { return is_fat_magic(magic.unwrap_value()); } } + + Result, 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{detail::make_unique(std::move(obj))}; + }); + } else { + std::mutex m; + std::unique_lock lock{m}; + // TODO: Re-evaluate storing the error + static std::unordered_map> 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(&obj); }); + } + } } } diff --git a/src/binary/mach-o.hpp b/src/binary/mach-o.hpp index 506756e..fdf0df4 100644 --- a/src/binary/mach-o.hpp +++ b/src/binary/mach-o.hpp @@ -137,6 +137,8 @@ namespace detail { }; Result macho_is_fat(const std::string& object_path); + + NODISCARD Result, internal_error> open_mach_o_cached(const std::string& object_path); } } diff --git a/src/binary/module_base.cpp b/src/binary/module_base.cpp index b571833..2e6f054 100644 --- a/src/binary/module_base.cpp +++ b/src/binary/module_base.cpp @@ -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(); } diff --git a/src/symbols/dwarf/debug_map_resolver.cpp b/src/symbols/dwarf/debug_map_resolver.cpp index 690a511..a340335 100644 --- a/src/symbols/dwarf/debug_map_resolver.cpp +++ b/src/symbols/dwarf/debug_map_resolver.cpp @@ -46,11 +46,11 @@ namespace libdwarf { // the path doesn't exist std::unordered_map 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; diff --git a/src/symbols/dwarf/dwarf_resolver.cpp b/src/symbols/dwarf/dwarf_resolver.cpp index 00dfad8..f62e460 100644 --- a/src/symbols/dwarf/dwarf_resolver.cpp +++ b/src/symbols/dwarf/dwarf_resolver.cpp @@ -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 diff --git a/src/symbols/symbols_with_libdwarf.cpp b/src/symbols/symbols_with_libdwarf.cpp index abd54cf..5687eac 100644 --- a/src/symbols/symbols_with_libdwarf.cpp +++ b/src/symbols/symbols_with_libdwarf.cpp @@ -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 } diff --git a/src/utils/result.hpp b/src/utils/result.hpp index 2bbd879..fc807dc 100644 --- a/src/utils/result.hpp +++ b/src/utils/result.hpp @@ -127,6 +127,24 @@ namespace detail { return has_value() ? static_cast(std::move(value_)) : static_cast(std::forward(default_value)); } + template + NODISCARD auto transform(F&& f) & -> Result())), E> { + if(has_value()) { + return f(unwrap_value()); + } else { + return unwrap_error(); + } + } + + template + NODISCARD auto transform(F&& f) && -> Result())), 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()); diff --git a/src/utils/utils.hpp b/src/utils/utils.hpp index 4bfa695..55c8c7b 100644 --- a/src/utils/utils.hpp +++ b/src/utils/utils.hpp @@ -279,6 +279,11 @@ namespace detail { using file_wrapper = raii_wrapper; + template + auto make_unique(Args&&... args) -> typename std::enable_if::value, std::unique_ptr>::type { + return std::unique_ptr(new T(std::forward(args)...)); + } + template class maybe_owned { std::unique_ptr owned; @@ -289,6 +294,9 @@ namespace detail { T* operator->() { return ptr; } + T& operator*() { + return *ptr; + } }; } }