More std::
This commit is contained in:
parent
e5ed083996
commit
ae5d2392fe
@ -27,7 +27,7 @@ namespace cpptrace {
|
||||
struct stacktrace;
|
||||
|
||||
struct raw_trace {
|
||||
std::vector<uintptr_t> frames;
|
||||
std::vector<std::uintptr_t> frames;
|
||||
CPPTRACE_API static raw_trace current(std::uint_least32_t skip = 0);
|
||||
CPPTRACE_API static raw_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
|
||||
CPPTRACE_API object_trace resolve_object_trace() const;
|
||||
@ -35,8 +35,8 @@ namespace cpptrace {
|
||||
CPPTRACE_API void clear();
|
||||
CPPTRACE_API bool empty() const noexcept;
|
||||
|
||||
using iterator = std::vector<uintptr_t>::iterator;
|
||||
using const_iterator = std::vector<uintptr_t>::const_iterator;
|
||||
using iterator = std::vector<std::uintptr_t>::iterator;
|
||||
using const_iterator = std::vector<std::uintptr_t>::const_iterator;
|
||||
inline iterator begin() noexcept { return frames.begin(); }
|
||||
inline iterator end() noexcept { return frames.end(); }
|
||||
inline const_iterator begin() const noexcept { return frames.begin(); }
|
||||
@ -48,8 +48,8 @@ namespace cpptrace {
|
||||
struct object_frame {
|
||||
std::string obj_path;
|
||||
std::string symbol;
|
||||
uintptr_t raw_address = 0;
|
||||
uintptr_t obj_address = 0;
|
||||
std::uintptr_t raw_address = 0;
|
||||
std::uintptr_t obj_address = 0;
|
||||
};
|
||||
|
||||
struct object_trace {
|
||||
@ -71,7 +71,7 @@ namespace cpptrace {
|
||||
};
|
||||
|
||||
struct stacktrace_frame {
|
||||
uintptr_t address;
|
||||
std::uintptr_t address;
|
||||
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::string filename;
|
||||
@ -183,13 +183,13 @@ namespace cpptrace {
|
||||
protected:
|
||||
explicit exception_with_message(
|
||||
std::string&& message_arg,
|
||||
uint32_t skip
|
||||
std::uint32_t skip
|
||||
) noexcept : exception(skip + 1), message(std::move(message_arg)) {}
|
||||
|
||||
explicit exception_with_message(
|
||||
std::string&& message_arg,
|
||||
uint_least32_t skip,
|
||||
uint_least32_t max_depth
|
||||
std::uint_least32_t skip,
|
||||
std::uint_least32_t max_depth
|
||||
) noexcept : exception(skip + 1, max_depth), message(std::move(message_arg)) {}
|
||||
|
||||
public:
|
||||
|
||||
@ -118,7 +118,7 @@ namespace cpptrace {
|
||||
stream
|
||||
<< std::hex
|
||||
<< "0x"
|
||||
<< std::setw(2 * sizeof(uintptr_t))
|
||||
<< std::setw(2 * sizeof(std::uintptr_t))
|
||||
<< std::setfill('0')
|
||||
<< frame.address
|
||||
<< std::dec
|
||||
@ -190,7 +190,7 @@ namespace cpptrace {
|
||||
<< std::hex
|
||||
<< blue
|
||||
<< "0x"
|
||||
<< std::setw(2 * sizeof(uintptr_t))
|
||||
<< std::setw(2 * sizeof(std::uintptr_t))
|
||||
<< std::setfill('0')
|
||||
<< frame.address
|
||||
<< std::dec
|
||||
@ -301,7 +301,7 @@ namespace cpptrace {
|
||||
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
|
||||
stacktrace generate_trace(std::uint32_t skip, std::uint_least32_t max_depth) {
|
||||
try {
|
||||
std::vector<uintptr_t> frames = detail::capture_frames(skip + 1, max_depth);
|
||||
std::vector<std::uintptr_t> frames = detail::capture_frames(skip + 1, max_depth);
|
||||
std::vector<stacktrace_frame> trace = detail::resolve_frames(frames);
|
||||
for(auto& frame : trace) {
|
||||
frame.symbol = detail::demangle(frame.symbol);
|
||||
@ -406,7 +406,7 @@ namespace cpptrace {
|
||||
} catch(const std::exception& e) {
|
||||
if(!detail::should_absorb_trace_exceptions()) {
|
||||
// TODO: Append to message somehow
|
||||
fprintf(
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"Cpptrace: Exception ocurred while resolving trace in cpptrace::exception object:\n%s\n",
|
||||
e.what()
|
||||
@ -450,7 +450,7 @@ namespace cpptrace {
|
||||
} catch(const std::exception& e) {
|
||||
if(!detail::should_absorb_trace_exceptions()) {
|
||||
// TODO: Append to message somehow
|
||||
fprintf(
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"Exception ocurred while resolving trace in cpptrace::exception object:\n%s\n",
|
||||
e.what()
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
#include "demangle.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
@ -51,13 +51,13 @@ namespace cpptrace {
|
||||
namespace detail {
|
||||
// Placed here instead of utils because it's used by error.hpp and utils.hpp
|
||||
template<typename... T> std::string stringf(T... args) {
|
||||
int length = snprintf(nullptr, 0, args...);
|
||||
int length = std::snprintf(nullptr, 0, args...);
|
||||
if(length < 0) {
|
||||
throw std::logic_error("invalid arguments to stringf");
|
||||
}
|
||||
std::string str(length, 0);
|
||||
// .data is const char* in c++11, but &str[0] should be legal
|
||||
snprintf(&str[0], length + 1, args...);
|
||||
std::snprintf(&str[0], length + 1, args...);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
@ -260,7 +260,7 @@ namespace libdwarf {
|
||||
return;
|
||||
}
|
||||
VERIFY(res == DW_DLV_OK);
|
||||
for(size_t i = 0 ; i < rnglists_entries; i++) {
|
||||
for(std::size_t i = 0 ; i < rnglists_entries; i++) {
|
||||
unsigned entrylen = 0;
|
||||
unsigned rle_value_out = 0;
|
||||
Dwarf_Unsigned raw1 = 0;
|
||||
@ -415,7 +415,7 @@ namespace libdwarf {
|
||||
}
|
||||
|
||||
void print() const {
|
||||
fprintf(
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"%08llx %s %s\n",
|
||||
to_ull(get_global_offset()),
|
||||
|
||||
@ -25,9 +25,9 @@ namespace detail {
|
||||
}
|
||||
|
||||
template<std::size_t Bits>
|
||||
static 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,
|
||||
FILE* file,
|
||||
std::FILE* file,
|
||||
bool is_little_endian
|
||||
) {
|
||||
static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument");
|
||||
@ -49,17 +49,17 @@ namespace detail {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uintptr_t elf_get_module_image_base(const std::string& obj_path) {
|
||||
auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||
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);
|
||||
if(file == nullptr) {
|
||||
throw file_error("Unable to read object file " + obj_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);
|
||||
bool is_64 = load_bytes<uint8_t>(file, 4) == 2;
|
||||
bool is_little_endian = load_bytes<uint8_t>(file, 5) == 1;
|
||||
VERIFY(load_bytes<uint8_t>(file, 6) == 1, "Unexpected ELF endianness " + obj_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);
|
||||
// get image base
|
||||
if(is_64) {
|
||||
return elf_get_module_image_base_from_program_table<64>(obj_path, file, is_little_endian);
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#ifndef ERROR_HPP
|
||||
#define ERROR_HPP
|
||||
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
static bool is_mach_o(uint32_t magic) {
|
||||
static bool is_mach_o(std::uint32_t magic) {
|
||||
switch(magic) {
|
||||
case FAT_MAGIC:
|
||||
case FAT_CIGAM:
|
||||
@ -37,17 +37,17 @@ namespace detail {
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_fat_magic(uint32_t magic) {
|
||||
static bool is_fat_magic(std::uint32_t magic) {
|
||||
return magic == FAT_MAGIC || magic == FAT_CIGAM;
|
||||
}
|
||||
|
||||
// Based on https://github.com/AlexDenisov/segment_dumper/blob/master/main.c
|
||||
// and https://lowlevelbits.org/parsing-mach-o-files/
|
||||
static bool is_magic_64(uint32_t magic) {
|
||||
static bool is_magic_64(std::uint32_t magic) {
|
||||
return magic == MH_MAGIC_64 || magic == MH_CIGAM_64;
|
||||
}
|
||||
|
||||
static bool should_swap_bytes(uint32_t magic) {
|
||||
static bool should_swap_bytes(std::uint32_t magic) {
|
||||
return magic == MH_CIGAM || magic == MH_CIGAM_64 || magic == FAT_CIGAM;
|
||||
}
|
||||
|
||||
@ -74,8 +74,8 @@ namespace detail {
|
||||
#endif
|
||||
|
||||
template<std::size_t Bits>
|
||||
static optional<uintptr_t> macho_get_text_vmaddr_mach(
|
||||
FILE* obj_file,
|
||||
static optional<std::uintptr_t> macho_get_text_vmaddr_mach(
|
||||
std::FILE* obj_file,
|
||||
const std::string& obj_path,
|
||||
off_t offset,
|
||||
bool should_swap,
|
||||
@ -84,15 +84,15 @@ namespace detail {
|
||||
static_assert(Bits == 32 || Bits == 64, "Unexpected Bits argument");
|
||||
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;
|
||||
uint32_t ncmds;
|
||||
std::uint32_t ncmds;
|
||||
off_t load_commands_offset = offset;
|
||||
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);
|
||||
if(should_swap) {
|
||||
swap_mach_header(header);
|
||||
}
|
||||
thread_local static struct LP(mach_header)* mhp = _NSGetMachExecuteHeader();
|
||||
//fprintf(
|
||||
//std::fprintf(
|
||||
// stderr,
|
||||
// "----> %d %d; %d %d\n",
|
||||
// header.cputype,
|
||||
@ -114,7 +114,7 @@ namespace detail {
|
||||
load_commands_offset += header_size;
|
||||
// iterate load commands
|
||||
off_t actual_offset = load_commands_offset;
|
||||
for(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);
|
||||
if(should_swap) {
|
||||
swap_load_command(&cmd, NX_UnknownByteOrder);
|
||||
@ -124,7 +124,7 @@ namespace detail {
|
||||
if(should_swap) {
|
||||
swap_segment_command(segment);
|
||||
}
|
||||
if(strcmp(segment.segname, "__TEXT") == 0) {
|
||||
if(std::strcmp(segment.segname, "__TEXT") == 0) {
|
||||
return segment.vmaddr;
|
||||
}
|
||||
actual_offset += cmd.cmdsize;
|
||||
@ -134,23 +134,27 @@ namespace detail {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 arch_size = sizeof(fat_arch);
|
||||
static std::uintptr_t macho_get_text_vmaddr_fat(
|
||||
std::FILE* obj_file,
|
||||
const std::string& obj_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);
|
||||
if(should_swap) {
|
||||
swap_fat_header(&header, NX_UnknownByteOrder);
|
||||
}
|
||||
off_t arch_offset = (off_t)header_size;
|
||||
optional<uintptr_t> text_vmaddr;
|
||||
for(uint32_t i = 0; i < header.nfat_arch; i++) {
|
||||
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);
|
||||
if(should_swap) {
|
||||
swap_fat_arch(&arch, 1, NX_UnknownByteOrder);
|
||||
}
|
||||
off_t mach_header_offset = (off_t)arch.offset;
|
||||
arch_offset += arch_size;
|
||||
uint32_t magic = load_bytes<uint32_t>(obj_file, mach_header_offset);
|
||||
std::uint32_t magic = load_bytes<std::uint32_t>(obj_file, mach_header_offset);
|
||||
if(is_magic_64(magic)) {
|
||||
text_vmaddr = macho_get_text_vmaddr_mach<64>(
|
||||
obj_file,
|
||||
@ -177,13 +181,13 @@ namespace detail {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
if(file == nullptr) {
|
||||
throw file_error("Unable to read object file " + obj_path);
|
||||
}
|
||||
uint32_t magic = load_bytes<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);
|
||||
bool is_64 = is_magic_64(magic);
|
||||
bool should_swap = should_swap_bytes(magic);
|
||||
@ -199,33 +203,33 @@ namespace detail {
|
||||
}
|
||||
|
||||
inline bool macho_is_fat(const std::string& obj_path) {
|
||||
auto file = raii_wrap(fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||
auto file = raii_wrap(std::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);
|
||||
std::uint32_t magic = load_bytes<std::uint32_t>(file, 0);
|
||||
return is_fat_magic(magic);
|
||||
}
|
||||
|
||||
// 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(fopen(obj_path.c_str(), "rb"), file_deleter);
|
||||
auto file = raii_wrap(std::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);
|
||||
std::uint32_t magic = load_bytes<std::uint32_t>(file, 0);
|
||||
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);
|
||||
std::size_t header_size = sizeof(fat_header);
|
||||
std::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++) {
|
||||
for(std::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);
|
||||
|
||||
@ -26,10 +26,10 @@ namespace cpptrace {
|
||||
namespace detail {
|
||||
#if IS_LINUX || IS_APPLE
|
||||
#if !IS_APPLE
|
||||
inline uintptr_t get_module_image_base(const std::string& obj_path) {
|
||||
inline std::uintptr_t get_module_image_base(const std::string& obj_path) {
|
||||
static std::mutex mutex;
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
static std::unordered_map<std::string, uintptr_t> cache;
|
||||
static std::unordered_map<std::string, std::uintptr_t> cache;
|
||||
auto it = cache.find(obj_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
|
||||
@ -42,13 +42,13 @@ namespace detail {
|
||||
}
|
||||
}
|
||||
#else
|
||||
inline uintptr_t get_module_image_base(const std::string& obj_path) {
|
||||
inline std::uintptr_t get_module_image_base(const std::string& obj_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, uintptr_t> cache;
|
||||
static std::unordered_map<std::string, std::uintptr_t> cache;
|
||||
auto it = cache.find(obj_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
|
||||
@ -62,11 +62,11 @@ namespace detail {
|
||||
}
|
||||
#endif
|
||||
// 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<uintptr_t>& addrs) {
|
||||
inline std::vector<object_frame> get_frames_object_info(const std::vector<std::uintptr_t>& addrs) {
|
||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||
std::vector<object_frame> frames;
|
||||
frames.reserve(addrs.size());
|
||||
for(const uintptr_t addr : addrs) {
|
||||
for(const std::uintptr_t addr : addrs) {
|
||||
Dl_info info;
|
||||
object_frame frame;
|
||||
frame.raw_address = addr;
|
||||
@ -75,7 +75,7 @@ namespace detail {
|
||||
// but we don't really need dli_saddr
|
||||
frame.obj_path = info.dli_fname;
|
||||
frame.obj_address = addr
|
||||
- reinterpret_cast<uintptr_t>(info.dli_fbase)
|
||||
- reinterpret_cast<std::uintptr_t>(info.dli_fbase)
|
||||
+ get_module_image_base(info.dli_fname);
|
||||
frame.symbol = info.dli_sname ?: "";
|
||||
}
|
||||
@ -92,11 +92,11 @@ namespace detail {
|
||||
if(it == cache.end()) {
|
||||
char path[MAX_PATH];
|
||||
if(GetModuleFileNameA(handle, path, sizeof(path))) {
|
||||
///fprintf(stderr, "path: %s base: %p\n", path, handle);
|
||||
///std::fprintf(stderr, "path: %s base: %p\n", path, handle);
|
||||
cache.insert(it, {handle, path});
|
||||
return path;
|
||||
} else {
|
||||
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());
|
||||
cache.insert(it, {handle, ""});
|
||||
return "";
|
||||
}
|
||||
@ -105,10 +105,10 @@ namespace detail {
|
||||
}
|
||||
}
|
||||
|
||||
inline uintptr_t get_module_image_base(const std::string& obj_path) {
|
||||
inline std::uintptr_t get_module_image_base(const std::string& obj_path) {
|
||||
static std::mutex mutex;
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
static std::unordered_map<std::string, uintptr_t> cache;
|
||||
static std::unordered_map<std::string, std::uintptr_t> cache;
|
||||
auto it = cache.find(obj_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
|
||||
@ -122,11 +122,11 @@ namespace detail {
|
||||
}
|
||||
|
||||
// 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<uintptr_t>& addrs) {
|
||||
inline std::vector<object_frame> get_frames_object_info(const std::vector<std::uintptr_t>& addrs) {
|
||||
// reference: https://github.com/bminor/glibc/blob/master/debug/backtracesyms.c
|
||||
std::vector<object_frame> frames;
|
||||
frames.reserve(addrs.size());
|
||||
for(const uintptr_t addr : addrs) {
|
||||
for(const std::uintptr_t addr : addrs) {
|
||||
object_frame frame;
|
||||
frame.raw_address = addr;
|
||||
HMODULE handle;
|
||||
@ -138,10 +138,10 @@ namespace detail {
|
||||
)) {
|
||||
frame.obj_path = get_module_name(handle);
|
||||
frame.obj_address = addr
|
||||
- reinterpret_cast<uintptr_t>(handle)
|
||||
- reinterpret_cast<std::uintptr_t>(handle)
|
||||
+ get_module_image_base(frame.obj_path);
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
frames.push_back(frame);
|
||||
}
|
||||
|
||||
@ -26,22 +26,22 @@ namespace detail {
|
||||
}
|
||||
}
|
||||
|
||||
inline uintptr_t pe_get_module_image_base(const std::string& obj_path) {
|
||||
inline std::uintptr_t pe_get_module_image_base(const std::string& obj_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
|
||||
FILE* file_ptr;
|
||||
std::FILE* file_ptr;
|
||||
errno_t ret = fopen_s(&file_ptr, obj_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);
|
||||
}
|
||||
auto magic = load_bytes<std::array<char, 2>>(file, 0);
|
||||
VERIFY(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 " + obj_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(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 " + obj_path);
|
||||
WORD size_of_optional_header = pe_byteswap_if_needed(
|
||||
load_bytes<WORD>(file, nt_header_offset + 4 + 0x10) // file header + 0x10
|
||||
);
|
||||
@ -56,7 +56,7 @@ namespace detail {
|
||||
// finally get image base
|
||||
if(optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
// 32 bit
|
||||
return to<uintptr_t>(
|
||||
return to<std::uintptr_t>(
|
||||
pe_byteswap_if_needed(
|
||||
load_bytes<DWORD>(file, nt_header_offset + 0x18 + 0x1c) // optional header + 0x1c
|
||||
)
|
||||
@ -64,7 +64,7 @@ namespace detail {
|
||||
} else {
|
||||
// 64 bit
|
||||
// I get an "error: 'QWORD' was not declared in this scope" for some reason when using QWORD
|
||||
return to<uintptr_t>(
|
||||
return to<std::uintptr_t>(
|
||||
pe_byteswap_if_needed(
|
||||
load_bytes<unsigned __int64>(file, nt_header_offset + 0x18 + 0x18) // optional header + 0x18
|
||||
)
|
||||
|
||||
@ -38,7 +38,7 @@ namespace detail {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int fileno(FILE* stream) {
|
||||
inline int fileno(std::FILE* stream) {
|
||||
#if IS_WINDOWS
|
||||
return _fileno(stream);
|
||||
#else
|
||||
@ -48,8 +48,8 @@ namespace detail {
|
||||
|
||||
inline std::vector<std::string> split(const std::string& str, const std::string& delims) {
|
||||
std::vector<std::string> vec;
|
||||
size_t old_pos = 0;
|
||||
size_t pos = 0;
|
||||
std::size_t old_pos = 0;
|
||||
std::size_t pos = 0;
|
||||
while((pos = str.find_first_of(delims, old_pos)) != std::string::npos) {
|
||||
vec.emplace_back(str.substr(old_pos, pos - old_pos));
|
||||
old_pos = pos + 1;
|
||||
@ -79,26 +79,26 @@ namespace detail {
|
||||
if(str.empty()) {
|
||||
return "";
|
||||
}
|
||||
const size_t left = str.find_first_not_of(whitespace);
|
||||
const size_t right = str.find_last_not_of(whitespace) + 1;
|
||||
const std::size_t left = str.find_first_not_of(whitespace);
|
||||
const std::size_t right = str.find_last_not_of(whitespace) + 1;
|
||||
return str.substr(left, right - left);
|
||||
}
|
||||
|
||||
inline std::string to_hex(uintptr_t addr) {
|
||||
inline std::string to_hex(std::uintptr_t addr) {
|
||||
std::stringstream sstream;
|
||||
sstream<<std::hex<<addr;
|
||||
return std::move(sstream).str();
|
||||
}
|
||||
|
||||
inline bool is_little_endian() {
|
||||
uint16_t num = 0x1;
|
||||
const auto* ptr = (uint8_t*)#
|
||||
std::uint16_t num = 0x1;
|
||||
const auto* ptr = (std::uint8_t*)#
|
||||
return ptr[0] == 1;
|
||||
}
|
||||
|
||||
// Modified from
|
||||
// https://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c
|
||||
template<typename T, size_t N>
|
||||
template<typename T, std::size_t N>
|
||||
struct byte_swapper;
|
||||
|
||||
template<typename T>
|
||||
@ -171,10 +171,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(FILE* obj_file, off_t offset) {
|
||||
T load_bytes(std::FILE* obj_file, off_t offset) {
|
||||
T object;
|
||||
VERIFY(fseek(obj_file, offset, SEEK_SET) == 0, "fseek error");
|
||||
VERIFY(fread(&object, sizeof(T), 1, obj_file) == 1, "fread error");
|
||||
VERIFY(std::fseek(obj_file, offset, SEEK_SET) == 0, "fseek error");
|
||||
VERIFY(std::fread(&object, sizeof(T), 1, obj_file) == 1, "fread error");
|
||||
return object;
|
||||
}
|
||||
|
||||
@ -352,8 +352,8 @@ namespace detail {
|
||||
return static_cast<unsigned long long>(t);
|
||||
}
|
||||
template<typename T>
|
||||
uintptr_t to_uintptr(T t) {
|
||||
return static_cast<uintptr_t>(t);
|
||||
std::uintptr_t to_uintptr(T t) {
|
||||
return static_cast<std::uintptr_t>(t);
|
||||
}
|
||||
|
||||
// A way to cast to U without "warning: useless cast to type"
|
||||
@ -424,7 +424,7 @@ namespace detail {
|
||||
return raii_wrapper<typename std::remove_reference<T>::type, D>(obj, deleter);
|
||||
}
|
||||
|
||||
inline void file_deleter(FILE* ptr) {
|
||||
inline void file_deleter(std::FILE* ptr) {
|
||||
fclose(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ namespace detail {
|
||||
|
||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE
|
||||
namespace libbacktrace {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
||||
}
|
||||
#endif
|
||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
|
||||
@ -31,7 +31,7 @@ namespace detail {
|
||||
#endif
|
||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDL
|
||||
namespace libdl {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
||||
}
|
||||
#endif
|
||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE
|
||||
@ -41,18 +41,18 @@ namespace detail {
|
||||
#endif
|
||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_DBGHELP
|
||||
namespace dbghelp {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
||||
}
|
||||
#endif
|
||||
#ifdef CPPTRACE_GET_SYMBOLS_WITH_NOTHING
|
||||
namespace nothing {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames);
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ namespace detail {
|
||||
|| defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) \
|
||||
|| defined(CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE)
|
||||
// actually need to go backwards to a void*
|
||||
std::vector<uintptr_t> raw_frames(frames.size());
|
||||
std::vector<std::uintptr_t> raw_frames(frames.size());
|
||||
for(std::size_t i = 0; i < frames.size(); i++) {
|
||||
raw_frames[i] = frames[i].raw_address;
|
||||
}
|
||||
@ -82,7 +82,7 @@ namespace detail {
|
||||
return trace;
|
||||
}
|
||||
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames) {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
||||
#if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) \
|
||||
|| defined(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
|
||||
auto dlframes = get_frames_object_info(frames);
|
||||
|
||||
@ -127,7 +127,7 @@ namespace addr2line {
|
||||
std::string output;
|
||||
constexpr int buffer_size = 4096;
|
||||
char buffer[buffer_size];
|
||||
size_t count = 0;
|
||||
std::size_t count = 0;
|
||||
while((count = read(output_pipe.read_end, buffer, buffer_size)) > 0) {
|
||||
output.insert(output.end(), buffer, buffer + count);
|
||||
}
|
||||
@ -145,12 +145,12 @@ namespace addr2line {
|
||||
// TODO: Popen is a hack. Implement properly with CreateProcess and pipes later.
|
||||
checked = true;
|
||||
#ifdef CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH
|
||||
FILE* p = popen("addr2line --version", "r");
|
||||
std::FILE* p = popen("addr2line --version", "r");
|
||||
#else
|
||||
#ifndef CPPTRACE_ADDR2LINE_PATH
|
||||
#error "CPPTRACE_ADDR2LINE_PATH must be defined if CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH is not"
|
||||
#endif
|
||||
FILE* p = popen(CPPTRACE_ADDR2LINE_PATH " --version", "r");
|
||||
std::FILE* p = popen(CPPTRACE_ADDR2LINE_PATH " --version", "r");
|
||||
#endif
|
||||
if(p) {
|
||||
has_addr2line = pclose(p) == 0;
|
||||
@ -163,12 +163,12 @@ namespace addr2line {
|
||||
// TODO: Popen is a hack. Implement properly with CreateProcess and pipes later.
|
||||
///fprintf(stderr, ("addr2line -e " + executable + " -fCp " + addresses + "\n").c_str());
|
||||
#ifdef CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH
|
||||
FILE* p = popen(("addr2line -e \"" + executable + "\" -fCp " + addresses).c_str(), "r");
|
||||
std::FILE* p = popen(("addr2line -e \"" + executable + "\" -fCp " + addresses).c_str(), "r");
|
||||
#else
|
||||
#ifndef CPPTRACE_ADDR2LINE_PATH
|
||||
#error "CPPTRACE_ADDR2LINE_PATH must be defined if CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH is not"
|
||||
#endif
|
||||
FILE* p = popen(
|
||||
std::FILE* p = popen(
|
||||
(CPPTRACE_ADDR2LINE_PATH " -e \"" + executable + "\" -fCp " + addresses).c_str(),
|
||||
"r"
|
||||
);
|
||||
@ -176,8 +176,8 @@ namespace addr2line {
|
||||
std::string output;
|
||||
constexpr int buffer_size = 4096;
|
||||
char buffer[buffer_size];
|
||||
size_t count = 0;
|
||||
while((count = fread(buffer, 1, buffer_size, p)) > 0) {
|
||||
std::size_t count = 0;
|
||||
while((count = std::fread(buffer, 1, buffer_size, p)) > 0) {
|
||||
output.insert(output.end(), buffer, buffer + count);
|
||||
}
|
||||
pclose(p);
|
||||
@ -186,7 +186,7 @@ namespace addr2line {
|
||||
}
|
||||
#endif
|
||||
|
||||
void update_trace(const std::string& line, size_t entry_index, const collated_vec& entries_vec) {
|
||||
void update_trace(const std::string& line, std::size_t entry_index, const collated_vec& entries_vec) {
|
||||
#if !IS_APPLE
|
||||
// Result will be of the form "<symbol> at path:line"
|
||||
// The path may be ?? if addr2line cannot resolve, line may be ?
|
||||
@ -268,7 +268,7 @@ namespace addr2line {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames) {
|
||||
// TODO: Refactor better
|
||||
std::vector<stacktrace_frame> trace(frames.size(), null_frame);
|
||||
for(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;
|
||||
// Set what is known for now, and resolutions from addr2line should overwrite
|
||||
trace[i].filename = frames[i].obj_path;
|
||||
@ -298,7 +298,7 @@ namespace addr2line {
|
||||
}
|
||||
auto output = split(trim(resolve_addresses(address_input, object_name)), "\n");
|
||||
VERIFY(output.size() == entries_vec.size());
|
||||
for(size_t i = 0; i < output.size(); i++) {
|
||||
for(std::size_t i = 0; i < output.size(); i++) {
|
||||
update_trace(output[i], i, entries_vec);
|
||||
}
|
||||
} catch(...) { // NOSONAR
|
||||
|
||||
@ -234,7 +234,7 @@ namespace dbghelp {
|
||||
return {return_type.base, "()" + return_type.extent};
|
||||
} else {
|
||||
// alignment should be fine
|
||||
size_t sz = sizeof(TI_FINDCHILDREN_PARAMS) +
|
||||
std::size_t sz = sizeof(TI_FINDCHILDREN_PARAMS) +
|
||||
(n_children) * sizeof(TI_FINDCHILDREN_PARAMS::ChildId[0]);
|
||||
TI_FINDCHILDREN_PARAMS* children = (TI_FINDCHILDREN_PARAMS*) new char[sz];
|
||||
children->Start = 0;
|
||||
@ -325,7 +325,7 @@ namespace dbghelp {
|
||||
std::recursive_mutex dbghelp_lock;
|
||||
|
||||
// TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions
|
||||
stacktrace_frame resolve_frame(HANDLE proc, uintptr_t addr) {
|
||||
stacktrace_frame resolve_frame(HANDLE proc, std::uintptr_t addr) {
|
||||
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)];
|
||||
SYMBOL_INFO* symbol = (SYMBOL_INFO*)buffer;
|
||||
@ -343,7 +343,7 @@ namespace dbghelp {
|
||||
// function fails but GetLastError returns ERROR_SUCCESS."
|
||||
// This is the stupidest fucking api I've ever worked with.
|
||||
if(SymSetContext(proc, &frame, nullptr) == FALSE && GetLastError() != ERROR_SUCCESS) {
|
||||
fprintf(stderr, "Stack trace: Internal error while calling SymSetContext\n");
|
||||
std::fprintf(stderr, "Stack trace: Internal error while calling SymSetContext\n");
|
||||
return {
|
||||
addr,
|
||||
static_cast<std::uint_least32_t>(line.LineNumber),
|
||||
@ -390,7 +390,7 @@ namespace dbghelp {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames) {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
||||
const std::lock_guard<std::recursive_mutex> lock(dbghelp_lock); // all dbghelp functions are not thread safe
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
namespace libdl {
|
||||
stacktrace_frame resolve_frame(const uintptr_t addr) {
|
||||
stacktrace_frame resolve_frame(const std::uintptr_t addr) {
|
||||
Dl_info info;
|
||||
if(dladdr(reinterpret_cast<void*>(addr), &info)) { // thread-safe
|
||||
return {
|
||||
@ -33,7 +33,7 @@ namespace libdl {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames) {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
for(const auto frame : frames) {
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
namespace libbacktrace {
|
||||
int full_callback(void* data, uintptr_t address, const char* file, int line, const char* symbol) {
|
||||
int full_callback(void* data, std::uintptr_t address, const char* file, int line, const char* symbol) {
|
||||
stacktrace_frame& frame = *static_cast<stacktrace_frame*>(data);
|
||||
frame.address = address;
|
||||
frame.line = line;
|
||||
@ -29,7 +29,7 @@ namespace libbacktrace {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void syminfo_callback(void* data, uintptr_t address, const char* symbol, uintptr_t, uintptr_t) {
|
||||
void syminfo_callback(void* data, std::uintptr_t address, const char* symbol, std::uintptr_t, std::uintptr_t) {
|
||||
stacktrace_frame& frame = *static_cast<stacktrace_frame*>(data);
|
||||
frame.address = address;
|
||||
frame.line = 0;
|
||||
@ -55,7 +55,7 @@ namespace libbacktrace {
|
||||
}
|
||||
|
||||
// TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions
|
||||
stacktrace_frame resolve_frame(const uintptr_t addr) {
|
||||
stacktrace_frame resolve_frame(const std::uintptr_t addr) {
|
||||
try {
|
||||
stacktrace_frame frame;
|
||||
frame.column = UINT_LEAST32_MAX;
|
||||
@ -85,7 +85,7 @@ namespace libbacktrace {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames) {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
||||
std::vector<stacktrace_frame> trace;
|
||||
trace.reserve(frames.size());
|
||||
for(const auto frame : frames) {
|
||||
|
||||
@ -233,7 +233,7 @@ namespace libdwarf {
|
||||
);
|
||||
if(ret == DW_DLV_NO_ENTRY) {
|
||||
if(dump_dwarf) {
|
||||
fprintf(stderr, "End walk_dbg\n");
|
||||
std::fprintf(stderr, "End walk_dbg\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -253,7 +253,7 @@ namespace libdwarf {
|
||||
}
|
||||
}
|
||||
if(dump_dwarf) {
|
||||
fprintf(stderr, "End walk_compilation_units\n");
|
||||
std::fprintf(stderr, "End walk_compilation_units\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,7 +297,7 @@ namespace libdwarf {
|
||||
die,
|
||||
[this, pc, dwversion, &frame, &found] (const die_object& die) {
|
||||
if(dump_dwarf) {
|
||||
fprintf(
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"-------------> %08llx %s %s\n",
|
||||
to_ull(die.get_global_offset()),
|
||||
@ -307,11 +307,11 @@ namespace libdwarf {
|
||||
}
|
||||
if(!(die.get_tag() == DW_TAG_namespace || die.pc_in_die(dwversion, pc))) {
|
||||
if(dump_dwarf) {
|
||||
fprintf(stderr, "pc not in die\n");
|
||||
std::fprintf(stderr, "pc not in die\n");
|
||||
}
|
||||
} else {
|
||||
if(trace_dwarf) {
|
||||
fprintf(
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"%s %08llx %s\n",
|
||||
die.get_tag() == DW_TAG_namespace ? "pc maybe in die (namespace)" : "pc in die",
|
||||
@ -332,7 +332,7 @@ namespace libdwarf {
|
||||
}
|
||||
} else {
|
||||
if(dump_dwarf) {
|
||||
fprintf(stderr, "(no child)\n");
|
||||
std::fprintf(stderr, "(no child)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,7 +340,7 @@ namespace libdwarf {
|
||||
}
|
||||
);
|
||||
if(dump_dwarf) {
|
||||
fprintf(stderr, "End walk_die_list\n");
|
||||
std::fprintf(stderr, "End walk_die_list\n");
|
||||
}
|
||||
return found;
|
||||
}
|
||||
@ -384,7 +384,7 @@ namespace libdwarf {
|
||||
}
|
||||
);
|
||||
if(dump_dwarf) {
|
||||
fprintf(stderr, "End walk_die_list\n");
|
||||
std::fprintf(stderr, "End walk_die_list\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,7 +506,7 @@ namespace libdwarf {
|
||||
if(found_line) {
|
||||
Dwarf_Unsigned line_number = 0;
|
||||
VERIFY(wrap(dwarf_lineno, found_line, &line_number) == DW_DLV_OK);
|
||||
frame.line = static_cast<uint_least32_t>(line_number);
|
||||
frame.line = static_cast<std::uint_least32_t>(line_number);
|
||||
char* filename = nullptr;
|
||||
VERIFY(wrap(dwarf_linesrc, found_line, &filename) == DW_DLV_OK);
|
||||
auto wrapper = raii_wrap(
|
||||
@ -534,8 +534,8 @@ namespace libdwarf {
|
||||
stacktrace_frame& frame
|
||||
) {
|
||||
if(dump_dwarf) {
|
||||
fprintf(stderr, "%s\n", obj_path.c_str());
|
||||
fprintf(stderr, "%llx\n", to_ull(pc));
|
||||
std::fprintf(stderr, "%s\n", obj_path.c_str());
|
||||
std::fprintf(stderr, "%llx\n", to_ull(pc));
|
||||
}
|
||||
// Check for .debug_aranges for fast lookup
|
||||
if(aranges) {
|
||||
@ -553,7 +553,7 @@ namespace libdwarf {
|
||||
Dwarf_Half dwversion = 0;
|
||||
VERIFY(dwarf_get_version_of_die(cu_die.get(), &dwversion, &offset_size) == DW_DLV_OK);
|
||||
if(trace_dwarf) {
|
||||
fprintf(stderr, "Found CU in aranges\n");
|
||||
std::fprintf(stderr, "Found CU in aranges\n");
|
||||
cu_die.print();
|
||||
}
|
||||
retrieve_line_info(cu_die, pc, frame); // no offset for line info
|
||||
@ -570,11 +570,11 @@ namespace libdwarf {
|
||||
//cu_die.print();
|
||||
//fprintf(stderr, " %llx, %llx\n", p.first, p.second);
|
||||
if(trace_dwarf) {
|
||||
fprintf(stderr, "CU: %d %s\n", dwversion, cu_die.get_name().c_str());
|
||||
std::fprintf(stderr, "CU: %d %s\n", dwversion, cu_die.get_name().c_str());
|
||||
}
|
||||
if(cu_die.pc_in_die(dwversion, pc)) {
|
||||
if(trace_dwarf) {
|
||||
fprintf(
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"pc in die %08llx %s (now searching for %08llx)\n",
|
||||
to_ull(cu_die.get_global_offset()),
|
||||
@ -624,7 +624,7 @@ namespace libdwarf {
|
||||
frame.symbol = frame_info.symbol;
|
||||
frame.address = frame_info.raw_address;
|
||||
if(trace_dwarf) {
|
||||
fprintf(
|
||||
std::fprintf(
|
||||
stderr,
|
||||
"Starting resolution for %s %08llx %s\n",
|
||||
obj_path.c_str(),
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
namespace nothing {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<uintptr_t>& frames) {
|
||||
std::vector<stacktrace_frame> resolve_frames(const std::vector<std::uintptr_t>& frames) {
|
||||
return std::vector<stacktrace_frame>(frames.size(), null_frame);
|
||||
}
|
||||
|
||||
|
||||
@ -10,12 +10,12 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
#ifdef CPPTRACE_HARD_MAX_FRAMES
|
||||
constexpr size_t hard_max_frames = CPPTRACE_HARD_MAX_FRAMES;
|
||||
constexpr std::size_t hard_max_frames = CPPTRACE_HARD_MAX_FRAMES;
|
||||
#else
|
||||
constexpr size_t hard_max_frames = 100;
|
||||
constexpr std::size_t hard_max_frames = 100;
|
||||
#endif
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth);
|
||||
std::vector<std::uintptr_t> 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
|
||||
#endif
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
|
||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||
skip++;
|
||||
// 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"
|
||||
#endif
|
||||
|
||||
std::vector<uintptr_t> trace;
|
||||
std::vector<std::uintptr_t> trace;
|
||||
|
||||
// Dbghelp is is single-threaded, so acquire a lock.
|
||||
static std::mutex mutex;
|
||||
|
||||
@ -13,17 +13,17 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
|
||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||
skip++;
|
||||
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
|
||||
// I hate the copy here but it's the only way that isn't UB
|
||||
std::vector<uintptr_t> frames(n_frames - skip, 0);
|
||||
std::vector<std::uintptr_t> frames(n_frames - skip, 0);
|
||||
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
|
||||
// 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.
|
||||
frames[i - skip] = reinterpret_cast<uintptr_t>(addrs[i]) - 1;
|
||||
frames[i - skip] = reinterpret_cast<std::uintptr_t>(addrs[i]) - 1;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
std::vector<uintptr_t> capture_frames(size_t, size_t) {
|
||||
std::vector<std::uintptr_t> capture_frames(std::size_t, std::size_t) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,14 +17,14 @@ namespace detail {
|
||||
struct unwind_state {
|
||||
std::size_t skip;
|
||||
std::size_t count;
|
||||
std::vector<uintptr_t>& vec;
|
||||
std::vector<std::uintptr_t>& vec;
|
||||
};
|
||||
|
||||
_Unwind_Reason_Code unwind_callback(_Unwind_Context* context, void* arg) {
|
||||
unwind_state& state = *static_cast<unwind_state*>(arg);
|
||||
if(state.skip) {
|
||||
state.skip--;
|
||||
if(_Unwind_GetIP(context) == uintptr_t(0)) {
|
||||
if(_Unwind_GetIP(context) == std::uintptr_t(0)) {
|
||||
return _URC_END_OF_STACK;
|
||||
} else {
|
||||
return _URC_NO_REASON;
|
||||
@ -36,11 +36,11 @@ namespace detail {
|
||||
"Somehow cpptrace::detail::unwind_callback is overflowing a vector"
|
||||
);
|
||||
int is_before_instruction = 0;
|
||||
uintptr_t ip = _Unwind_GetIPInfo(context, &is_before_instruction);
|
||||
if(!is_before_instruction && ip != uintptr_t(0)) {
|
||||
std::uintptr_t ip = _Unwind_GetIPInfo(context, &is_before_instruction);
|
||||
if(!is_before_instruction && ip != std::uintptr_t(0)) {
|
||||
ip--;
|
||||
}
|
||||
if (ip == uintptr_t(0)) {
|
||||
if (ip == std::uintptr_t(0)) {
|
||||
return _URC_END_OF_STACK;
|
||||
} else {
|
||||
// TODO: push_back?...
|
||||
@ -54,8 +54,8 @@ namespace detail {
|
||||
}
|
||||
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
|
||||
std::vector<uintptr_t> frames(std::min(hard_max_frames, max_depth), 0);
|
||||
std::vector<std::uintptr_t> 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);
|
||||
unwind_state state{skip + 1, 0, frames};
|
||||
_Unwind_Backtrace(unwind_callback, &state); // presumably thread-safe
|
||||
frames.resize(state.count);
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
namespace cpptrace {
|
||||
namespace detail {
|
||||
CPPTRACE_FORCE_NO_INLINE
|
||||
std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
|
||||
std::vector<std::uintptr_t> capture_frames(std::size_t skip, std::size_t max_depth) {
|
||||
std::vector<void*> addrs(std::min(hard_max_frames, max_depth), nullptr);
|
||||
int n_frames = CaptureStackBackTrace(
|
||||
static_cast<ULONG>(skip + 1),
|
||||
@ -28,12 +28,12 @@ namespace detail {
|
||||
NULL
|
||||
);
|
||||
// I hate the copy here but it's the only way that isn't UB
|
||||
std::vector<uintptr_t> frames(n_frames, 0);
|
||||
std::vector<std::uintptr_t> frames(n_frames, 0);
|
||||
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
|
||||
// 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.
|
||||
frames[i] = reinterpret_cast<uintptr_t>(addrs[i]) - 1;
|
||||
frames[i] = reinterpret_cast<std::uintptr_t>(addrs[i]) - 1;
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user