Some refactoring, bring object_frame in line with safe_object_frame. Also renamed address_relative_to_object_base_in_memory.

This commit is contained in:
Jeremy 2023-11-20 23:13:21 -06:00
parent 2a4a8066d3
commit 9113cc5ffc
No known key found for this signature in database
GPG Key ID: B4C8300FEC395042
12 changed files with 109 additions and 109 deletions

View File

@ -185,9 +185,9 @@ is resolved), and the path to the object the instruction pointer is located in.
```cpp ```cpp
namespace cpptrace { namespace cpptrace {
struct object_frame { struct object_frame {
std::string obj_path; std::string object_path;
frame_ptr raw_address; frame_ptr raw_address;
frame_ptr obj_address; frame_ptr object_address;
}; };
struct object_trace { struct object_trace {
@ -410,7 +410,7 @@ namespace cpptrace {
std::size_t safe_generate_raw_trace(frame_ptr* buffer, std::size_t size, std::size_t skip, std::size_t max_depth); std::size_t safe_generate_raw_trace(frame_ptr* buffer, std::size_t size, std::size_t skip, std::size_t max_depth);
struct safe_object_frame { struct safe_object_frame {
frame_ptr raw_address; frame_ptr raw_address;
frame_ptr address_relative_to_object_base_in_memory; frame_ptr address_relative_to_object_start; // object base address must yet be added
char object_path[CPPTRACE_PATH_MAX + 1]; char object_path[CPPTRACE_PATH_MAX + 1];
object_frame resolve() const; // To be called outside a signal handler. Not signal safe. object_frame resolve() const; // To be called outside a signal handler. Not signal safe.
}; };

View File

@ -54,9 +54,9 @@ namespace cpptrace {
}; };
struct CPPTRACE_EXPORT object_frame { struct CPPTRACE_EXPORT object_frame {
std::string obj_path;
frame_ptr raw_address; frame_ptr raw_address;
frame_ptr obj_address; frame_ptr object_address;
std::string object_path;
}; };
struct CPPTRACE_EXPORT object_trace { struct CPPTRACE_EXPORT object_trace {
@ -195,7 +195,7 @@ namespace cpptrace {
); );
struct CPPTRACE_EXPORT safe_object_frame { struct CPPTRACE_EXPORT safe_object_frame {
frame_ptr raw_address; frame_ptr raw_address;
frame_ptr address_relative_to_object_base_in_memory; frame_ptr address_relative_to_object_start; // base must still be added
char object_path[CPPTRACE_PATH_MAX + 1]; char object_path[CPPTRACE_PATH_MAX + 1];
// To be called outside a signal handler. Not signal safe. // To be called outside a signal handler. Not signal safe.
object_frame resolve() const; object_frame resolve() const;

View File

@ -46,7 +46,7 @@ namespace cpptrace {
struct safe_object_frame { struct safe_object_frame {
frame_ptr raw_address; frame_ptr raw_address;
frame_ptr address_relative_to_object_base_in_memory; frame_ptr address_relative_to_object_start; // object base address must yet be added
char object_path[CPPTRACE_PATH_MAX + 1]; char object_path[CPPTRACE_PATH_MAX + 1];
object_frame resolve() const; // To be called outside a signal handler. Not signal safe. object_frame resolve() const; // To be called outside a signal handler. Not signal safe.
}; };

View File

@ -26,7 +26,7 @@ namespace detail {
template<std::size_t Bits> template<std::size_t Bits>
static std::uintptr_t elf_get_module_image_base_from_program_table( static std::uintptr_t elf_get_module_image_base_from_program_table(
const std::string& obj_path, const std::string& object_path,
std::FILE* file, std::FILE* file,
bool is_little_endian bool is_little_endian
) { ) {
@ -34,7 +34,7 @@ namespace detail {
using Header = typename std::conditional<Bits == 32, Elf32_Ehdr, Elf64_Ehdr>::type; using Header = typename std::conditional<Bits == 32, Elf32_Ehdr, Elf64_Ehdr>::type;
using PHeader = typename std::conditional<Bits == 32, Elf32_Phdr, Elf64_Phdr>::type; using PHeader = typename std::conditional<Bits == 32, Elf32_Phdr, Elf64_Phdr>::type;
Header file_header = load_bytes<Header>(file, 0); Header file_header = load_bytes<Header>(file, 0);
VERIFY(file_header.e_ehsize == sizeof(Header), "ELF file header size mismatch" + obj_path); VERIFY(file_header.e_ehsize == sizeof(Header), "ELF file header size mismatch" + object_path);
// PT_PHDR will occur at most once // PT_PHDR will occur at most once
// Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011 // Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011
// It should occur at the beginning but may as well loop just in case // It should occur at the beginning but may as well loop just in case
@ -49,22 +49,22 @@ namespace detail {
return 0; return 0;
} }
static std::uintptr_t elf_get_module_image_base(const std::string& obj_path) { static std::uintptr_t elf_get_module_image_base(const std::string& object_path) {
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter); auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
if(file == nullptr) { if(file == nullptr) {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + object_path);
} }
// Initial checks/metadata // Initial checks/metadata
auto magic = load_bytes<std::array<char, 4>>(file, 0); auto magic = load_bytes<std::array<char, 4>>(file, 0);
VERIFY(magic == (std::array<char, 4>{0x7F, 'E', 'L', 'F'}), "File is not ELF " + obj_path); VERIFY(magic == (std::array<char, 4>{0x7F, 'E', 'L', 'F'}), "File is not ELF " + object_path);
bool is_64 = load_bytes<std::uint8_t>(file, 4) == 2; bool is_64 = load_bytes<std::uint8_t>(file, 4) == 2;
bool is_little_endian = load_bytes<std::uint8_t>(file, 5) == 1; bool is_little_endian = load_bytes<std::uint8_t>(file, 5) == 1;
VERIFY(load_bytes<std::uint8_t>(file, 6) == 1, "Unexpected ELF endianness " + obj_path); VERIFY(load_bytes<std::uint8_t>(file, 6) == 1, "Unexpected ELF endianness " + object_path);
// get image base // get image base
if(is_64) { if(is_64) {
return elf_get_module_image_base_from_program_table<64>(obj_path, file, is_little_endian); return elf_get_module_image_base_from_program_table<64>(object_path, file, is_little_endian);
} else { } else {
return elf_get_module_image_base_from_program_table<32>(obj_path, file, is_little_endian); return elf_get_module_image_base_from_program_table<32>(object_path, file, is_little_endian);
} }
} }
} }

View File

@ -75,8 +75,8 @@ namespace detail {
template<std::size_t Bits> template<std::size_t Bits>
static optional<std::uintptr_t> macho_get_text_vmaddr_mach( static optional<std::uintptr_t> macho_get_text_vmaddr_mach(
std::FILE* obj_file, std::FILE* object_file,
const std::string& obj_path, const std::string& object_path,
off_t offset, off_t offset,
bool should_swap, bool should_swap,
bool allow_arch_mismatch bool allow_arch_mismatch
@ -87,7 +87,7 @@ namespace detail {
std::uint32_t ncmds; std::uint32_t ncmds;
off_t load_commands_offset = offset; off_t load_commands_offset = offset;
std::size_t header_size = sizeof(Mach_Header); std::size_t header_size = sizeof(Mach_Header);
Mach_Header header = load_bytes<Mach_Header>(obj_file, offset); Mach_Header header = load_bytes<Mach_Header>(object_file, offset);
if(should_swap) { if(should_swap) {
swap_mach_header(header); swap_mach_header(header);
} }
@ -107,7 +107,7 @@ namespace detail {
if(allow_arch_mismatch) { if(allow_arch_mismatch) {
return nullopt; return nullopt;
} else { } else {
PANIC("Mach-O file cpu type and subtype do not match current machine " + obj_path); PANIC("Mach-O file cpu type and subtype do not match current machine " + object_path);
} }
} }
ncmds = header.ncmds; ncmds = header.ncmds;
@ -115,12 +115,12 @@ namespace detail {
// iterate load commands // iterate load commands
off_t actual_offset = load_commands_offset; off_t actual_offset = load_commands_offset;
for(std::uint32_t i = 0; i < ncmds; i++) { for(std::uint32_t i = 0; i < ncmds; i++) {
load_command cmd = load_bytes<load_command>(obj_file, actual_offset); load_command cmd = load_bytes<load_command>(object_file, actual_offset);
if(should_swap) { if(should_swap) {
swap_load_command(&cmd, NX_UnknownByteOrder); swap_load_command(&cmd, NX_UnknownByteOrder);
} }
// TODO: This is a mistake? Need to check cmd.cmd == LC_SEGMENT_64 / cmd.cmd == LC_SEGMENT // TODO: This is a mistake? Need to check cmd.cmd == LC_SEGMENT_64 / cmd.cmd == LC_SEGMENT
Segment_Command segment = load_bytes<Segment_Command>(obj_file, actual_offset); Segment_Command segment = load_bytes<Segment_Command>(object_file, actual_offset);
if(should_swap) { if(should_swap) {
swap_segment_command(segment); swap_segment_command(segment);
} }
@ -135,38 +135,38 @@ namespace detail {
} }
static std::uintptr_t macho_get_text_vmaddr_fat( static std::uintptr_t macho_get_text_vmaddr_fat(
std::FILE* obj_file, std::FILE* object_file,
const std::string& obj_path, const std::string& object_path,
bool should_swap bool should_swap
) { ) {
std::size_t header_size = sizeof(fat_header); std::size_t header_size = sizeof(fat_header);
std::size_t arch_size = sizeof(fat_arch); std::size_t arch_size = sizeof(fat_arch);
fat_header header = load_bytes<fat_header>(obj_file, 0); fat_header header = load_bytes<fat_header>(object_file, 0);
if(should_swap) { if(should_swap) {
swap_fat_header(&header, NX_UnknownByteOrder); swap_fat_header(&header, NX_UnknownByteOrder);
} }
off_t arch_offset = (off_t)header_size; off_t arch_offset = (off_t)header_size;
optional<std::uintptr_t> text_vmaddr; optional<std::uintptr_t> text_vmaddr;
for(std::uint32_t i = 0; i < header.nfat_arch; i++) { for(std::uint32_t i = 0; i < header.nfat_arch; i++) {
fat_arch arch = load_bytes<fat_arch>(obj_file, arch_offset); fat_arch arch = load_bytes<fat_arch>(object_file, arch_offset);
if(should_swap) { if(should_swap) {
swap_fat_arch(&arch, 1, NX_UnknownByteOrder); swap_fat_arch(&arch, 1, NX_UnknownByteOrder);
} }
off_t mach_header_offset = (off_t)arch.offset; off_t mach_header_offset = (off_t)arch.offset;
arch_offset += arch_size; arch_offset += arch_size;
std::uint32_t magic = load_bytes<std::uint32_t>(obj_file, mach_header_offset); std::uint32_t magic = load_bytes<std::uint32_t>(object_file, mach_header_offset);
if(is_magic_64(magic)) { if(is_magic_64(magic)) {
text_vmaddr = macho_get_text_vmaddr_mach<64>( text_vmaddr = macho_get_text_vmaddr_mach<64>(
obj_file, object_file,
obj_path, object_path,
mach_header_offset, mach_header_offset,
should_swap_bytes(magic), should_swap_bytes(magic),
true true
); );
} else { } else {
text_vmaddr = macho_get_text_vmaddr_mach<32>( text_vmaddr = macho_get_text_vmaddr_mach<32>(
obj_file, object_file,
obj_path, object_path,
mach_header_offset, mach_header_offset,
should_swap_bytes(magic), should_swap_bytes(magic),
true true
@ -181,31 +181,31 @@ namespace detail {
return 0; return 0;
} }
static std::uintptr_t macho_get_text_vmaddr(const std::string& obj_path) { static std::uintptr_t macho_get_text_vmaddr(const std::string& object_path) {
//std::fprintf(stderr, "--%s--\n", obj_path.c_str()); //std::fprintf(stderr, "--%s--\n", object_path.c_str());
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter); auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
if(file == nullptr) { if(file == nullptr) {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + object_path);
} }
std::uint32_t magic = load_bytes<std::uint32_t>(file, 0); std::uint32_t magic = load_bytes<std::uint32_t>(file, 0);
VERIFY(is_mach_o(magic), "File is not Mach-O " + obj_path); VERIFY(is_mach_o(magic), "File is not Mach-O " + object_path);
bool is_64 = is_magic_64(magic); bool is_64 = is_magic_64(magic);
bool should_swap = should_swap_bytes(magic); bool should_swap = should_swap_bytes(magic);
if(magic == FAT_MAGIC || magic == FAT_CIGAM) { if(magic == FAT_MAGIC || magic == FAT_CIGAM) {
return macho_get_text_vmaddr_fat(file, obj_path, should_swap); return macho_get_text_vmaddr_fat(file, object_path, should_swap);
} else { } else {
if(is_64) { if(is_64) {
return macho_get_text_vmaddr_mach<64>(file, obj_path, 0, should_swap, false).unwrap(); return macho_get_text_vmaddr_mach<64>(file, object_path, 0, should_swap, false).unwrap();
} else { } else {
return macho_get_text_vmaddr_mach<32>(file, obj_path, 0, should_swap, false).unwrap(); return macho_get_text_vmaddr_mach<32>(file, object_path, 0, should_swap, false).unwrap();
} }
} }
} }
inline bool macho_is_fat(const std::string& obj_path) { inline bool macho_is_fat(const std::string& object_path) {
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter); auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
if(file == nullptr) { if(file == nullptr) {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + object_path);
} }
std::uint32_t magic = load_bytes<std::uint32_t>(file, 0); std::uint32_t magic = load_bytes<std::uint32_t>(file, 0);
return is_fat_magic(magic); return is_fat_magic(magic);
@ -213,10 +213,10 @@ namespace detail {
// returns index of the appropriate mach-o binary in the universal binary // returns index of the appropriate mach-o binary in the universal binary
// TODO: Code duplication with macho_get_text_vmaddr_fat // TODO: Code duplication with macho_get_text_vmaddr_fat
inline unsigned get_fat_macho_index(const std::string& obj_path) { inline unsigned get_fat_macho_index(const std::string& object_path) {
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter); auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
if(file == nullptr) { if(file == nullptr) {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + object_path);
} }
std::uint32_t magic = load_bytes<std::uint32_t>(file, 0); std::uint32_t magic = load_bytes<std::uint32_t>(file, 0);
VERIFY(is_fat_magic(magic)); VERIFY(is_fat_magic(magic));

View File

@ -26,35 +26,35 @@ namespace cpptrace {
namespace detail { namespace detail {
#if IS_LINUX || IS_APPLE #if IS_LINUX || IS_APPLE
#if !IS_APPLE #if !IS_APPLE
inline std::uintptr_t get_module_image_base(const std::string& obj_path) { inline std::uintptr_t get_module_image_base(const std::string& object_path) {
static std::mutex mutex; static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
static std::unordered_map<std::string, std::uintptr_t> cache; static std::unordered_map<std::string, std::uintptr_t> cache;
auto it = cache.find(obj_path); auto it = cache.find(object_path);
if(it == cache.end()) { if(it == cache.end()) {
// arguably it'd be better to release the lock while computing this, but also arguably it's good to not // 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 // have two threads try to do the same computation
auto base = elf_get_module_image_base(obj_path); auto base = elf_get_module_image_base(object_path);
cache.insert(it, {obj_path, base}); cache.insert(it, {object_path, base});
return base; return base;
} else { } else {
return it->second; return it->second;
} }
} }
#else #else
inline std::uintptr_t get_module_image_base(const std::string& obj_path) { inline std::uintptr_t get_module_image_base(const std::string& object_path) {
// We have to parse the Mach-O to find the offset of the text section..... // 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 // 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. // now that there is only one, and I'm using only the first section entry within that load command.
static std::mutex mutex; static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
static std::unordered_map<std::string, std::uintptr_t> cache; static std::unordered_map<std::string, std::uintptr_t> cache;
auto it = cache.find(obj_path); auto it = cache.find(object_path);
if(it == cache.end()) { if(it == cache.end()) {
// arguably it'd be better to release the lock while computing this, but also arguably it's good to not // 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 // have two threads try to do the same computation
auto base = macho_get_text_vmaddr(obj_path); auto base = macho_get_text_vmaddr(object_path);
cache.insert(it, {obj_path, base}); cache.insert(it, {object_path, base});
return base; return base;
} else { } else {
return it->second; return it->second;
@ -70,12 +70,12 @@ namespace detail {
Dl_info info; Dl_info info;
object_frame frame; object_frame frame;
frame.raw_address = addr; frame.raw_address = addr;
frame.obj_address = 0; frame.object_address = 0;
if(dladdr(reinterpret_cast<void*>(addr), &info)) { // thread safe if(dladdr(reinterpret_cast<void*>(addr), &info)) { // thread safe
// dli_sname and dli_saddr are only present with -rdynamic, sname will be included // dli_sname and dli_saddr are only present with -rdynamic, sname will be included
// but we don't really need dli_saddr // but we don't really need dli_saddr
frame.obj_path = info.dli_fname; frame.object_path = info.dli_fname;
frame.obj_address = addr frame.object_address = addr
- reinterpret_cast<std::uintptr_t>(info.dli_fbase) - reinterpret_cast<std::uintptr_t>(info.dli_fbase)
+ get_module_image_base(info.dli_fname); + get_module_image_base(info.dli_fname);
} }
@ -105,16 +105,16 @@ namespace detail {
} }
} }
inline std::uintptr_t get_module_image_base(const std::string& obj_path) { inline std::uintptr_t get_module_image_base(const std::string& object_path) {
static std::mutex mutex; static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
static std::unordered_map<std::string, std::uintptr_t> cache; static std::unordered_map<std::string, std::uintptr_t> cache;
auto it = cache.find(obj_path); auto it = cache.find(object_path);
if(it == cache.end()) { if(it == cache.end()) {
// arguably it'd be better to release the lock while computing this, but also arguably it's good to not // 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 // have two threads try to do the same computation
auto base = pe_get_module_image_base(obj_path); auto base = pe_get_module_image_base(object_path);
cache.insert(it, {obj_path, base}); cache.insert(it, {object_path, base});
return base; return base;
} else { } else {
return it->second; return it->second;
@ -129,7 +129,7 @@ namespace detail {
for(const frame_ptr addr : addrs) { for(const frame_ptr addr : addrs) {
object_frame frame; object_frame frame;
frame.raw_address = addr; frame.raw_address = addr;
frame.obj_address = 0; frame.object_address = 0;
HMODULE handle; HMODULE handle;
// Multithread safe as long as another thread doesn't come along and free the module // Multithread safe as long as another thread doesn't come along and free the module
if(GetModuleHandleExA( if(GetModuleHandleExA(
@ -137,10 +137,10 @@ namespace detail {
reinterpret_cast<const char*>(addr), reinterpret_cast<const char*>(addr),
&handle &handle
)) { )) {
frame.obj_path = get_module_name(handle); frame.object_path = get_module_name(handle);
frame.obj_address = addr frame.object_address = addr
- reinterpret_cast<std::uintptr_t>(handle) - reinterpret_cast<std::uintptr_t>(handle)
+ get_module_image_base(frame.obj_path); + get_module_image_base(frame.object_path);
} else { } else {
std::fprintf(stderr, "%s\n", std::system_error(GetLastError(), std::system_category()).what()); std::fprintf(stderr, "%s\n", std::system_error(GetLastError(), std::system_category()).what());
} }
@ -152,9 +152,9 @@ namespace detail {
inline object_frame resolve_safe_object_frame(const safe_object_frame& frame) { inline object_frame resolve_safe_object_frame(const safe_object_frame& frame) {
return { return {
frame.object_path,
frame.raw_address, frame.raw_address,
frame.address_relative_to_object_base_in_memory + get_module_image_base(frame.object_path) frame.address_relative_to_object_start + get_module_image_base(frame.object_path),
frame.object_path
}; };
} }
} }

View File

@ -26,22 +26,22 @@ namespace detail {
} }
} }
inline std::uintptr_t pe_get_module_image_base(const std::string& obj_path) { inline std::uintptr_t pe_get_module_image_base(const std::string& object_path) {
// https://drive.google.com/file/d/0B3_wGJkuWLytbnIxY1J5WUs4MEk/view?pli=1&resourcekey=0-n5zZ2UW39xVTH8ZSu6C2aQ // https://drive.google.com/file/d/0B3_wGJkuWLytbnIxY1J5WUs4MEk/view?pli=1&resourcekey=0-n5zZ2UW39xVTH8ZSu6C2aQ
// https://0xrick.github.io/win-internals/pe3/ // https://0xrick.github.io/win-internals/pe3/
// Endianness should always be little for dos and pe headers // Endianness should always be little for dos and pe headers
std::FILE* file_ptr; std::FILE* file_ptr;
errno_t ret = fopen_s(&file_ptr, obj_path.c_str(), "rb"); errno_t ret = fopen_s(&file_ptr, object_path.c_str(), "rb");
auto file = raii_wrap(std::move(file_ptr), file_deleter); auto file = raii_wrap(std::move(file_ptr), file_deleter);
if(ret != 0 || file == nullptr) { if(ret != 0 || file == nullptr) {
throw file_error("Unable to read object file " + obj_path); throw file_error("Unable to read object file " + object_path);
} }
auto magic = load_bytes<std::array<char, 2>>(file, 0); auto magic = load_bytes<std::array<char, 2>>(file, 0);
VERIFY(std::memcmp(magic.data(), "MZ", 2) == 0, "File is not a PE file " + obj_path); VERIFY(std::memcmp(magic.data(), "MZ", 2) == 0, "File is not a PE file " + object_path);
DWORD e_lfanew = pe_byteswap_if_needed(load_bytes<DWORD>(file, 0x3c)); // dos header + 0x3c DWORD e_lfanew = pe_byteswap_if_needed(load_bytes<DWORD>(file, 0x3c)); // dos header + 0x3c
DWORD nt_header_offset = e_lfanew; DWORD nt_header_offset = e_lfanew;
auto signature = load_bytes<std::array<char, 4>>(file, nt_header_offset); // nt header + 0 auto signature = load_bytes<std::array<char, 4>>(file, nt_header_offset); // nt header + 0
VERIFY(std::memcmp(signature.data(), "PE\0\0", 4) == 0, "File is not a PE file " + obj_path); VERIFY(std::memcmp(signature.data(), "PE\0\0", 4) == 0, "File is not a PE file " + object_path);
WORD size_of_optional_header = pe_byteswap_if_needed( WORD size_of_optional_header = pe_byteswap_if_needed(
load_bytes<WORD>(file, nt_header_offset + 4 + 0x10) // file header + 0x10 load_bytes<WORD>(file, nt_header_offset + 4 + 0x10) // file header + 0x10
); );
@ -51,7 +51,7 @@ namespace detail {
); );
VERIFY( VERIFY(
optional_header_magic == IMAGE_NT_OPTIONAL_HDR_MAGIC, optional_header_magic == IMAGE_NT_OPTIONAL_HDR_MAGIC,
"PE file does not match expected bit-mode " + obj_path "PE file does not match expected bit-mode " + object_path
); );
// finally get image base // finally get image base
if(optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { if(optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {

View File

@ -25,7 +25,7 @@ namespace detail {
dl_find_object result; dl_find_object result;
if(_dl_find_object(reinterpret_cast<void*>(address), &result) == 0) { if(_dl_find_object(reinterpret_cast<void*>(address), &result) == 0) {
out->raw_address = address; out->raw_address = address;
out->address_relative_to_object_base_in_memory = address - reinterpret_cast<frame_ptr>(result.dlfo_map_start); out->address_relative_to_object_start = address - reinterpret_cast<frame_ptr>(result.dlfo_map_start);
if(result.dlfo_link_map->l_name != nullptr && result.dlfo_link_map->l_name[0] != 0) { if(result.dlfo_link_map->l_name != nullptr && result.dlfo_link_map->l_name[0] != 0) {
std::size_t path_length = std::strlen(result.dlfo_link_map->l_name); std::size_t path_length = std::strlen(result.dlfo_link_map->l_name);
std::memcpy( std::memcpy(
@ -45,7 +45,7 @@ namespace detail {
} else { } else {
// std::cout<<"error"<<std::endl; // std::cout<<"error"<<std::endl;
out->raw_address = address; out->raw_address = address;
out->address_relative_to_object_base_in_memory = 0; out->address_relative_to_object_start = 0;
out->object_path[0] = 0; out->object_path[0] = 0;
} }
// TODO: Handle this part of the documentation? // TODO: Handle this part of the documentation?
@ -61,7 +61,7 @@ namespace cpptrace {
namespace detail { namespace detail {
inline void get_safe_object_frame(frame_ptr address, safe_object_frame* out) { inline void get_safe_object_frame(frame_ptr address, safe_object_frame* out) {
out->raw_address = address; out->raw_address = address;
out->address_relative_to_object_base_in_memory = 0; out->address_relative_to_object_start = 0;
out->object_path[0] = 0; out->object_path[0] = 0;
} }
} }

View File

@ -17,8 +17,8 @@ namespace detail {
const auto& entry = frames[i]; const auto& entry = frames[i];
// If libdl fails to find the shared object for a frame, the path will be empty. I've observed this // If libdl fails to find the shared object for a frame, the path will be empty. I've observed this
// on macos when looking up the shared object containing `start`. // on macos when looking up the shared object containing `start`.
if(!entry.obj_path.empty()) { if(!entry.object_path.empty()) {
entries[entry.obj_path].emplace_back( entries[entry.object_path].emplace_back(
entry, entry,
trace[i] trace[i]
); );
@ -36,8 +36,8 @@ namespace detail {
const auto& entry = frames[i]; const auto& entry = frames[i];
// If libdl fails to find the shared object for a frame, the path will be empty. I've observed this // If libdl fails to find the shared object for a frame, the path will be empty. I've observed this
// on macos when looking up the shared object containing `start`. // on macos when looking up the shared object containing `start`.
if(!entry.obj_path.empty()) { if(!entry.object_path.empty()) {
entries[entry.obj_path].emplace_back( entries[entry.object_path].emplace_back(
entry, entry,
trace[i] trace[i]
); );

View File

@ -236,12 +236,12 @@ namespace addr2line {
} }
const std::size_t symbol_end = in_location; const std::size_t symbol_end = in_location;
entries_vec[entry_index].second.get().symbol = line.substr(0, symbol_end); entries_vec[entry_index].second.get().symbol = line.substr(0, symbol_end);
const std::size_t obj_end = line.find(")", in_location); const std::size_t object_end = line.find(")", in_location);
VERIFY( VERIFY(
obj_end != std::string::npos, object_end != std::string::npos,
"Unexpected edge case while processing addr2line/atos output" "Unexpected edge case while processing addr2line/atos output"
); );
const std::size_t filename_start = line.find(") (", obj_end); const std::size_t filename_start = line.find(") (", object_end);
if(filename_start == std::string::npos) { if(filename_start == std::string::npos) {
// presumably something like 0x100003b70 (in demo) or foo (in bar) + 14 // presumably something like 0x100003b70 (in demo) or foo (in bar) + 14
return; return;
@ -271,7 +271,7 @@ namespace addr2line {
for(std::size_t i = 0; i < frames.size(); i++) { for(std::size_t i = 0; i < frames.size(); i++) {
trace[i].address = frames[i].raw_address; trace[i].address = frames[i].raw_address;
// Set what is known for now, and resolutions from addr2line should overwrite // Set what is known for now, and resolutions from addr2line should overwrite
trace[i].filename = frames[i].obj_path; trace[i].filename = frames[i].object_path;
} }
if(has_addr2line()) { if(has_addr2line()) {
const auto entries = collate_frames(frames, trace); const auto entries = collate_frames(frames, trace);
@ -288,7 +288,7 @@ namespace addr2line {
} }
std::string address_input; std::string address_input;
for(const auto& pair : entries_vec) { for(const auto& pair : entries_vec) {
address_input += to_hex(pair.first.get().obj_address); address_input += to_hex(pair.first.get().object_address);
#if !IS_WINDOWS #if !IS_WINDOWS
address_input += '\n'; address_input += '\n';
#else #else

View File

@ -83,7 +83,7 @@ namespace libdwarf {
}; };
struct dwarf_resolver { struct dwarf_resolver {
std::string obj_path; std::string object_path;
Dwarf_Debug dbg = nullptr; Dwarf_Debug dbg = nullptr;
bool ok = false; bool ok = false;
// .debug_aranges cache // .debug_aranges cache
@ -124,16 +124,16 @@ namespace libdwarf {
} }
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
dwarf_resolver(const std::string& object_path) { dwarf_resolver(const std::string& _object_path) {
obj_path = object_path; object_path = _object_path;
// for universal / fat mach-o files // for universal / fat mach-o files
unsigned universal_number = 0; unsigned universal_number = 0;
#if IS_APPLE #if IS_APPLE
if(directory_exists(obj_path + ".dSYM")) { if(directory_exists(object_path + ".dSYM")) {
obj_path += ".dSYM/Contents/Resources/DWARF/" + basename(object_path); object_path += ".dSYM/Contents/Resources/DWARF/" + basename(object_path);
} }
if(macho_is_fat(obj_path)) { if(macho_is_fat(object_path)) {
universal_number = get_fat_macho_index(obj_path); universal_number = get_fat_macho_index(object_path);
} }
#endif #endif
@ -142,7 +142,7 @@ namespace libdwarf {
std::unique_ptr<char[]> buffer(new char[CPPTRACE_MAX_PATH]); std::unique_ptr<char[]> buffer(new char[CPPTRACE_MAX_PATH]);
auto ret = wrap( auto ret = wrap(
dwarf_init_path_a, dwarf_init_path_a,
obj_path.c_str(), object_path.c_str(),
buffer.get(), buffer.get(),
CPPTRACE_MAX_PATH, CPPTRACE_MAX_PATH,
DW_GROUPNUMBER_ANY, DW_GROUPNUMBER_ANY,
@ -205,7 +205,7 @@ namespace libdwarf {
dwarf_resolver& operator=(const dwarf_resolver&) = delete; dwarf_resolver& operator=(const dwarf_resolver&) = delete;
dwarf_resolver(dwarf_resolver&& other) noexcept : dwarf_resolver(dwarf_resolver&& other) noexcept :
obj_path(std::move(other.obj_path)), object_path(std::move(other.object_path)),
dbg(other.dbg), dbg(other.dbg),
ok(other.ok), ok(other.ok),
aranges(other.aranges), aranges(other.aranges),
@ -220,7 +220,7 @@ namespace libdwarf {
} }
dwarf_resolver& operator=(dwarf_resolver&& other) noexcept { dwarf_resolver& operator=(dwarf_resolver&& other) noexcept {
obj_path = std::move(other.obj_path); object_path = std::move(other.object_path);
dbg = other.dbg; dbg = other.dbg;
ok = other.ok; ok = other.ok;
aranges = other.aranges; aranges = other.aranges;
@ -763,7 +763,7 @@ namespace libdwarf {
std::vector<stacktrace_frame>& inlines std::vector<stacktrace_frame>& inlines
) { ) {
if(dump_dwarf) { if(dump_dwarf) {
std::fprintf(stderr, "%s\n", obj_path.c_str()); std::fprintf(stderr, "%s\n", object_path.c_str());
std::fprintf(stderr, "%llx\n", to_ull(pc)); std::fprintf(stderr, "%llx\n", to_ull(pc));
} }
// Check for .debug_aranges for fast lookup // Check for .debug_aranges for fast lookup
@ -849,19 +849,19 @@ namespace libdwarf {
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
frame_with_inlines resolve_frame(const object_frame& frame_info) { frame_with_inlines resolve_frame(const object_frame& frame_info) {
stacktrace_frame frame = null_frame; stacktrace_frame frame = null_frame;
frame.filename = frame_info.obj_path; frame.filename = frame_info.object_path;
frame.address = frame_info.raw_address; frame.address = frame_info.raw_address;
if(trace_dwarf) { if(trace_dwarf) {
std::fprintf( std::fprintf(
stderr, stderr,
"Starting resolution for %s %08llx\n", "Starting resolution for %s %08llx\n",
obj_path.c_str(), object_path.c_str(),
to_ull(frame_info.obj_address) to_ull(frame_info.object_address)
); );
} }
std::vector<stacktrace_frame> inlines; std::vector<stacktrace_frame> inlines;
lookup_pc( lookup_pc(
frame_info.obj_address, frame_info.object_address,
frame, frame,
inlines inlines
); );
@ -877,21 +877,21 @@ namespace libdwarf {
static std::unordered_map<std::string, dwarf_resolver> resolver_map; static std::unordered_map<std::string, dwarf_resolver> resolver_map;
// Locking around all libdwarf interaction per https://github.com/davea42/libdwarf-code/discussions/184 // Locking around all libdwarf interaction per https://github.com/davea42/libdwarf-code/discussions/184
const std::lock_guard<std::mutex> lock(mutex); const std::lock_guard<std::mutex> lock(mutex);
for(const auto& obj_entry : collate_frames(frames, trace)) { for(const auto& object_entry : collate_frames(frames, trace)) {
try { try {
const auto& obj_name = obj_entry.first; const auto& object_name = object_entry.first;
optional<dwarf_resolver> resolver_object = nullopt; optional<dwarf_resolver> resolver_object = nullopt;
dwarf_resolver* resolver = nullptr; dwarf_resolver* resolver = nullptr;
auto it = resolver_map.find(obj_name); auto it = resolver_map.find(object_name);
if(it != resolver_map.end()) { if(it != resolver_map.end()) {
resolver = &it->second; resolver = &it->second;
} else { } else {
resolver_object = dwarf_resolver(obj_name); resolver_object = dwarf_resolver(object_name);
resolver = &resolver_object.unwrap(); resolver = &resolver_object.unwrap();
} }
// If there's no debug information it'll mark itself as not ok // If there's no debug information it'll mark itself as not ok
if(resolver->ok) { if(resolver->ok) {
for(const auto& entry : obj_entry.second) { for(const auto& entry : object_entry.second) {
try { try {
const auto& dlframe = entry.first.get(); const auto& dlframe = entry.first.get();
auto& frame = entry.second.get(); auto& frame = entry.second.get();
@ -904,7 +904,7 @@ namespace libdwarf {
} }
} else { } else {
// at least copy the addresses // at least copy the addresses
for(const auto& entry : obj_entry.second) { for(const auto& entry : object_entry.second) {
const auto& dlframe = entry.first.get(); const auto& dlframe = entry.first.get();
auto& frame = entry.second.get(); auto& frame = entry.second.get();
frame.frame.address = dlframe.raw_address; frame.frame.address = dlframe.raw_address;
@ -912,7 +912,7 @@ namespace libdwarf {
} }
if(resolver_object.has_value() && get_cache_mode() == cache_mode::prioritize_speed) { if(resolver_object.has_value() && get_cache_mode() == cache_mode::prioritize_speed) {
// .emplace needed, for some reason .insert tries to copy <= gcc 7.2 // .emplace needed, for some reason .insert tries to copy <= gcc 7.2
resolver_map.emplace(obj_name, std::move(resolver_object).unwrap()); resolver_map.emplace(object_name, std::move(resolver_object).unwrap());
} }
} catch(...) { // NOSONAR } catch(...) { // NOSONAR
if(!should_absorb_trace_exceptions()) { if(!should_absorb_trace_exceptions()) {

View File

@ -170,10 +170,10 @@ namespace detail {
// TODO: Re-evaluate use of off_t // TODO: Re-evaluate use of off_t
template<typename T, typename std::enable_if<std::is_trivial<T>::value, int>::type = 0> template<typename T, typename std::enable_if<std::is_trivial<T>::value, int>::type = 0>
T load_bytes(std::FILE* obj_file, off_t offset) { T load_bytes(std::FILE* object_file, off_t offset) {
T object; T object;
VERIFY(std::fseek(obj_file, offset, SEEK_SET) == 0, "fseek error"); VERIFY(std::fseek(object_file, offset, SEEK_SET) == 0, "fseek error");
VERIFY(std::fread(&object, sizeof(T), 1, obj_file) == 1, "fread error"); VERIFY(std::fread(&object, sizeof(T), 1, object_file) == 1, "fread error");
return object; return object;
} }