diff --git a/src/debug.cpp b/src/debug.cpp index c68f9a8414564..d604f85199e02 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -59,6 +59,7 @@ # include # if defined(LIBBACKTRACE) # include +# include # endif # elif defined(__ANDROID__) # include @@ -103,6 +104,63 @@ static bool capturing = false; /** сaptured debug messages */ static std::string captured; +#if defined(_WIN32) and defined(LIBBACKTRACE) +// Get the image base of a module from its PE header +static uintptr_t get_image_base( const char *const path ) +{ + HANDLE file = CreateFile( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL ); + if( file == INVALID_HANDLE_VALUE ) { + return 0; + } + on_out_of_scope close_file( [file]() { + CloseHandle( file ); + } ); + + HANDLE mapping = CreateFileMapping( file, NULL, PAGE_READONLY, 0, 0, NULL ); + if( mapping == NULL ) { + return 0; + } + on_out_of_scope close_mapping( [mapping]() { + CloseHandle( mapping ); + } ); + + LONG nt_header_offset = 0; + { + LPVOID dos_header_view = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, sizeof( IMAGE_DOS_HEADER ) ); + if( dos_header_view == NULL ) { + return 0; + } + on_out_of_scope close_dos_header_view( [dos_header_view]() { + UnmapViewOfFile( dos_header_view ); + } ); + + PIMAGE_DOS_HEADER dos_header = reinterpret_cast( dos_header_view ); + if( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { + return 0; + } + nt_header_offset = dos_header->e_lfanew; + } + + LPVOID pe_header_view = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, + nt_header_offset + sizeof( IMAGE_NT_HEADERS ) ); + if( pe_header_view == NULL ) { + return 0; + } + on_out_of_scope close_pe_header_view( [pe_header_view]() { + UnmapViewOfFile( pe_header_view ); + } ); + + PIMAGE_NT_HEADERS nt_header = reinterpret_cast( + reinterpret_cast( pe_header_view ) + nt_header_offset ); + if( nt_header->Signature != IMAGE_NT_SIGNATURE + || nt_header->FileHeader.SizeOfOptionalHeader != sizeof( IMAGE_OPTIONAL_HEADER ) ) { + return 0; + } + return nt_header->OptionalHeader.ImageBase; +} +#endif + /** * Class for capturing debugmsg, * used by capture_debugmsg_during. @@ -939,7 +997,11 @@ static struct { } sym_storage; static SYMBOL_INFO &sym = reinterpret_cast( sym_storage ); #if defined(LIBBACKTRACE) -static std::map bt_states; +struct backtrace_module_info_t { + backtrace_state *state = nullptr; + uintptr_t image_base = 0; +}; +static std::map bt_module_info_map; #endif #elif !defined(__ANDROID__) static constexpr int bt_cnt = 20; @@ -1035,39 +1097,37 @@ void debug_write_backtrace( std::ostream &out ) } out << "), "; #if defined(LIBBACKTRACE) - backtrace_state *bt_state = nullptr; + backtrace_module_info_t bt_module_info; if( mod_base ) { - const auto it = bt_states.find( mod_base ); - if( it != bt_states.end() ) { - bt_state = it->second; + const auto it = bt_module_info_map.find( mod_base ); + if( it != bt_module_info_map.end() ) { + bt_module_info = it->second; } else { const DWORD mod_len = GetModuleFileName( reinterpret_cast( mod_base ), mod_path, module_path_len ); if( mod_len > 0 && mod_len < module_path_len ) { - bt_state = bt_create_state( mod_path, 0, - // error callback + bt_module_info.state = bt_create_state( mod_path, 0, + // error callback [&out]( const char *const msg, const int errnum ) { out << "\n (backtrace_create_state failed: errno = " << errnum << ", msg = " << ( msg ? msg : "[no msg]" ) << "),"; } ); + bt_module_info.image_base = get_image_base( mod_path ); + if( bt_module_info.image_base == 0 ) { + out << "\n (cannot locate image base),"; + } } else { out << "\n (executable path exceeds " << module_path_len << " chars),"; } - if( bt_state ) { - bt_states.emplace( mod_base, bt_state ); - } + bt_module_info_map.emplace( mod_base, bt_module_info ); } } else { out << "\n (unable to get module base address),"; } - if( bt_state ) { -#if defined(__MINGW64__) - constexpr uint64_t static_image_base = 0x140000000ULL; -#elif defined(__MINGW32__) - constexpr uint64_t static_image_base = 0x400000ULL; -#endif - uint64_t de_aslr_pc = reinterpret_cast( bt[i] ) - mod_base + static_image_base; - bt_syminfo( bt_state, de_aslr_pc, + if( bt_module_info.state && bt_module_info.image_base != 0 ) { + const uintptr_t de_aslr_pc = reinterpret_cast( bt[i] ) - mod_base + + bt_module_info.image_base; + bt_syminfo( bt_module_info.state, de_aslr_pc, // syminfo callback [&out]( const uintptr_t pc, const char *const symname, const uintptr_t symval, const uintptr_t ) { @@ -1082,7 +1142,7 @@ void debug_write_backtrace( std::ostream &out ) << ", msg = " << ( msg ? msg : "[no msg]" ) << "),"; } ); - bt_pcinfo( bt_state, de_aslr_pc, + bt_pcinfo( bt_module_info.state, de_aslr_pc, // backtrace callback [&out]( const uintptr_t pc, const char *const filename, const int lineno, const char *const function ) -> int {