diff --git a/src/binary/elf.cpp b/src/binary/elf.cpp index 336a59d..f97bf03 100644 --- a/src/binary/elf.cpp +++ b/src/binary/elf.cpp @@ -54,38 +54,40 @@ namespace detail { Result elf::get_module_image_base() { // get image base - auto impl = [this]() -> Result { - static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument"); - using PHeader = typename std::conditional::type; - auto header = get_header_info(); - if(header.is_error()) { - return std::move(header).unwrap_error(); - } - const auto& header_info = header.unwrap_value(); - // PT_PHDR will occur at most once - // Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011 - // It should occur at the beginning but may as well loop just in case - for(unsigned i = 0; i < header_info.e_phnum; i++) { - auto loaded_ph = load_bytes(file, header_info.e_phoff + header_info.e_phentsize * i); - if(loaded_ph.is_error()) { - return std::move(loaded_ph).unwrap_error(); - } - const PHeader& program_header = loaded_ph.unwrap_value(); - if(byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) { - return byteswap_if_needed(program_header.p_vaddr, is_little_endian) - - byteswap_if_needed(program_header.p_offset, is_little_endian); - } - } - // Apparently some objects like shared objects can end up missing this header. 0 as a base seems correct. - return 0; - }; if(is_64) { - return impl.operator()<64>(); + return get_module_image_base_impl<64>(); } else { - return impl.operator()<32>(); + return get_module_image_base_impl<32>(); } } + template + Result elf::get_module_image_base_impl() { + static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument"); + using PHeader = typename std::conditional::type; + auto header = get_header_info(); + if(header.is_error()) { + return std::move(header).unwrap_error(); + } + const auto& header_info = header.unwrap_value(); + // PT_PHDR will occur at most once + // Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011 + // It should occur at the beginning but may as well loop just in case + for(unsigned i = 0; i < header_info.e_phnum; i++) { + auto loaded_ph = load_bytes(file, header_info.e_phoff + header_info.e_phentsize * i); + if(loaded_ph.is_error()) { + return std::move(loaded_ph).unwrap_error(); + } + const PHeader& program_header = loaded_ph.unwrap_value(); + if(byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) { + return byteswap_if_needed(program_header.p_vaddr, is_little_endian) - + byteswap_if_needed(program_header.p_offset, is_little_endian); + } + } + // Apparently some objects like shared objects can end up missing this header. 0 as a base seems correct. + return 0; + } + template::value, int>::type> T elf::byteswap_if_needed(T value, bool elf_is_little) { if(cpptrace::detail::is_little_endian() == elf_is_little) { @@ -99,33 +101,35 @@ namespace detail { if(header) { return header.unwrap(); } - auto impl = [this]() -> Result { - static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument"); - using Header = typename std::conditional::type; - auto loaded_header = load_bytes
(file, 0); - if(loaded_header.is_error()) { - return std::move(loaded_header).unwrap_error(); - } - const Header& file_header = loaded_header.unwrap_value(); - if(file_header.e_ehsize != sizeof(Header)) { - return internal_error("ELF file header size mismatch" + object_path); - } - header_info info; - info.e_phoff = file_header.e_phoff; - info.e_phnum = file_header.e_phnum; - info.e_phentsize = file_header.e_phentsize; - info.e_shoff = file_header.e_shoff; - info.e_shnum = file_header.e_shnum; - info.e_shentsize = file_header.e_shentsize; - header = info; - return header.unwrap(); - }; if(is_64) { - return impl.operator()<64>(); + return get_header_info_impl<64>(); } else { - return impl.operator()<32>(); + return get_header_info_impl<32>(); } } + + template + Result elf::get_header_info_impl() { + static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument"); + using Header = typename std::conditional::type; + auto loaded_header = load_bytes
(file, 0); + if(loaded_header.is_error()) { + return std::move(loaded_header).unwrap_error(); + } + const Header& file_header = loaded_header.unwrap_value(); + if(file_header.e_ehsize != sizeof(Header)) { + return internal_error("ELF file header size mismatch" + object_path); + } + header_info info; + info.e_phoff = file_header.e_phoff; + info.e_phnum = file_header.e_phnum; + info.e_phentsize = file_header.e_phentsize; + info.e_shoff = file_header.e_shoff; + info.e_shnum = file_header.e_shnum; + info.e_shentsize = file_header.e_shentsize; + header = info; + return header.unwrap(); + } } } diff --git a/src/binary/elf.hpp b/src/binary/elf.hpp index b7d40ac..0f590d4 100644 --- a/src/binary/elf.hpp +++ b/src/binary/elf.hpp @@ -32,13 +32,19 @@ namespace detail { public: static NODISCARD Result open_elf(const std::string& object_path); + public: Result get_module_image_base(); + private: + template + Result get_module_image_base_impl(); private: template::value, int>::type = 0> T byteswap_if_needed(T value, bool elf_is_little); Result get_header_info(); + template + Result get_header_info_impl(); }; } }