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:
parent
2a4a8066d3
commit
9113cc5ffc
@ -185,9 +185,9 @@ is resolved), and the path to the object the instruction pointer is located in.
|
||||
```cpp
|
||||
namespace cpptrace {
|
||||
struct object_frame {
|
||||
std::string obj_path;
|
||||
std::string object_path;
|
||||
frame_ptr raw_address;
|
||||
frame_ptr obj_address;
|
||||
frame_ptr object_address;
|
||||
};
|
||||
|
||||
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);
|
||||
struct safe_object_frame {
|
||||
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];
|
||||
object_frame resolve() const; // To be called outside a signal handler. Not signal safe.
|
||||
};
|
||||
|
||||
@ -54,9 +54,9 @@ namespace cpptrace {
|
||||
};
|
||||
|
||||
struct CPPTRACE_EXPORT object_frame {
|
||||
std::string obj_path;
|
||||
frame_ptr raw_address;
|
||||
frame_ptr obj_address;
|
||||
frame_ptr object_address;
|
||||
std::string object_path;
|
||||
};
|
||||
|
||||
struct CPPTRACE_EXPORT object_trace {
|
||||
@ -195,7 +195,7 @@ namespace cpptrace {
|
||||
);
|
||||
struct CPPTRACE_EXPORT safe_object_frame {
|
||||
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];
|
||||
// To be called outside a signal handler. Not signal safe.
|
||||
object_frame resolve() const;
|
||||
|
||||
@ -46,7 +46,7 @@ namespace cpptrace {
|
||||
|
||||
struct safe_object_frame {
|
||||
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];
|
||||
object_frame resolve() const; // To be called outside a signal handler. Not signal safe.
|
||||
};
|
||||
|
||||
@ -26,7 +26,7 @@ namespace detail {
|
||||
|
||||
template<std::size_t Bits>
|
||||
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,
|
||||
bool is_little_endian
|
||||
) {
|
||||
@ -34,7 +34,7 @@ namespace detail {
|
||||
using Header = typename std::conditional<Bits == 32, Elf32_Ehdr, Elf64_Ehdr>::type;
|
||||
using PHeader = typename std::conditional<Bits == 32, Elf32_Phdr, Elf64_Phdr>::type;
|
||||
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
|
||||
// Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011
|
||||
// It should occur at the beginning but may as well loop just in case
|
||||
@ -49,22 +49,22 @@ namespace detail {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::uintptr_t elf_get_module_image_base(const std::string& obj_path) {
|
||||
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||
static std::uintptr_t elf_get_module_image_base(const std::string& object_path) {
|
||||
auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
|
||||
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
|
||||
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_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
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,8 +75,8 @@ namespace detail {
|
||||
|
||||
template<std::size_t Bits>
|
||||
static optional<std::uintptr_t> macho_get_text_vmaddr_mach(
|
||||
std::FILE* obj_file,
|
||||
const std::string& obj_path,
|
||||
std::FILE* object_file,
|
||||
const std::string& object_path,
|
||||
off_t offset,
|
||||
bool should_swap,
|
||||
bool allow_arch_mismatch
|
||||
@ -87,7 +87,7 @@ namespace detail {
|
||||
std::uint32_t ncmds;
|
||||
off_t load_commands_offset = offset;
|
||||
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) {
|
||||
swap_mach_header(header);
|
||||
}
|
||||
@ -107,7 +107,7 @@ namespace detail {
|
||||
if(allow_arch_mismatch) {
|
||||
return nullopt;
|
||||
} 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;
|
||||
@ -115,12 +115,12 @@ namespace detail {
|
||||
// iterate load commands
|
||||
off_t actual_offset = load_commands_offset;
|
||||
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) {
|
||||
swap_load_command(&cmd, NX_UnknownByteOrder);
|
||||
}
|
||||
// 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) {
|
||||
swap_segment_command(segment);
|
||||
}
|
||||
@ -135,38 +135,38 @@ namespace detail {
|
||||
}
|
||||
|
||||
static std::uintptr_t macho_get_text_vmaddr_fat(
|
||||
std::FILE* obj_file,
|
||||
const std::string& obj_path,
|
||||
std::FILE* object_file,
|
||||
const std::string& object_path,
|
||||
bool should_swap
|
||||
) {
|
||||
std::size_t header_size = sizeof(fat_header);
|
||||
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) {
|
||||
swap_fat_header(&header, NX_UnknownByteOrder);
|
||||
}
|
||||
off_t arch_offset = (off_t)header_size;
|
||||
optional<std::uintptr_t> text_vmaddr;
|
||||
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) {
|
||||
swap_fat_arch(&arch, 1, NX_UnknownByteOrder);
|
||||
}
|
||||
off_t mach_header_offset = (off_t)arch.offset;
|
||||
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)) {
|
||||
text_vmaddr = macho_get_text_vmaddr_mach<64>(
|
||||
obj_file,
|
||||
obj_path,
|
||||
object_file,
|
||||
object_path,
|
||||
mach_header_offset,
|
||||
should_swap_bytes(magic),
|
||||
true
|
||||
);
|
||||
} else {
|
||||
text_vmaddr = macho_get_text_vmaddr_mach<32>(
|
||||
obj_file,
|
||||
obj_path,
|
||||
object_file,
|
||||
object_path,
|
||||
mach_header_offset,
|
||||
should_swap_bytes(magic),
|
||||
true
|
||||
@ -181,31 +181,31 @@ namespace detail {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::uintptr_t macho_get_text_vmaddr(const std::string& obj_path) {
|
||||
//std::fprintf(stderr, "--%s--\n", obj_path.c_str());
|
||||
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||
static std::uintptr_t macho_get_text_vmaddr(const std::string& object_path) {
|
||||
//std::fprintf(stderr, "--%s--\n", object_path.c_str());
|
||||
auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
|
||||
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);
|
||||
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 should_swap = should_swap_bytes(magic);
|
||||
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 {
|
||||
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 {
|
||||
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) {
|
||||
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||
inline bool macho_is_fat(const std::string& object_path) {
|
||||
auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
|
||||
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);
|
||||
return is_fat_magic(magic);
|
||||
@ -213,10 +213,10 @@ namespace detail {
|
||||
|
||||
// returns index of the appropriate mach-o binary in the universal binary
|
||||
// TODO: Code duplication with macho_get_text_vmaddr_fat
|
||||
inline unsigned get_fat_macho_index(const std::string& obj_path) {
|
||||
auto file = raii_wrap(std::fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||
inline unsigned get_fat_macho_index(const std::string& object_path) {
|
||||
auto file = raii_wrap(std::fopen(object_path.c_str(), "rb"), file_deleter);
|
||||
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);
|
||||
VERIFY(is_fat_magic(magic));
|
||||
|
||||
@ -26,35 +26,35 @@ namespace cpptrace {
|
||||
namespace detail {
|
||||
#if IS_LINUX || 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;
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
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()) {
|
||||
// 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(obj_path);
|
||||
cache.insert(it, {obj_path, base});
|
||||
auto base = elf_get_module_image_base(object_path);
|
||||
cache.insert(it, {object_path, base});
|
||||
return base;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
#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.....
|
||||
// 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(obj_path);
|
||||
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 = macho_get_text_vmaddr(obj_path);
|
||||
cache.insert(it, {obj_path, base});
|
||||
auto base = macho_get_text_vmaddr(object_path);
|
||||
cache.insert(it, {object_path, base});
|
||||
return base;
|
||||
} else {
|
||||
return it->second;
|
||||
@ -70,12 +70,12 @@ namespace detail {
|
||||
Dl_info info;
|
||||
object_frame frame;
|
||||
frame.raw_address = addr;
|
||||
frame.obj_address = 0;
|
||||
frame.object_address = 0;
|
||||
if(dladdr(reinterpret_cast<void*>(addr), &info)) { // thread safe
|
||||
// dli_sname and dli_saddr are only present with -rdynamic, sname will be included
|
||||
// but we don't really need dli_saddr
|
||||
frame.obj_path = info.dli_fname;
|
||||
frame.obj_address = addr
|
||||
frame.object_path = info.dli_fname;
|
||||
frame.object_address = addr
|
||||
- reinterpret_cast<std::uintptr_t>(info.dli_fbase)
|
||||
+ 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;
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
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()) {
|
||||
// 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(obj_path);
|
||||
cache.insert(it, {obj_path, base});
|
||||
auto base = pe_get_module_image_base(object_path);
|
||||
cache.insert(it, {object_path, base});
|
||||
return base;
|
||||
} else {
|
||||
return it->second;
|
||||
@ -129,7 +129,7 @@ namespace detail {
|
||||
for(const frame_ptr addr : addrs) {
|
||||
object_frame frame;
|
||||
frame.raw_address = addr;
|
||||
frame.obj_address = 0;
|
||||
frame.object_address = 0;
|
||||
HMODULE handle;
|
||||
// Multithread safe as long as another thread doesn't come along and free the module
|
||||
if(GetModuleHandleExA(
|
||||
@ -137,10 +137,10 @@ namespace detail {
|
||||
reinterpret_cast<const char*>(addr),
|
||||
&handle
|
||||
)) {
|
||||
frame.obj_path = get_module_name(handle);
|
||||
frame.obj_address = addr
|
||||
frame.object_path = get_module_name(handle);
|
||||
frame.object_address = addr
|
||||
- reinterpret_cast<std::uintptr_t>(handle)
|
||||
+ get_module_image_base(frame.obj_path);
|
||||
+ get_module_image_base(frame.object_path);
|
||||
} else {
|
||||
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) {
|
||||
return {
|
||||
frame.object_path,
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -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://0xrick.github.io/win-internals/pe3/
|
||||
// Endianness should always be little for dos and pe headers
|
||||
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);
|
||||
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);
|
||||
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 nt_header_offset = e_lfanew;
|
||||
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(
|
||||
load_bytes<WORD>(file, nt_header_offset + 4 + 0x10) // file header + 0x10
|
||||
);
|
||||
@ -51,7 +51,7 @@ namespace detail {
|
||||
);
|
||||
VERIFY(
|
||||
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
|
||||
if(optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
|
||||
@ -25,7 +25,7 @@ namespace detail {
|
||||
dl_find_object result;
|
||||
if(_dl_find_object(reinterpret_cast<void*>(address), &result) == 0) {
|
||||
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) {
|
||||
std::size_t path_length = std::strlen(result.dlfo_link_map->l_name);
|
||||
std::memcpy(
|
||||
@ -45,7 +45,7 @@ namespace detail {
|
||||
} else {
|
||||
// std::cout<<"error"<<std::endl;
|
||||
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;
|
||||
}
|
||||
// TODO: Handle this part of the documentation?
|
||||
@ -61,7 +61,7 @@ namespace cpptrace {
|
||||
namespace detail {
|
||||
inline void get_safe_object_frame(frame_ptr address, safe_object_frame* out) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,8 +17,8 @@ namespace detail {
|
||||
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
|
||||
// on macos when looking up the shared object containing `start`.
|
||||
if(!entry.obj_path.empty()) {
|
||||
entries[entry.obj_path].emplace_back(
|
||||
if(!entry.object_path.empty()) {
|
||||
entries[entry.object_path].emplace_back(
|
||||
entry,
|
||||
trace[i]
|
||||
);
|
||||
@ -36,8 +36,8 @@ namespace detail {
|
||||
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
|
||||
// on macos when looking up the shared object containing `start`.
|
||||
if(!entry.obj_path.empty()) {
|
||||
entries[entry.obj_path].emplace_back(
|
||||
if(!entry.object_path.empty()) {
|
||||
entries[entry.object_path].emplace_back(
|
||||
entry,
|
||||
trace[i]
|
||||
);
|
||||
|
||||
@ -236,12 +236,12 @@ namespace addr2line {
|
||||
}
|
||||
const std::size_t symbol_end = in_location;
|
||||
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(
|
||||
obj_end != std::string::npos,
|
||||
object_end != std::string::npos,
|
||||
"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) {
|
||||
// presumably something like 0x100003b70 (in demo) or foo (in bar) + 14
|
||||
return;
|
||||
@ -271,7 +271,7 @@ namespace addr2line {
|
||||
for(std::size_t i = 0; i < frames.size(); i++) {
|
||||
trace[i].address = frames[i].raw_address;
|
||||
// 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()) {
|
||||
const auto entries = collate_frames(frames, trace);
|
||||
@ -288,7 +288,7 @@ namespace addr2line {
|
||||
}
|
||||
std::string address_input;
|
||||
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
|
||||
address_input += '\n';
|
||||
#else
|
||||
|
||||
@ -83,7 +83,7 @@ namespace libdwarf {
|
||||
};
|
||||
|
||||
struct dwarf_resolver {
|
||||
std::string obj_path;
|
||||
std::string object_path;
|
||||
Dwarf_Debug dbg = nullptr;
|
||||
bool ok = false;
|
||||
// .debug_aranges cache
|
||||
@ -124,16 +124,16 @@ namespace libdwarf {
|
||||
}
|
||||
|
||||
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
|
||||
dwarf_resolver(const std::string& object_path) {
|
||||
obj_path = object_path;
|
||||
dwarf_resolver(const std::string& _object_path) {
|
||||
object_path = _object_path;
|
||||
// for universal / fat mach-o files
|
||||
unsigned universal_number = 0;
|
||||
#if IS_APPLE
|
||||
if(directory_exists(obj_path + ".dSYM")) {
|
||||
obj_path += ".dSYM/Contents/Resources/DWARF/" + basename(object_path);
|
||||
if(directory_exists(object_path + ".dSYM")) {
|
||||
object_path += ".dSYM/Contents/Resources/DWARF/" + basename(object_path);
|
||||
}
|
||||
if(macho_is_fat(obj_path)) {
|
||||
universal_number = get_fat_macho_index(obj_path);
|
||||
if(macho_is_fat(object_path)) {
|
||||
universal_number = get_fat_macho_index(object_path);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -142,7 +142,7 @@ namespace libdwarf {
|
||||
std::unique_ptr<char[]> buffer(new char[CPPTRACE_MAX_PATH]);
|
||||
auto ret = wrap(
|
||||
dwarf_init_path_a,
|
||||
obj_path.c_str(),
|
||||
object_path.c_str(),
|
||||
buffer.get(),
|
||||
CPPTRACE_MAX_PATH,
|
||||
DW_GROUPNUMBER_ANY,
|
||||
@ -205,7 +205,7 @@ namespace libdwarf {
|
||||
dwarf_resolver& operator=(const dwarf_resolver&) = delete;
|
||||
|
||||
dwarf_resolver(dwarf_resolver&& other) noexcept :
|
||||
obj_path(std::move(other.obj_path)),
|
||||
object_path(std::move(other.object_path)),
|
||||
dbg(other.dbg),
|
||||
ok(other.ok),
|
||||
aranges(other.aranges),
|
||||
@ -220,7 +220,7 @@ namespace libdwarf {
|
||||
}
|
||||
|
||||
dwarf_resolver& operator=(dwarf_resolver&& other) noexcept {
|
||||
obj_path = std::move(other.obj_path);
|
||||
object_path = std::move(other.object_path);
|
||||
dbg = other.dbg;
|
||||
ok = other.ok;
|
||||
aranges = other.aranges;
|
||||
@ -763,7 +763,7 @@ namespace libdwarf {
|
||||
std::vector<stacktrace_frame>& inlines
|
||||
) {
|
||||
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));
|
||||
}
|
||||
// Check for .debug_aranges for fast lookup
|
||||
@ -849,19 +849,19 @@ namespace libdwarf {
|
||||
CPPTRACE_FORCE_NO_INLINE_FOR_PROFILING
|
||||
frame_with_inlines resolve_frame(const object_frame& frame_info) {
|
||||
stacktrace_frame frame = null_frame;
|
||||
frame.filename = frame_info.obj_path;
|
||||
frame.filename = frame_info.object_path;
|
||||
frame.address = frame_info.raw_address;
|
||||
if(trace_dwarf) {
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"Starting resolution for %s %08llx\n",
|
||||
obj_path.c_str(),
|
||||
to_ull(frame_info.obj_address)
|
||||
object_path.c_str(),
|
||||
to_ull(frame_info.object_address)
|
||||
);
|
||||
}
|
||||
std::vector<stacktrace_frame> inlines;
|
||||
lookup_pc(
|
||||
frame_info.obj_address,
|
||||
frame_info.object_address,
|
||||
frame,
|
||||
inlines
|
||||
);
|
||||
@ -877,21 +877,21 @@ namespace libdwarf {
|
||||
static std::unordered_map<std::string, dwarf_resolver> resolver_map;
|
||||
// Locking around all libdwarf interaction per https://github.com/davea42/libdwarf-code/discussions/184
|
||||
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 {
|
||||
const auto& obj_name = obj_entry.first;
|
||||
const auto& object_name = object_entry.first;
|
||||
optional<dwarf_resolver> resolver_object = nullopt;
|
||||
dwarf_resolver* resolver = nullptr;
|
||||
auto it = resolver_map.find(obj_name);
|
||||
auto it = resolver_map.find(object_name);
|
||||
if(it != resolver_map.end()) {
|
||||
resolver = &it->second;
|
||||
} else {
|
||||
resolver_object = dwarf_resolver(obj_name);
|
||||
resolver_object = dwarf_resolver(object_name);
|
||||
resolver = &resolver_object.unwrap();
|
||||
}
|
||||
// If there's no debug information it'll mark itself as not ok
|
||||
if(resolver->ok) {
|
||||
for(const auto& entry : obj_entry.second) {
|
||||
for(const auto& entry : object_entry.second) {
|
||||
try {
|
||||
const auto& dlframe = entry.first.get();
|
||||
auto& frame = entry.second.get();
|
||||
@ -904,7 +904,7 @@ namespace libdwarf {
|
||||
}
|
||||
} else {
|
||||
// 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();
|
||||
auto& frame = entry.second.get();
|
||||
frame.frame.address = dlframe.raw_address;
|
||||
@ -912,7 +912,7 @@ namespace libdwarf {
|
||||
}
|
||||
if(resolver_object.has_value() && get_cache_mode() == cache_mode::prioritize_speed) {
|
||||
// .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
|
||||
if(!should_absorb_trace_exceptions()) {
|
||||
|
||||
@ -170,10 +170,10 @@ namespace detail {
|
||||
|
||||
// TODO: Re-evaluate use of off_t
|
||||
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;
|
||||
VERIFY(std::fseek(obj_file, offset, SEEK_SET) == 0, "fseek error");
|
||||
VERIFY(std::fread(&object, sizeof(T), 1, obj_file) == 1, "fread error");
|
||||
VERIFY(std::fseek(object_file, offset, SEEK_SET) == 0, "fseek error");
|
||||
VERIFY(std::fread(&object, sizeof(T), 1, object_file) == 1, "fread error");
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user