Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 190 additions & 3 deletions include/boost/stacktrace/detail/libbacktrace_impls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
# include <backtrace.h>
#endif

#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
# include <boost/winapi/dll.hpp>
# include <boost/winapi/file_management.hpp>
# include "boost/winapi/access_rights.hpp"
# include "boost/winapi/handles.hpp"
#endif

namespace boost { namespace stacktrace { namespace detail {


Expand All @@ -46,14 +53,20 @@ inline void libbacktrace_syminfo_callback(void *data, uintptr_t pc, const char *

inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
pc_data& d = *static_cast<pc_data*>(data);
int return_value = 0;
if (d.filename && filename) {
*d.filename = filename;
return_value = 1;
}
if (d.function && function) {
*d.function = function;
return_value = 1;
}
d.line = static_cast<std::size_t>(lineno);
return 0;
if (d.line) {
return_value = 1;
}
return return_value;
}

inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) noexcept {
Expand Down Expand Up @@ -114,6 +127,180 @@ BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_loc
return state;
}

#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
[[nodiscard]] inline uintptr_t read_static_image_base(const char* file_path) noexcept
{
boost::winapi::HANDLE_ hfile = boost::winapi::CreateFileA(
file_path,
boost::winapi::GENERIC_READ_,
boost::winapi::FILE_SHARE_READ_,
nullptr,
boost::winapi::OPEN_EXISTING_,
boost::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr);

if (hfile == boost::winapi::INVALID_HANDLE_VALUE_) {
return 0;
}

// Use anonymous struct because boost::winapi doesn't have IMAGE_DOS_HEADER
// yet. Same for all other anonymous structs in this function.
struct /* _IMAGE_DOS_HEADER */ {
boost::winapi::WORD_ e_magic;
boost::winapi::WORD_ e_cblp;
boost::winapi::WORD_ e_cp;
boost::winapi::WORD_ e_crlc;
boost::winapi::WORD_ e_cparhdr;
boost::winapi::WORD_ e_minalloc;
boost::winapi::WORD_ e_maxalloc;
boost::winapi::WORD_ e_ss;
boost::winapi::WORD_ e_sp;
boost::winapi::WORD_ e_csum;
boost::winapi::WORD_ e_ip;
boost::winapi::WORD_ e_cs;
boost::winapi::WORD_ e_lfarlc;
boost::winapi::WORD_ e_ovno;
boost::winapi::WORD_ e_res[4];
boost::winapi::WORD_ e_oemid;
boost::winapi::WORD_ e_oeminfo;
boost::winapi::WORD_ e_res2[10];
boost::winapi::LONG_ e_lfanew;
} dos_header {};
boost::winapi::DWORD_ bytes_read = 0;

if (!boost::winapi::ReadFile(hfile, &dos_header, sizeof(dos_header),
&bytes_read, nullptr) || dos_header.e_magic != 0x5A4D /* IMAGE_DOS_SIGNATURE */) {
boost::winapi::CloseHandle(hfile);
return 0;
}

boost::winapi::SetFilePointer(hfile, dos_header.e_lfanew, nullptr, boost::winapi::FILE_BEGIN_);

boost::winapi::DWORD_ nt_signature = 0;
boost::winapi::ReadFile(hfile, &nt_signature, sizeof(nt_signature), &bytes_read, nullptr);

if (nt_signature != 0x00004550 /* IMAGE_NT_SIGNATURE */) {
boost::winapi::CloseHandle(hfile);
return 0;
}

struct /* _IMAGE_FILE_HEADER */ {
boost::winapi::WORD_ Machine;
boost::winapi::WORD_ NumberOfSections;
boost::winapi::DWORD_ TimeDateStamp;
boost::winapi::DWORD_ PointerToSymbolTable;
boost::winapi::DWORD_ NumberOfSymbols;
boost::winapi::WORD_ SizeOfOptionalHeader;
boost::winapi::WORD_ Characteristics;
} file_header {};
boost::winapi::ReadFile(hfile, &file_header, sizeof(file_header), &bytes_read, nullptr);

uintptr_t image_base = 0;
if (file_header.SizeOfOptionalHeader > 0) {
boost::winapi::WORD_ magic = 0;
boost::winapi::SetFilePointer(hfile, dos_header.e_lfanew + 4 + sizeof(file_header), nullptr, boost::winapi::FILE_BEGIN_);
boost::winapi::ReadFile(hfile, &magic, sizeof(magic), &bytes_read, nullptr);

typedef struct _IMAGE_DATA_DIRECTORY {
boost::winapi::DWORD_ VirtualAddress;
boost::winapi::DWORD_ Size;
} IMAGE_DATA_DIRECTORY;

if (magic == 0x10b /* IMAGE_NT_OPTIONAL_HDR32_MAGIC */) {
struct /* _IMAGE_OPTIONAL_HEADER */ {
boost::winapi::WORD_ Magic;
boost::winapi::BYTE_ MajorLinkerVersion;
boost::winapi::BYTE_ MinorLinkerVersion;
boost::winapi::DWORD_ SizeOfCode;
boost::winapi::DWORD_ SizeOfInitializedData;
boost::winapi::DWORD_ SizeOfUninitializedData;
boost::winapi::DWORD_ AddressOfEntryPoint;
boost::winapi::DWORD_ BaseOfCode;
boost::winapi::DWORD_ BaseOfData;
boost::winapi::DWORD_ ImageBase;
boost::winapi::DWORD_ SectionAlignment;
boost::winapi::DWORD_ FileAlignment;
boost::winapi::WORD_ MajorOperatingSystemVersion;
boost::winapi::WORD_ MinorOperatingSystemVersion;
boost::winapi::WORD_ MajorImageVersion;
boost::winapi::WORD_ MinorImageVersion;
boost::winapi::WORD_ MajorSubsystemVersion;
boost::winapi::WORD_ MinorSubsystemVersion;
boost::winapi::DWORD_ Win32VersionValue;
boost::winapi::DWORD_ SizeOfImage;
boost::winapi::DWORD_ SizeOfHeaders;
boost::winapi::DWORD_ CheckSum;
boost::winapi::WORD_ Subsystem;
boost::winapi::WORD_ DllCharacteristics;
boost::winapi::DWORD_ SizeOfStackReserve;
boost::winapi::DWORD_ SizeOfStackCommit;
boost::winapi::DWORD_ SizeOfHeapReserve;
boost::winapi::DWORD_ SizeOfHeapCommit;
boost::winapi::DWORD_ LoaderFlags;
boost::winapi::DWORD_ NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16 /* IMAGE_NUMBEROF_DIRECTORY_ENTRIES */];
} optional_header {};
boost::winapi::SetFilePointer(hfile, dos_header.e_lfanew + 4 + sizeof(file_header), nullptr, boost::winapi::FILE_BEGIN_);
boost::winapi::ReadFile(hfile, &optional_header, sizeof(optional_header), &bytes_read, nullptr);
image_base = optional_header.ImageBase;
} else if (magic == 0x20b /* IMAGE_NT_OPTIONAL_HDR64_MAGIC */) {
struct /* _IMAGE_OPTIONAL_HEADER64 */ {
boost::winapi::WORD_ Magic;
boost::winapi::BYTE_ MajorLinkerVersion;
boost::winapi::BYTE_ MinorLinkerVersion;
boost::winapi::DWORD_ SizeOfCode;
boost::winapi::DWORD_ SizeOfInitializedData;
boost::winapi::DWORD_ SizeOfUninitializedData;
boost::winapi::DWORD_ AddressOfEntryPoint;
boost::winapi::DWORD_ BaseOfCode;
boost::winapi::ULONGLONG_ ImageBase;
boost::winapi::DWORD_ SectionAlignment;
boost::winapi::DWORD_ FileAlignment;
boost::winapi::WORD_ MajorOperatingSystemVersion;
boost::winapi::WORD_ MinorOperatingSystemVersion;
boost::winapi::WORD_ MajorImageVersion;
boost::winapi::WORD_ MinorImageVersion;
boost::winapi::WORD_ MajorSubsystemVersion;
boost::winapi::WORD_ MinorSubsystemVersion;
boost::winapi::DWORD_ Win32VersionValue;
boost::winapi::DWORD_ SizeOfImage;
boost::winapi::DWORD_ SizeOfHeaders;
boost::winapi::DWORD_ CheckSum;
boost::winapi::WORD_ Subsystem;
boost::winapi::WORD_ DllCharacteristics;
boost::winapi::ULONGLONG_ SizeOfStackReserve;
boost::winapi::ULONGLONG_ SizeOfStackCommit;
boost::winapi::ULONGLONG_ SizeOfHeapReserve;
boost::winapi::ULONGLONG_ SizeOfHeapCommit;
boost::winapi::DWORD_ LoaderFlags;
boost::winapi::DWORD_ NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16 /* IMAGE_NUMBEROF_DIRECTORY_ENTRIES */];
} optional_header {};
boost::winapi::SetFilePointer(hfile, dos_header.e_lfanew + 4 + sizeof(file_header), nullptr, boost::winapi::FILE_BEGIN_);
boost::winapi::ReadFile(hfile, &optional_header, sizeof(optional_header), &bytes_read, nullptr);
image_base = optional_header.ImageBase;
}
}

boost::winapi::CloseHandle(hfile);
return image_base;
}
[[nodiscard]] inline uintptr_t rebase_address_for_syminfo(const void* addr_ptr) noexcept
{
auto addr = reinterpret_cast<uintptr_t>(addr_ptr);

boost::stacktrace::detail::location_from_symbol loc(addr_ptr);
const char* symbol_file = loc.empty() ? nullptr : loc.name();
const auto static_base = read_static_image_base(symbol_file);
const auto dynamic_base = reinterpret_cast<uintptr_t>(boost::winapi::GetModuleHandleA(symbol_file));

return addr - dynamic_base + static_base;
}
#else
[[nodiscard]] inline uintptr_t rebase_address_for_syminfo(const void* addr_ptr) noexcept
{ return reinterpret_cast<uintptr_t>(addr_ptr); }
#endif

struct to_string_using_backtrace {
std::string res;
boost::stacktrace::detail::program_location prog_location;
Expand All @@ -134,7 +321,7 @@ struct to_string_using_backtrace {
||
::backtrace_syminfo(
state,
reinterpret_cast<uintptr_t>(addr),
rebase_address_for_syminfo(addr),
boost::stacktrace::detail::libbacktrace_syminfo_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
Expand Down Expand Up @@ -181,7 +368,7 @@ inline std::string name_impl(const void* addr) {
||
::backtrace_syminfo(
state,
reinterpret_cast<uintptr_t>(addr),
rebase_address_for_syminfo(addr),
boost::stacktrace::detail::libbacktrace_syminfo_callback,
boost::stacktrace::detail::libbacktrace_error_callback,
&data
Expand Down