Add frame_ptr alias
This commit is contained in:
parent
7929d239bd
commit
4c1c42c61d
@ -22,8 +22,10 @@ namespace cpptrace {
|
|||||||
struct object_trace;
|
struct object_trace;
|
||||||
struct stacktrace;
|
struct stacktrace;
|
||||||
|
|
||||||
|
using frame_ptr = std::uintptr_t;
|
||||||
|
|
||||||
struct CPPTRACE_EXPORT raw_trace {
|
struct CPPTRACE_EXPORT raw_trace {
|
||||||
std::vector<std::uintptr_t> frames;
|
std::vector<frame_ptr> frames;
|
||||||
static raw_trace current(std::uint_least32_t skip = 0);
|
static raw_trace current(std::uint_least32_t skip = 0);
|
||||||
static raw_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
|
static raw_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
|
||||||
object_trace resolve_object_trace() const;
|
object_trace resolve_object_trace() const;
|
||||||
@ -31,8 +33,8 @@ namespace cpptrace {
|
|||||||
void clear();
|
void clear();
|
||||||
bool empty() const noexcept;
|
bool empty() const noexcept;
|
||||||
|
|
||||||
using iterator = std::vector<std::uintptr_t>::iterator;
|
using iterator = std::vector<frame_ptr>::iterator;
|
||||||
using const_iterator = std::vector<std::uintptr_t>::const_iterator;
|
using const_iterator = std::vector<frame_ptr>::const_iterator;
|
||||||
inline iterator begin() noexcept { return frames.begin(); }
|
inline iterator begin() noexcept { return frames.begin(); }
|
||||||
inline iterator end() noexcept { return frames.end(); }
|
inline iterator end() noexcept { return frames.end(); }
|
||||||
inline const_iterator begin() const noexcept { return frames.begin(); }
|
inline const_iterator begin() const noexcept { return frames.begin(); }
|
||||||
@ -44,8 +46,8 @@ namespace cpptrace {
|
|||||||
struct CPPTRACE_EXPORT object_frame {
|
struct CPPTRACE_EXPORT object_frame {
|
||||||
std::string obj_path;
|
std::string obj_path;
|
||||||
std::string symbol;
|
std::string symbol;
|
||||||
std::uintptr_t raw_address = 0;
|
frame_ptr raw_address = 0;
|
||||||
std::uintptr_t obj_address = 0;
|
frame_ptr obj_address = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CPPTRACE_EXPORT object_trace {
|
struct CPPTRACE_EXPORT object_trace {
|
||||||
@ -67,7 +69,7 @@ namespace cpptrace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct CPPTRACE_EXPORT stacktrace_frame {
|
struct CPPTRACE_EXPORT stacktrace_frame {
|
||||||
std::uintptr_t address;
|
frame_ptr address;
|
||||||
std::uint_least32_t line; // TODO: This should use UINT_LEAST32_MAX as a sentinel
|
std::uint_least32_t line; // TODO: This should use UINT_LEAST32_MAX as a sentinel
|
||||||
std::uint_least32_t column; // UINT_LEAST32_MAX if not present
|
std::uint_least32_t column; // UINT_LEAST32_MAX if not present
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
|||||||
@ -111,7 +111,7 @@ namespace cpptrace {
|
|||||||
stream
|
stream
|
||||||
<< std::hex
|
<< std::hex
|
||||||
<< "0x"
|
<< "0x"
|
||||||
<< std::setw(2 * sizeof(std::uintptr_t))
|
<< std::setw(2 * sizeof(frame_ptr))
|
||||||
<< std::setfill('0')
|
<< std::setfill('0')
|
||||||
<< frame.address
|
<< frame.address
|
||||||
<< std::dec
|
<< std::dec
|
||||||
@ -178,14 +178,14 @@ namespace cpptrace {
|
|||||||
<< " ";
|
<< " ";
|
||||||
if(frame.is_inline) {
|
if(frame.is_inline) {
|
||||||
stream
|
stream
|
||||||
<< std::setw(2 * sizeof(std::uintptr_t) + 2)
|
<< std::setw(2 * sizeof(frame_ptr) + 2)
|
||||||
<< "(inlined)";
|
<< "(inlined)";
|
||||||
} else {
|
} else {
|
||||||
stream
|
stream
|
||||||
<< std::hex
|
<< std::hex
|
||||||
<< blue
|
<< blue
|
||||||
<< "0x"
|
<< "0x"
|
||||||
<< std::setw(2 * sizeof(std::uintptr_t))
|
<< std::setw(2 * sizeof(frame_ptr))
|
||||||
<< std::setfill('0')
|
<< std::setfill('0')
|
||||||
<< frame.address
|
<< frame.address
|
||||||
<< std::dec
|
<< std::dec
|
||||||
@ -295,7 +295,7 @@ namespace cpptrace {
|
|||||||
CPPTRACE_FORCE_NO_INLINE
|
CPPTRACE_FORCE_NO_INLINE
|
||||||
stacktrace generate_trace(std::uint32_t skip, std::uint_least32_t max_depth) {
|
stacktrace generate_trace(std::uint32_t skip, std::uint_least32_t max_depth) {
|
||||||
try {
|
try {
|
||||||
std::vector<std::uintptr_t> frames = detail::capture_frames(skip + 1, max_depth);
|
std::vector<frame_ptr> frames = detail::capture_frames(skip + 1, max_depth);
|
||||||
std::vector<stacktrace_frame> trace = detail::resolve_frames(frames);
|
std::vector<stacktrace_frame> trace = detail::resolve_frames(frames);
|
||||||
for(auto& frame : trace) {
|
for(auto& frame : trace) {
|
||||||
frame.symbol = detail::demangle(frame.symbol);
|
frame.symbol = detail::demangle(frame.symbol);
|
||||||
|
|||||||
@ -62,11 +62,11 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
||||||
inline std::vector<object_frame> get_frames_object_info(const std::vector<std::uintptr_t>& addrs) {
|
inline std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addrs) {
|
||||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||||
std::vector<object_frame> frames;
|
std::vector<object_frame> frames;
|
||||||
frames.reserve(addrs.size());
|
frames.reserve(addrs.size());
|
||||||
for(const std::uintptr_t addr : addrs) {
|
for(const frame_ptr addr : addrs) {
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
object_frame frame;
|
object_frame frame;
|
||||||
frame.raw_address = addr;
|
frame.raw_address = addr;
|
||||||
@ -122,11 +122,11 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
// aladdr queries are needed to get pre-ASLR addresses and targets to run addr2line on
|
||||||
inline std::vector<object_frame> get_frames_object_info(const std::vector<std::uintptr_t>& addrs) {
|
inline std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addrs) {
|
||||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||||
std::vector<object_frame> frames;
|
std::vector<object_frame> frames;
|
||||||
frames.reserve(addrs.size());
|
frames.reserve(addrs.size());
|
||||||
for(const std::uintptr_t addr : addrs) {
|
for(const frame_ptr addr : addrs) {
|
||||||
object_frame frame;
|
object_frame frame;
|
||||||
frame.raw_address = addr;
|
frame.raw_address = addr;
|
||||||
HMODULE handle;
|
HMODULE handle;
|
||||||
|
|||||||
@ -352,8 +352,8 @@ namespace detail {
|
|||||||
return static_cast<unsigned long long>(t);
|
return static_cast<unsigned long long>(t);
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::uintptr_t to_uintptr(T t) {
|
frame_ptr to_frame_ptr(T t) {
|
||||||
return static_cast<std::uintptr_t>(t);
|
return static_cast<frame_ptr>(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A way to cast to U without "warning: useless cast to type"
|
// A way to cast to U without "warning: useless cast to type"
|
||||||
|
|||||||
@ -32,7 +32,7 @@ namespace detail {
|
|||||||
|
|
||||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE
|
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE
|
||||||
namespace libbacktrace {
|
namespace libbacktrace {
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
|
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
|
||||||
@ -42,7 +42,7 @@ namespace detail {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL
|
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL
|
||||||
namespace libdl {
|
namespace libdl {
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE
|
#ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE
|
||||||
@ -52,18 +52,18 @@ namespace detail {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP
|
#ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP
|
||||||
namespace dbghelp {
|
namespace dbghelp {
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING
|
#ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING
|
||||||
namespace nothing {
|
namespace nothing {
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames);
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames);
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames);
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames);
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -84,7 +84,7 @@ namespace detail {
|
|||||||
|| defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) \
|
|| defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) \
|
||||||
|| defined(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE)
|
|| defined(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE)
|
||||||
// actually need to go backwards to a void*
|
// actually need to go backwards to a void*
|
||||||
std::vector<std::uintptr_t> raw_frames(frames.size());
|
std::vector<frame_ptr> raw_frames(frames.size());
|
||||||
for(std::size_t i = 0; i < frames.size(); i++) {
|
for(std::size_t i = 0; i < frames.size(); i++) {
|
||||||
raw_frames[i] = frames[i].raw_address;
|
raw_frames[i] = frames[i].raw_address;
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ namespace detail {
|
|||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames) {
|
||||||
#if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) \
|
#if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) \
|
||||||
|| defined(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
|
|| defined(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
|
||||||
auto dlframes = get_frames_object_info(frames);
|
auto dlframes = get_frames_object_info(frames);
|
||||||
|
|||||||
@ -325,7 +325,7 @@ namespace dbghelp {
|
|||||||
std::recursive_mutex dbghelp_lock;
|
std::recursive_mutex dbghelp_lock;
|
||||||
|
|
||||||
// TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions
|
// TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions
|
||||||
stacktrace_frame resolve_frame(HANDLE proc, std::uintptr_t addr) {
|
stacktrace_frame resolve_frame(HANDLE proc, frame_ptr addr) {
|
||||||
const std::lock_guard<std::recursive_mutex> lock(dbghelp_lock); // all dbghelp functions are not thread safe
|
const std::lock_guard<std::recursive_mutex> lock(dbghelp_lock); // all dbghelp functions are not thread safe
|
||||||
alignas(SYMBOL_INFO) char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
alignas(SYMBOL_INFO) char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||||
SYMBOL_INFO* symbol = (SYMBOL_INFO*)buffer;
|
SYMBOL_INFO* symbol = (SYMBOL_INFO*)buffer;
|
||||||
@ -390,7 +390,7 @@ namespace dbghelp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames) {
|
||||||
const std::lock_guard<std::recursive_mutex> lock(dbghelp_lock); // all dbghelp functions are not thread safe
|
const std::lock_guard<std::recursive_mutex> lock(dbghelp_lock); // all dbghelp functions are not thread safe
|
||||||
std::vector<stacktrace_frame> trace;
|
std::vector<stacktrace_frame> trace;
|
||||||
trace.reserve(frames.size());
|
trace.reserve(frames.size());
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace libdl {
|
namespace libdl {
|
||||||
stacktrace_frame resolve_frame(const std::uintptr_t addr) {
|
stacktrace_frame resolve_frame(const frame_ptr addr) {
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
if(dladdr(reinterpret_cast<void*>(addr), &info)) { // thread-safe
|
if(dladdr(reinterpret_cast<void*>(addr), &info)) { // thread-safe
|
||||||
return {
|
return {
|
||||||
@ -33,7 +33,7 @@ namespace libdl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames) {
|
||||||
std::vector<stacktrace_frame> trace;
|
std::vector<stacktrace_frame> trace;
|
||||||
trace.reserve(frames.size());
|
trace.reserve(frames.size());
|
||||||
for(const auto frame : frames) {
|
for(const auto frame : frames) {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ namespace libbacktrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions
|
// TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions
|
||||||
stacktrace_frame resolve_frame(const std::uintptr_t addr) {
|
stacktrace_frame resolve_frame(const frame_ptr addr) {
|
||||||
try {
|
try {
|
||||||
stacktrace_frame frame;
|
stacktrace_frame frame;
|
||||||
frame.column = UINT_LEAST32_MAX;
|
frame.column = UINT_LEAST32_MAX;
|
||||||
@ -85,7 +85,7 @@ namespace libbacktrace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames) {
|
||||||
std::vector<stacktrace_frame> trace;
|
std::vector<stacktrace_frame> trace;
|
||||||
trace.reserve(frames.size());
|
trace.reserve(frames.size());
|
||||||
for(const auto frame : frames) {
|
for(const auto frame : frames) {
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace nothing {
|
namespace nothing {
|
||||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames) {
|
||||||
return std::vector<stacktrace_frame>(frames.size(), null_frame);
|
return std::vector<stacktrace_frame>(frames.size(), null_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace detail {
|
|||||||
constexpr std::size_t hard_max_frames = 100;
|
constexpr std::size_t hard_max_frames = 100;
|
||||||
#endif
|
#endif
|
||||||
CPPTRACE_FORCE_NO_INLINE
|
CPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth);
|
std::vector<frame_ptr> capture_frames(std::size_t skip, std::size_t max_depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ namespace detail {
|
|||||||
#pragma warning(disable: 4740) // warning C4740: flow in or out of inline asm code suppresses global optimization
|
#pragma warning(disable: 4740) // warning C4740: flow in or out of inline asm code suppresses global optimization
|
||||||
#endif
|
#endif
|
||||||
CPPTRACE_FORCE_NO_INLINE
|
CPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth) {
|
std::vector<frame_ptr> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||||
skip++;
|
skip++;
|
||||||
// https://jpassing.com/2008/03/12/walking-the-stack-of-the-current-thread/
|
// https://jpassing.com/2008/03/12/walking-the-stack-of-the-current-thread/
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ namespace detail {
|
|||||||
#error "Cpptrace: StackWalk64 not supported for this platform yet"
|
#error "Cpptrace: StackWalk64 not supported for this platform yet"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<std::uintptr_t> trace;
|
std::vector<frame_ptr> trace;
|
||||||
|
|
||||||
// Dbghelp is is single-threaded, so acquire a lock.
|
// Dbghelp is is single-threaded, so acquire a lock.
|
||||||
static std::mutex mutex;
|
static std::mutex mutex;
|
||||||
@ -138,7 +138,7 @@ namespace detail {
|
|||||||
// On x86/x64/arm, as far as I can tell, the frame return address is always one after the call
|
// On x86/x64/arm, as far as I can tell, the frame return address is always one after the call
|
||||||
// So we just decrement to get the pc back inside the `call` / `bl`
|
// So we just decrement to get the pc back inside the `call` / `bl`
|
||||||
// This is done with _Unwind too but conditionally based on info from _Unwind_GetIPInfo.
|
// This is done with _Unwind too but conditionally based on info from _Unwind_GetIPInfo.
|
||||||
trace.push_back(to_uintptr(frame.AddrPC.Offset) - 1);
|
trace.push_back(to_frame_ptr(frame.AddrPC.Offset) - 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// base
|
// base
|
||||||
|
|||||||
@ -13,17 +13,17 @@
|
|||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
CPPTRACE_FORCE_NO_INLINE
|
CPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth) {
|
std::vector<frame_ptr> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||||
skip++;
|
skip++;
|
||||||
std::vector<void*> addrs(std::min(hard_max_frames, skip + max_depth), nullptr);
|
std::vector<void*> addrs(std::min(hard_max_frames, skip + max_depth), nullptr);
|
||||||
const int n_frames = backtrace(addrs.data(), static_cast<int>(addrs.size())); // thread safe
|
const int n_frames = backtrace(addrs.data(), static_cast<int>(addrs.size())); // thread safe
|
||||||
// I hate the copy here but it's the only way that isn't UB
|
// I hate the copy here but it's the only way that isn't UB
|
||||||
std::vector<std::uintptr_t> frames(n_frames - skip, 0);
|
std::vector<frame_ptr> frames(n_frames - skip, 0);
|
||||||
for(int i = skip; i < n_frames; i++) {
|
for(int i = skip; i < n_frames; i++) {
|
||||||
// On x86/x64/arm, as far as I can tell, the frame return address is always one after the call
|
// On x86/x64/arm, as far as I can tell, the frame return address is always one after the call
|
||||||
// So we just decrement to get the pc back inside the `call` / `bl`
|
// So we just decrement to get the pc back inside the `call` / `bl`
|
||||||
// This is done with _Unwind too but conditionally based on info from _Unwind_GetIPInfo.
|
// This is done with _Unwind too but conditionally based on info from _Unwind_GetIPInfo.
|
||||||
frames[i - skip] = reinterpret_cast<std::uintptr_t>(addrs[i]) - 1;
|
frames[i - skip] = reinterpret_cast<frame_ptr>(addrs[i]) - 1;
|
||||||
}
|
}
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
std::vector<std::uintptr_t> capture_frames(std::size_t, std::size_t) {
|
std::vector<frame_ptr> capture_frames(std::size_t, std::size_t) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,14 +17,14 @@ namespace detail {
|
|||||||
struct unwind_state {
|
struct unwind_state {
|
||||||
std::size_t skip;
|
std::size_t skip;
|
||||||
std::size_t count;
|
std::size_t count;
|
||||||
std::vector<std::uintptr_t>& vec;
|
std::vector<frame_ptr>& vec;
|
||||||
};
|
};
|
||||||
|
|
||||||
_Unwind_Reason_Code unwind_callback(_Unwind_Context* context, void* arg) {
|
_Unwind_Reason_Code unwind_callback(_Unwind_Context* context, void* arg) {
|
||||||
unwind_state& state = *static_cast<unwind_state*>(arg);
|
unwind_state& state = *static_cast<unwind_state*>(arg);
|
||||||
if(state.skip) {
|
if(state.skip) {
|
||||||
state.skip--;
|
state.skip--;
|
||||||
if(_Unwind_GetIP(context) == std::uintptr_t(0)) {
|
if(_Unwind_GetIP(context) == frame_ptr(0)) {
|
||||||
return _URC_END_OF_STACK;
|
return _URC_END_OF_STACK;
|
||||||
} else {
|
} else {
|
||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
@ -36,11 +36,11 @@ namespace detail {
|
|||||||
"Somehow cpptrace::detail::unwind_callback is overflowing a vector"
|
"Somehow cpptrace::detail::unwind_callback is overflowing a vector"
|
||||||
);
|
);
|
||||||
int is_before_instruction = 0;
|
int is_before_instruction = 0;
|
||||||
std::uintptr_t ip = _Unwind_GetIPInfo(context, &is_before_instruction);
|
frame_ptr ip = _Unwind_GetIPInfo(context, &is_before_instruction);
|
||||||
if(!is_before_instruction && ip != std::uintptr_t(0)) {
|
if(!is_before_instruction && ip != frame_ptr(0)) {
|
||||||
ip--;
|
ip--;
|
||||||
}
|
}
|
||||||
if (ip == std::uintptr_t(0)) {
|
if (ip == frame_ptr(0)) {
|
||||||
return _URC_END_OF_STACK;
|
return _URC_END_OF_STACK;
|
||||||
} else {
|
} else {
|
||||||
// TODO: push_back?...
|
// TODO: push_back?...
|
||||||
@ -54,8 +54,8 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CPPTRACE_FORCE_NO_INLINE
|
CPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth) {
|
std::vector<frame_ptr> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||||
std::vector<std::uintptr_t> frames(std::min(hard_max_frames, max_depth), 0);
|
std::vector<frame_ptr> frames(std::min(hard_max_frames, max_depth), 0);
|
||||||
unwind_state state{skip + 1, 0, frames};
|
unwind_state state{skip + 1, 0, frames};
|
||||||
_Unwind_Backtrace(unwind_callback, &state); // presumably thread-safe
|
_Unwind_Backtrace(unwind_callback, &state); // presumably thread-safe
|
||||||
frames.resize(state.count);
|
frames.resize(state.count);
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
namespace cpptrace {
|
namespace cpptrace {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
CPPTRACE_FORCE_NO_INLINE
|
CPPTRACE_FORCE_NO_INLINE
|
||||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth) {
|
std::vector<frame_ptr> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||||
std::vector<void*> addrs(std::min(hard_max_frames, max_depth), nullptr);
|
std::vector<void*> addrs(std::min(hard_max_frames, max_depth), nullptr);
|
||||||
int n_frames = CaptureStackBackTrace(
|
int n_frames = CaptureStackBackTrace(
|
||||||
static_cast<ULONG>(skip + 1),
|
static_cast<ULONG>(skip + 1),
|
||||||
@ -28,12 +28,12 @@ namespace detail {
|
|||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
// I hate the copy here but it's the only way that isn't UB
|
// I hate the copy here but it's the only way that isn't UB
|
||||||
std::vector<std::uintptr_t> frames(n_frames, 0);
|
std::vector<frame_ptr> frames(n_frames, 0);
|
||||||
for(std::size_t i = 0; i < n_frames; i++) {
|
for(std::size_t i = 0; i < n_frames; i++) {
|
||||||
// On x86/x64/arm, as far as I can tell, the frame return address is always one after the call
|
// On x86/x64/arm, as far as I can tell, the frame return address is always one after the call
|
||||||
// So we just decrement to get the pc back inside the `call` / `bl`
|
// So we just decrement to get the pc back inside the `call` / `bl`
|
||||||
// This is done with _Unwind too but conditionally based on info from _Unwind_GetIPInfo.
|
// This is done with _Unwind too but conditionally based on info from _Unwind_GetIPInfo.
|
||||||
frames[i] = reinterpret_cast<std::uintptr_t>(addrs[i]) - 1;
|
frames[i] = reinterpret_cast<frame_ptr>(addrs[i]) - 1;
|
||||||
}
|
}
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user