diff --git a/src/platform/common.hpp b/src/platform/common.hpp index a23a93a..61324cc 100644 --- a/src/platform/common.hpp +++ b/src/platform/common.hpp @@ -250,6 +250,7 @@ static_assert(n_digits(10) == 2, "n_digits utility producing the wrong result"); static_assert(n_digits(11) == 2, "n_digits utility producing the wrong result"); static_assert(n_digits(1024) == 4, "n_digits utility producing the wrong result"); +// TODO: Re-evaluate use of off_t template::value, int>::type = 0> T load_bytes(FILE* obj_file, off_t offset) { T object; diff --git a/src/platform/elf.hpp b/src/platform/elf.hpp new file mode 100644 index 0000000..7d78a97 --- /dev/null +++ b/src/platform/elf.hpp @@ -0,0 +1,87 @@ +#ifndef ELF_HPP +#define ELF_HPP + +#include "common.hpp" + +#if IS_LINUX +#include +#include +#include +#include + +#include + +template::value, int>::type = 0> +T elf_byteswap_if_needed(T value, bool elf_is_little) { + if(is_little_endian() == elf_is_little) { + return value; + } else { + return byteswap(value); + } +} + +// TODO: Re-evaluate use of off_t +// I think we can rely on PT_PHDR https://stackoverflow.com/q/61568612/15675011... +static uintptr_t elf_get_module_image_base_from_program_table( + FILE* file, + bool is_64, + bool is_little_endian, + off_t e_phoff, + off_t e_phentsize, + int e_phnum +) { + for(int i = 0; i < e_phnum; i++) { + if(is_64) { + Elf64_Phdr program_header = load_bytes(file, e_phoff + e_phentsize * i); + if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) { + return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian) + - elf_byteswap_if_needed(program_header.p_offset, is_little_endian); + } + } else { + Elf32_Phdr program_header = load_bytes(file, e_phoff + e_phentsize * i); + if(elf_byteswap_if_needed(program_header.p_type, is_little_endian) == PT_PHDR) { + return elf_byteswap_if_needed(program_header.p_vaddr, is_little_endian) + - elf_byteswap_if_needed(program_header.p_offset, is_little_endian); + } + } + } + return 0; +} + +static uintptr_t elf_get_module_image_base(const std::string& obj_path) { + FILE* file = fopen(obj_path.c_str(), "rb"); + // Initial checks/metadata + auto magic = load_bytes>(file, 0); + internal_verify(magic == (std::array{0x7F, 'E', 'L', 'F'})); + bool is_64 = load_bytes(file, 4) == 2; + bool is_little_endian = load_bytes(file, 5) == 1; + internal_verify(load_bytes(file, 6) == 1, "Unexpected ELF version"); + // + if(is_64) { + Elf64_Ehdr file_header = load_bytes(file, 0); + internal_verify(file_header.e_ehsize == sizeof(Elf64_Ehdr)); + return elf_get_module_image_base_from_program_table( + file, + is_64, + is_little_endian, + elf_byteswap_if_needed(file_header.e_phoff, is_little_endian), + elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian), + elf_byteswap_if_needed(file_header.e_phnum, is_little_endian) + ); + } else { + Elf32_Ehdr file_header = load_bytes(file, 0); + internal_verify(file_header.e_ehsize == sizeof(Elf32_Ehdr)); + return elf_get_module_image_base_from_program_table( + file, + is_64, + is_little_endian, + elf_byteswap_if_needed(file_header.e_phoff, is_little_endian), + elf_byteswap_if_needed(file_header.e_phentsize, is_little_endian), + elf_byteswap_if_needed(file_header.e_phnum, is_little_endian) + ); + } +} + +#endif + +#endif diff --git a/src/platform/mach-o.hpp b/src/platform/mach-o.hpp index fc46636..8877d74 100644 --- a/src/platform/mach-o.hpp +++ b/src/platform/mach-o.hpp @@ -1,13 +1,13 @@ #ifndef MACHO_HPP #define MACHO_HPP +#include "common.hpp" + #if IS_APPLE #include #include #include -#include "common.hpp" - #include #include #include diff --git a/src/platform/pe.hpp b/src/platform/pe.hpp index 0f16784..d9e3e08 100644 --- a/src/platform/pe.hpp +++ b/src/platform/pe.hpp @@ -1,15 +1,15 @@ #ifndef PE_HPP #define PE_HPP +#include "common.hpp" + +#if IS_WINDOWS #include #include #include #include #include -#include "common.hpp" - -#if IS_WINDOWS #include template::value, int>::type = 0> diff --git a/src/symbols/symbols_with_addr2line.cpp b/src/symbols/symbols_with_addr2line.cpp index c40f283..9911aee 100644 --- a/src/symbols/symbols_with_addr2line.cpp +++ b/src/symbols/symbols_with_addr2line.cpp @@ -21,6 +21,8 @@ #include #if IS_APPLE #include "../platform/mach-o.hpp" + #else + #include "../platform/elf.hpp" #endif #elif IS_WINDOWS #include "../platform/pe.hpp" @@ -166,8 +168,7 @@ namespace cpptrace { #if !IS_APPLE uintptr_t get_module_image_base(const dlframe &entry) { - (void)entry; - return 0; + return elf_get_module_image_base(entry.obj_path); } #else uintptr_t get_module_image_base(const dlframe &entry) {