#include "binary/module_base.hpp" #include "platform/platform.hpp" #include "utils/utils.hpp" #include #include #include #if IS_LINUX || IS_APPLE #include #include #if IS_APPLE #include "binary/mach-o.hpp" #else #include "binary/elf.hpp" #endif #elif IS_WINDOWS #include "binary/pe.hpp" #endif namespace cpptrace { namespace detail { #if IS_LINUX Result get_module_image_base(const std::string& object_path) { static std::mutex mutex; std::lock_guard lock(mutex); static std::unordered_map cache; auto it = cache.find(object_path); 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 base = elf_get_module_image_base(object_path); // TODO: Cache the error if(base.is_error()) { return std::move(base).unwrap_error(); } cache.insert(it, {object_path, base.unwrap_value()}); return base; } else { return it->second; } } #elif IS_APPLE Result get_module_image_base(const std::string& object_path) { // We have to parse the Mach-O to find the offset of the text section..... // I don't know how addresses are handled if there is more than one __TEXT load command. I'm assuming for // now that there is only one, and I'm using only the first section entry within that load command. static std::mutex mutex; std::lock_guard lock(mutex); static std::unordered_map cache; auto it = cache.find(object_path); 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); // TODO: Cache the error if(!obj) { return obj.unwrap_error(); } auto base = obj.unwrap_value().get_text_vmaddr(); if(!base) { return std::move(base).unwrap_error(); } cache.insert(it, {object_path, base.unwrap_value()}); return base; } else { return it->second; } } #elif IS_WINDOWS Result get_module_image_base(const std::string& object_path) { static std::mutex mutex; std::lock_guard lock(mutex); static std::unordered_map cache; auto it = cache.find(object_path); 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 base = pe_get_module_image_base(object_path); // TODO: Cache the error if(!base) { return std::move(base).unwrap_error(); } cache.insert(it, {object_path, base.unwrap_value()}); return base; } else { return it->second; } } #endif } }