From 89023f7c05a33ded51d041450dd86c7a6b3e9fea Mon Sep 17 00:00:00 2001 From: prbegd <1225095986@qq.com> Date: Sat, 24 Jan 2026 23:11:47 +0800 Subject: [PATCH 1/3] Fix for issue 212 --- .../stacktrace/detail/libbacktrace_impls.hpp | 185 +++++++++++++++++- 1 file changed, 183 insertions(+), 2 deletions(-) diff --git a/include/boost/stacktrace/detail/libbacktrace_impls.hpp b/include/boost/stacktrace/detail/libbacktrace_impls.hpp index bde53f2..f9b3c98 100644 --- a/include/boost/stacktrace/detail/libbacktrace_impls.hpp +++ b/include/boost/stacktrace/detail/libbacktrace_impls.hpp @@ -23,6 +23,13 @@ # include #endif +#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# include +# include +# include "boost/winapi/access_rights.hpp" +# include "boost/winapi/handles.hpp" +#endif + namespace boost { namespace stacktrace { namespace detail { @@ -114,6 +121,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(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(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(addr_ptr); } +#endif + struct to_string_using_backtrace { std::string res; boost::stacktrace::detail::program_location prog_location; @@ -134,7 +315,7 @@ struct to_string_using_backtrace { || ::backtrace_syminfo( state, - reinterpret_cast(addr), + rebase_address_for_syminfo(addr), boost::stacktrace::detail::libbacktrace_syminfo_callback, boost::stacktrace::detail::libbacktrace_error_callback, &data @@ -181,7 +362,7 @@ inline std::string name_impl(const void* addr) { || ::backtrace_syminfo( state, - reinterpret_cast(addr), + rebase_address_for_syminfo(addr), boost::stacktrace::detail::libbacktrace_syminfo_callback, boost::stacktrace::detail::libbacktrace_error_callback, &data From f39e222138b7a63822a4624365d3e171f7e358b8 Mon Sep 17 00:00:00 2001 From: prbegd <1225095986@qq.com> Date: Sun, 25 Jan 2026 11:18:48 +0800 Subject: [PATCH 2/3] Fix libbacktrace_full_callback return value --- include/boost/stacktrace/detail/libbacktrace_impls.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/stacktrace/detail/libbacktrace_impls.hpp b/include/boost/stacktrace/detail/libbacktrace_impls.hpp index f9b3c98..2c3c831 100644 --- a/include/boost/stacktrace/detail/libbacktrace_impls.hpp +++ b/include/boost/stacktrace/detail/libbacktrace_impls.hpp @@ -60,7 +60,7 @@ inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char * *d.function = function; } d.line = static_cast(lineno); - return 0; + return 1; } inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) noexcept { From 73347cb7fb1e183af0227e1ce7a0c006280b962f Mon Sep 17 00:00:00 2001 From: prbegd <1225095986@qq.com> Date: Sun, 25 Jan 2026 14:40:07 +0800 Subject: [PATCH 3/3] Fix: libbacktrace_full_callback will return 0 if there is no data --- include/boost/stacktrace/detail/libbacktrace_impls.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/boost/stacktrace/detail/libbacktrace_impls.hpp b/include/boost/stacktrace/detail/libbacktrace_impls.hpp index 2c3c831..4c8c461 100644 --- a/include/boost/stacktrace/detail/libbacktrace_impls.hpp +++ b/include/boost/stacktrace/detail/libbacktrace_impls.hpp @@ -53,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(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(lineno); - return 1; + if (d.line) { + return_value = 1; + } + return return_value; } inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) noexcept {