Improve Mach-O support (#40)
This commit is contained in:
parent
214dd1df36
commit
1689487978
@ -251,6 +251,8 @@ A couple things I'd like to fix in the future:
|
|||||||
- On Windows unwinding with `CaptureStackBackTrace` (msvc/clang) can sometimes produce program counters that are after
|
- On Windows unwinding with `CaptureStackBackTrace` (msvc/clang) can sometimes produce program counters that are after
|
||||||
the call instruction. Execinfo suffers from the same problem, but libgcc's `_Unwind` provides a means to detect this.
|
the call instruction. Execinfo suffers from the same problem, but libgcc's `_Unwind` provides a means to detect this.
|
||||||
I would like to find a solution on windows so stack traces are more accurate.
|
I would like to find a solution on windows so stack traces are more accurate.
|
||||||
|
- Support for universal binaries on macos (fat mach-o files) is hacky and inefficient at the moment. Libdwarf should be
|
||||||
|
adding proper support for these soon thanks to an awesome maintainer.
|
||||||
|
|
||||||
### FAQ: What about C++23 `<stacktrace>`?
|
### FAQ: What about C++23 `<stacktrace>`?
|
||||||
|
|
||||||
|
|||||||
@ -169,7 +169,7 @@ def main():
|
|||||||
run_matrix(matrix, exclude, build_full_or_auto)
|
run_matrix(matrix, exclude, build_full_or_auto)
|
||||||
if platform.system() == "Darwin":
|
if platform.system() == "Darwin":
|
||||||
matrix = {
|
matrix = {
|
||||||
"compiler": ["g++-13", "clang++"],
|
"compiler": ["g++-12", "clang++"],
|
||||||
"target": ["Debug"],
|
"target": ["Debug"],
|
||||||
"std": ["11", "20"],
|
"std": ["11", "20"],
|
||||||
"unwind": [
|
"unwind": [
|
||||||
@ -192,7 +192,7 @@ def main():
|
|||||||
exclude = []
|
exclude = []
|
||||||
run_matrix(matrix, exclude, build)
|
run_matrix(matrix, exclude, build)
|
||||||
matrix = {
|
matrix = {
|
||||||
"compiler": ["g++-13", "clang++"],
|
"compiler": ["g++-12", "clang++"],
|
||||||
"target": ["Debug"],
|
"target": ["Debug"],
|
||||||
"std": ["11", "20"],
|
"std": ["11", "20"],
|
||||||
"config": [""]
|
"config": [""]
|
||||||
|
|||||||
@ -323,7 +323,7 @@ def main():
|
|||||||
run_matrix(matrix, exclude, build_and_test_full_or_auto)
|
run_matrix(matrix, exclude, build_and_test_full_or_auto)
|
||||||
if platform.system() == "Darwin":
|
if platform.system() == "Darwin":
|
||||||
matrix = {
|
matrix = {
|
||||||
"compiler": ["g++-13", "clang++"],
|
"compiler": ["g++-12", "clang++"],
|
||||||
"target": ["Debug"],
|
"target": ["Debug"],
|
||||||
"std": ["11", "20"],
|
"std": ["11", "20"],
|
||||||
"unwind": [
|
"unwind": [
|
||||||
@ -346,7 +346,7 @@ def main():
|
|||||||
exclude = []
|
exclude = []
|
||||||
run_matrix(matrix, exclude, build_and_test)
|
run_matrix(matrix, exclude, build_and_test)
|
||||||
matrix = {
|
matrix = {
|
||||||
"compiler": ["g++-13", "clang++"],
|
"compiler": ["g++-12", "clang++"],
|
||||||
"target": ["Debug"],
|
"target": ["Debug"],
|
||||||
"std": ["11", "20"],
|
"std": ["11", "20"],
|
||||||
"config": [""]
|
"config": [""]
|
||||||
|
|||||||
@ -5,6 +5,11 @@
|
|||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
#if IS_APPLE
|
#if IS_APPLE
|
||||||
|
|
||||||
|
// A number of mach-o functions are deprecated as of macos 13
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@ -12,18 +17,9 @@
|
|||||||
#include <mach-o/loader.h>
|
#include <mach-o/loader.h>
|
||||||
#include <mach-o/swap.h>
|
#include <mach-o/swap.h>
|
||||||
#include <mach-o/fat.h>
|
#include <mach-o/fat.h>
|
||||||
|
#include <crt_externs.h>
|
||||||
#if defined(__aarch64__)
|
#include <mach-o/nlist.h>
|
||||||
#define CURRENT_CPU CPU_TYPE_ARM64
|
#include <mach-o/stab.h>
|
||||||
#elif defined(__arm__) && defined(__thumb__)
|
|
||||||
#define CURRENT_CPU CPU_TYPE_ARM
|
|
||||||
#elif defined(__amd64__)
|
|
||||||
#define CURRENT_CPU CPU_TYPE_X86_64
|
|
||||||
#elif defined(__i386__)
|
|
||||||
#define CURRENT_CPU CPU_TYPE_I386
|
|
||||||
#else
|
|
||||||
#error "Unknown CPU architecture"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -41,6 +37,10 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_fat_magic(uint32_t magic) {
|
||||||
|
return magic == FAT_MAGIC || magic == FAT_CIGAM;
|
||||||
|
}
|
||||||
|
|
||||||
// Based on https://github.com/AlexDenisov/segment_dumper/blob/master/main.c
|
// Based on https://github.com/AlexDenisov/segment_dumper/blob/master/main.c
|
||||||
// and https://lowlevelbits.org/parsing-mach-o-files/
|
// and https://lowlevelbits.org/parsing-mach-o-files/
|
||||||
static bool is_magic_64(uint32_t magic) {
|
static bool is_magic_64(uint32_t magic) {
|
||||||
@ -67,8 +67,20 @@ namespace detail {
|
|||||||
swap_segment_command(&segment, NX_UnknownByteOrder);
|
swap_segment_command(&segment, NX_UnknownByteOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
#define LP(x) x##_64
|
||||||
|
#else
|
||||||
|
#define LP(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
template<std::size_t Bits>
|
template<std::size_t Bits>
|
||||||
static uintptr_t macho_get_text_vmaddr_mach(FILE* obj_file, off_t offset, bool should_swap) {
|
static optional<uintptr_t> macho_get_text_vmaddr_mach(
|
||||||
|
FILE* obj_file,
|
||||||
|
const std::string& obj_path,
|
||||||
|
off_t offset,
|
||||||
|
bool should_swap,
|
||||||
|
bool allow_arch_mismatch
|
||||||
|
) {
|
||||||
static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument");
|
static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument");
|
||||||
using Mach_Header = typename std::conditional<Bits == 32, mach_header, mach_header_64>::type;
|
using Mach_Header = typename std::conditional<Bits == 32, mach_header, mach_header_64>::type;
|
||||||
using Segment_Command = typename std::conditional<Bits == 32, segment_command, segment_command_64>::type;
|
using Segment_Command = typename std::conditional<Bits == 32, segment_command, segment_command_64>::type;
|
||||||
@ -76,12 +88,28 @@ namespace detail {
|
|||||||
off_t load_commands_offset = offset;
|
off_t load_commands_offset = offset;
|
||||||
size_t header_size = sizeof(Mach_Header);
|
size_t header_size = sizeof(Mach_Header);
|
||||||
Mach_Header header = load_bytes<Mach_Header>(obj_file, offset);
|
Mach_Header header = load_bytes<Mach_Header>(obj_file, offset);
|
||||||
if(header.cputype != CURRENT_CPU) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(should_swap) {
|
if(should_swap) {
|
||||||
swap_mach_header(header);
|
swap_mach_header(header);
|
||||||
}
|
}
|
||||||
|
thread_local static struct LP(mach_header)* mhp = _NSGetMachExecuteHeader();
|
||||||
|
//fprintf(
|
||||||
|
// stderr,
|
||||||
|
// "----> %d %d; %d %d\n",
|
||||||
|
// header.cputype,
|
||||||
|
// mhp->cputype,
|
||||||
|
// static_cast<cpu_subtype_t>(mhp->cpusubtype & ~CPU_SUBTYPE_MASK),
|
||||||
|
// header.cpusubtype
|
||||||
|
//);
|
||||||
|
if(
|
||||||
|
header.cputype != mhp->cputype ||
|
||||||
|
static_cast<cpu_subtype_t>(mhp->cpusubtype & ~CPU_SUBTYPE_MASK) != header.cpusubtype
|
||||||
|
) {
|
||||||
|
if(allow_arch_mismatch) {
|
||||||
|
return nullopt;
|
||||||
|
} else {
|
||||||
|
CPPTRACE_VERIFY(false, "Mach-O file cpu type and subtype do not match current machine " + obj_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
ncmds = header.ncmds;
|
ncmds = header.ncmds;
|
||||||
load_commands_offset += header_size;
|
load_commands_offset += header_size;
|
||||||
// iterate load commands
|
// iterate load commands
|
||||||
@ -91,6 +119,7 @@ namespace detail {
|
|||||||
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
|
||||||
Segment_Command segment = load_bytes<Segment_Command>(obj_file, actual_offset);
|
Segment_Command segment = load_bytes<Segment_Command>(obj_file, actual_offset);
|
||||||
if(should_swap) {
|
if(should_swap) {
|
||||||
swap_segment_command(segment);
|
swap_segment_command(segment);
|
||||||
@ -105,7 +134,7 @@ namespace detail {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t macho_get_text_vmaddr_fat(FILE* obj_file, bool should_swap) {
|
static uintptr_t macho_get_text_vmaddr_fat(FILE* obj_file, const std::string& obj_path, bool should_swap) {
|
||||||
size_t header_size = sizeof(fat_header);
|
size_t header_size = sizeof(fat_header);
|
||||||
size_t arch_size = sizeof(fat_arch);
|
size_t arch_size = sizeof(fat_arch);
|
||||||
fat_header header = load_bytes<fat_header>(obj_file, 0);
|
fat_header header = load_bytes<fat_header>(obj_file, 0);
|
||||||
@ -113,7 +142,7 @@ namespace detail {
|
|||||||
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;
|
||||||
uintptr_t text_vmaddr = 0;
|
optional<uintptr_t> text_vmaddr;
|
||||||
for(uint32_t i = 0; i < header.nfat_arch; i++) {
|
for(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>(obj_file, arch_offset);
|
||||||
if(should_swap) {
|
if(should_swap) {
|
||||||
@ -125,27 +154,31 @@ namespace detail {
|
|||||||
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,
|
obj_file,
|
||||||
|
obj_path,
|
||||||
mach_header_offset,
|
mach_header_offset,
|
||||||
should_swap_bytes(magic)
|
should_swap_bytes(magic),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
text_vmaddr = macho_get_text_vmaddr_mach<32>(
|
text_vmaddr = macho_get_text_vmaddr_mach<32>(
|
||||||
obj_file,
|
obj_file,
|
||||||
|
obj_path,
|
||||||
mach_header_offset,
|
mach_header_offset,
|
||||||
should_swap_bytes(magic)
|
should_swap_bytes(magic),
|
||||||
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(text_vmaddr != 0) {
|
if(text_vmaddr.has_value()) {
|
||||||
return text_vmaddr;
|
return text_vmaddr.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If this is reached... something went wrong. The cpu we're on wasn't found.
|
// If this is reached... something went wrong. The cpu we're on wasn't found.
|
||||||
// TODO: Disabled temporarily for CI
|
CPPTRACE_VERIFY(false, "Couldn't find appropriate architecture in fat Mach-O");
|
||||||
/////CPPTRACE_VERIFY(false, "Couldn't find appropriate architecture in fat Mach-O");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t macho_get_text_vmaddr(const std::string& obj_path) {
|
static uintptr_t macho_get_text_vmaddr(const std::string& obj_path) {
|
||||||
|
//fprintf(stderr, "--%s--\n", obj_path.c_str());
|
||||||
auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter);
|
auto file = raii_wrap(fopen(obj_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 " + obj_path);
|
||||||
@ -155,18 +188,70 @@ namespace detail {
|
|||||||
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, should_swap);
|
return macho_get_text_vmaddr_fat(file, obj_path, should_swap);
|
||||||
} else {
|
} else {
|
||||||
if(is_64) {
|
if(is_64) {
|
||||||
return macho_get_text_vmaddr_mach<64>(file, 0, should_swap);
|
return macho_get_text_vmaddr_mach<64>(file, obj_path, 0, should_swap, false).unwrap();
|
||||||
} else {
|
} else {
|
||||||
return macho_get_text_vmaddr_mach<32>(file, 0, should_swap);
|
return macho_get_text_vmaddr_mach<32>(file, obj_path, 0, should_swap, false).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool macho_is_fat(const std::string& obj_path) {
|
||||||
|
auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||||
|
if(file == nullptr) {
|
||||||
|
throw file_error("Unable to read object file " + obj_path);
|
||||||
|
}
|
||||||
|
uint32_t magic = load_bytes<uint32_t>(file, 0);
|
||||||
|
return is_fat_magic(magic);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fat_info {
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns offset, file size
|
||||||
|
// TODO: Code duplication with macho_get_text_vmaddr_fat
|
||||||
|
inline fat_info get_fat_macho_information(const std::string& obj_path) {
|
||||||
|
auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||||
|
if(file == nullptr) {
|
||||||
|
throw file_error("Unable to read object file " + obj_path);
|
||||||
|
}
|
||||||
|
uint32_t magic = load_bytes<uint32_t>(file, 0);
|
||||||
|
CPPTRACE_VERIFY(is_fat_magic(magic));
|
||||||
|
bool should_swap = should_swap_bytes(magic);
|
||||||
|
size_t header_size = sizeof(fat_header);
|
||||||
|
size_t arch_size = sizeof(fat_arch);
|
||||||
|
fat_header header = load_bytes<fat_header>(file, 0);
|
||||||
|
if(should_swap) {
|
||||||
|
swap_fat_header(&header, NX_UnknownByteOrder);
|
||||||
|
}
|
||||||
|
off_t arch_offset = (off_t)header_size;
|
||||||
|
thread_local static struct LP(mach_header)* mhp = _NSGetMachExecuteHeader();
|
||||||
|
for(uint32_t i = 0; i < header.nfat_arch; i++) {
|
||||||
|
fat_arch arch = load_bytes<fat_arch>(file, arch_offset);
|
||||||
|
if(should_swap) {
|
||||||
|
swap_fat_arch(&arch, 1, NX_UnknownByteOrder);
|
||||||
|
}
|
||||||
|
arch_offset += arch_size;
|
||||||
|
if(
|
||||||
|
arch.cputype == mhp->cputype &&
|
||||||
|
static_cast<cpu_subtype_t>(mhp->cpusubtype & ~CPU_SUBTYPE_MASK) == arch.cpusubtype
|
||||||
|
) {
|
||||||
|
return { arch.offset, arch.size };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If this is reached... something went wrong. The cpu we're on wasn't found.
|
||||||
|
CPPTRACE_VERIFY(false, "Couldn't find appropriate architecture in fat Mach-O");
|
||||||
|
return { 0, 0 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -152,7 +152,7 @@ namespace detail {
|
|||||||
static_assert(n_digits(1024) == 4, "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
|
// TODO: Re-evaluate use of off_t
|
||||||
template<typename T, typename std::enable_if<std::is_pod<T>::value, int>::type = 0>
|
template<typename T, typename std::enable_if<std::is_trivial<T>::value, int>::type = 0>
|
||||||
T load_bytes(FILE* obj_file, off_t offset) {
|
T load_bytes(FILE* obj_file, off_t offset) {
|
||||||
T object;
|
T object;
|
||||||
CPPTRACE_VERIFY(fseek(obj_file, offset, SEEK_SET) == 0, "fseek error");
|
CPPTRACE_VERIFY(fseek(obj_file, offset, SEEK_SET) == 0, "fseek error");
|
||||||
@ -260,7 +260,7 @@ namespace detail {
|
|||||||
return holds_value;
|
return holds_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator bool() const {
|
explicit operator bool() const {
|
||||||
return holds_value;
|
return holds_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +347,8 @@ namespace detail {
|
|||||||
typename T,
|
typename T,
|
||||||
typename D,
|
typename D,
|
||||||
typename std::enable_if<
|
typename std::enable_if<
|
||||||
std::is_same<decltype(std::declval<D>()(std::declval<T>())), void>::value, int
|
std::is_same<decltype(std::declval<D>()(std::declval<T>())), void>::value,
|
||||||
|
int
|
||||||
>::type = 0
|
>::type = 0
|
||||||
>
|
>
|
||||||
class raii_wrapper {
|
class raii_wrapper {
|
||||||
@ -362,7 +363,7 @@ namespace detail {
|
|||||||
raii_wrapper& operator=(raii_wrapper&&) = delete;
|
raii_wrapper& operator=(raii_wrapper&&) = delete;
|
||||||
raii_wrapper& operator=(const raii_wrapper&) = delete;
|
raii_wrapper& operator=(const raii_wrapper&) = delete;
|
||||||
~raii_wrapper() {
|
~raii_wrapper() {
|
||||||
if(deleter) {
|
if(deleter.has_value()) {
|
||||||
deleter.unwrap()(obj);
|
deleter.unwrap()(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,7 +379,8 @@ namespace detail {
|
|||||||
typename T,
|
typename T,
|
||||||
typename D,
|
typename D,
|
||||||
typename std::enable_if<
|
typename std::enable_if<
|
||||||
std::is_same<decltype(std::declval<D>()(std::declval<T>())), void>::value, int
|
std::is_same<decltype(std::declval<D>()(std::declval<T>())), void>::value,
|
||||||
|
int
|
||||||
>::type = 0
|
>::type = 0
|
||||||
>
|
>
|
||||||
raii_wrapper<T, D> raii_wrap(T&& obj, D deleter) {
|
raii_wrapper<T, D> raii_wrap(T&& obj, D deleter) {
|
||||||
|
|||||||
@ -515,6 +515,9 @@ namespace libdwarf {
|
|||||||
std::unordered_map<Dwarf_Off, line_context> line_contexts;
|
std::unordered_map<Dwarf_Off, line_context> line_contexts;
|
||||||
std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache;
|
std::unordered_map<Dwarf_Off, std::vector<subprogram_entry>> subprograms_cache;
|
||||||
|
|
||||||
|
// Exists only for cleaning up an awful mach-o hack
|
||||||
|
std::string tmp_object_path;
|
||||||
|
|
||||||
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;
|
obj_path = object_path;
|
||||||
@ -522,6 +525,27 @@ namespace libdwarf {
|
|||||||
if(directory_exists(obj_path + ".dSYM")) {
|
if(directory_exists(obj_path + ".dSYM")) {
|
||||||
obj_path += ".dSYM/Contents/Resources/DWARF/" + basename(object_path);
|
obj_path += ".dSYM/Contents/Resources/DWARF/" + basename(object_path);
|
||||||
}
|
}
|
||||||
|
if(macho_is_fat(obj_path)) {
|
||||||
|
// If the object is fat, we'll copy out the mach-o object we care about
|
||||||
|
// Awful hack until libdwarf supports fat mach
|
||||||
|
auto sub_object = get_fat_macho_information(obj_path);
|
||||||
|
char tmp_template[] = "/tmp/tmp.cpptrace.XXXXXX";
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
CPPTRACE_VERIFY(mktemp(tmp_template) != nullptr);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
std::string tmp_path = tmp_template;
|
||||||
|
auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||||
|
auto tmp = raii_wrap(fopen(tmp_path.c_str(), "wb"), file_deleter);
|
||||||
|
CPPTRACE_VERIFY(file != nullptr);
|
||||||
|
CPPTRACE_VERIFY(tmp != nullptr);
|
||||||
|
std::unique_ptr<char[]> buffer(new char[sub_object.size]);
|
||||||
|
CPPTRACE_VERIFY(fseek(file, sub_object.offset, SEEK_SET) == 0);
|
||||||
|
CPPTRACE_VERIFY(fread(buffer.get(), 1, sub_object.size, file) == sub_object.size);
|
||||||
|
CPPTRACE_VERIFY(fwrite(buffer.get(), 1, sub_object.size, tmp) == sub_object.size);
|
||||||
|
obj_path = tmp_path;
|
||||||
|
tmp_object_path = std::move(tmp_path);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Dwarf_Ptr errarg = 0;
|
Dwarf_Ptr errarg = 0;
|
||||||
@ -553,6 +577,10 @@ namespace libdwarf {
|
|||||||
// subprograms_cache needs to be destroyed before dbg otherwise there will be another use after free
|
// subprograms_cache needs to be destroyed before dbg otherwise there will be another use after free
|
||||||
subprograms_cache.clear();
|
subprograms_cache.clear();
|
||||||
dwarf_finish(dbg);
|
dwarf_finish(dbg);
|
||||||
|
// cleanup awful mach-o hack
|
||||||
|
if(!tmp_object_path.empty()) {
|
||||||
|
unlink(tmp_object_path.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk die list, callback is called on each die and should return true to
|
// walk die list, callback is called on each die and should return true to
|
||||||
@ -616,7 +644,7 @@ namespace libdwarf {
|
|||||||
} else if(auto linkage_name = die.get_string_attribute(DW_AT_name)) {
|
} else if(auto linkage_name = die.get_string_attribute(DW_AT_name)) {
|
||||||
name = std::move(linkage_name);
|
name = std::move(linkage_name);
|
||||||
}
|
}
|
||||||
if(name) {
|
if(name.has_value()) {
|
||||||
frame.symbol = std::move(name).unwrap();
|
frame.symbol = std::move(name).unwrap();
|
||||||
} else {
|
} else {
|
||||||
if(die.has_attr(DW_AT_specification)) {
|
if(die.has_attr(DW_AT_specification)) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user