mirror of
https://github.com/pocoproject/poco.git
synced 2025-12-18 11:56:11 +01:00
96 lines
3.5 KiB
C++
96 lines
3.5 KiB
C++
#include "binary/module_base.hpp"
|
|
|
|
#include "utils/common.hpp"
|
|
#include "utils/utils.hpp"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <mutex>
|
|
#include <unordered_map>
|
|
|
|
#if IS_LINUX || IS_APPLE || IS_FREEBSD
|
|
#include <unistd.h>
|
|
#include <dlfcn.h>
|
|
#if IS_APPLE
|
|
#include "binary/mach-o.hpp"
|
|
#else
|
|
#include "binary/elf.hpp"
|
|
#endif
|
|
#elif IS_WINDOWS
|
|
#include <windows.h>
|
|
#include "binary/pe.hpp"
|
|
#endif
|
|
|
|
namespace cpptrace {
|
|
namespace detail {
|
|
#if IS_LINUX || IS_FREEBSD
|
|
Result<std::uintptr_t, internal_error> get_module_image_base(const std::string& object_path) {
|
|
static std::mutex mutex;
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
static std::unordered_map<std::string, std::uintptr_t> 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<std::uintptr_t, internal_error> 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<std::mutex> lock(mutex);
|
|
static std::unordered_map<std::string, std::uintptr_t> 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;
|
|
}
|
|
}
|
|
#else // Windows
|
|
Result<std::uintptr_t, internal_error> get_module_image_base(const std::string& object_path) {
|
|
static std::mutex mutex;
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
static std::unordered_map<std::string, std::uintptr_t> 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
|
|
}
|
|
}
|