diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 867f1d537ca..e32fbd47dda 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -47,9 +47,6 @@ #include -#pragma comment(lib, "psapi.lib") -#pragma comment(lib, "dbghelp.lib") - // Some versions of imagehlp.dll lack the proper packing directives themselves // so we need to do it. #pragma pack(push, before_imagehlp, 8) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 1b55574b193..ba8d27bba57 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -409,6 +409,9 @@ def configure_msvc(env, vcvars_msvc_config): "wbemuuid", ] + if env.debug_features: + LIBS += ["psapi", "dbghelp"] + if env["vulkan"]: env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: @@ -587,6 +590,9 @@ def configure_mingw(env): ] ) + if env.debug_features: + env.Append(LIBS=["psapi", "dbghelp"]) + if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 6e219fb9299..edc3a6c6f64 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -55,6 +55,12 @@ #include #include +#ifdef DEBUG_ENABLED +#pragma pack(push, before_imagehlp, 8) +#include +#pragma pack(pop, before_imagehlp) +#endif + extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 1; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; @@ -88,7 +94,7 @@ static String format_error_message(DWORD id) { LocalFree(messageBuffer); - return msg; + return msg.replace("\r", "").replace("\n", ""); } void RedirectStream(const char *p_file_name, const char *p_mode, FILE *p_cpp_stream, const DWORD p_std_handle) { @@ -277,6 +283,73 @@ Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) { return OK; } +#ifdef DEBUG_ENABLED +void debug_dynamic_library_check_dependencies(const String &p_root_path, const String &p_path, HashSet &r_checked, HashSet &r_missing) { + if (r_checked.has(p_path)) { + return; + } + r_checked.insert(p_path); + + LOADED_IMAGE loaded_image; + HANDLE file = CreateFileW((LPCWSTR)p_path.utf16().get_data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (file != INVALID_HANDLE_VALUE) { + HANDLE file_mapping = CreateFileMappingW(file, nullptr, PAGE_READONLY | SEC_COMMIT, 0, 0, nullptr); + if (file_mapping != INVALID_HANDLE_VALUE) { + PVOID mapping = MapViewOfFile(file_mapping, FILE_MAP_READ, 0, 0, 0); + if (mapping) { + PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)mapping; + PIMAGE_NT_HEADERS nt_header = nullptr; + if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) { + PCHAR nt_header_ptr; + nt_header_ptr = ((PCHAR)mapping) + dos_header->e_lfanew; + nt_header = (PIMAGE_NT_HEADERS)nt_header_ptr; + if (nt_header->Signature != IMAGE_NT_SIGNATURE) { + nt_header = nullptr; + } + } + if (nt_header) { + loaded_image.ModuleName = nullptr; + loaded_image.hFile = file; + loaded_image.MappedAddress = (PUCHAR)mapping; + loaded_image.FileHeader = nt_header; + loaded_image.Sections = (PIMAGE_SECTION_HEADER)((LPBYTE)&nt_header->OptionalHeader + nt_header->FileHeader.SizeOfOptionalHeader); + loaded_image.NumberOfSections = nt_header->FileHeader.NumberOfSections; + loaded_image.SizeOfImage = GetFileSize(file, nullptr); + loaded_image.Characteristics = nt_header->FileHeader.Characteristics; + loaded_image.LastRvaSection = loaded_image.Sections; + loaded_image.fSystemImage = false; + loaded_image.fDOSImage = false; + loaded_image.Links.Flink = &loaded_image.Links; + loaded_image.Links.Blink = &loaded_image.Links; + + ULONG size = 0; + const IMAGE_IMPORT_DESCRIPTOR *import_desc = (const IMAGE_IMPORT_DESCRIPTOR *)ImageDirectoryEntryToData((HMODULE)loaded_image.MappedAddress, false, IMAGE_DIRECTORY_ENTRY_IMPORT, &size); + if (import_desc) { + for (; import_desc->Name && import_desc->FirstThunk; import_desc++) { + char16_t full_name_wc[MAX_PATH]; + const char *name_cs = (const char *)ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, 0); + String name = String(name_cs); + if (name.begins_with("api-ms-win-")) { + r_checked.insert(name); + } else if (SearchPathW(nullptr, (LPCWSTR)name.utf16().get_data(), nullptr, MAX_PATH, (LPWSTR)full_name_wc, nullptr)) { + debug_dynamic_library_check_dependencies(p_root_path, String::utf16(full_name_wc), r_checked, r_missing); + } else if (SearchPathW((LPCWSTR)(p_path.get_base_dir().utf16().get_data()), (LPCWSTR)name.utf16().get_data(), nullptr, MAX_PATH, (LPWSTR)full_name_wc, nullptr)) { + debug_dynamic_library_check_dependencies(p_root_path, String::utf16(full_name_wc), r_checked, r_missing); + } else { + r_missing.insert(name); + } + } + } + } + UnmapViewOfFile(mapping); + } + CloseHandle(file_mapping); + } + CloseHandle(file); + } +} +#endif + Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = p_path.replace("/", "\\"); @@ -299,7 +372,29 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han } p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(path.utf16().get_data()), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0); - ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + format_error_message(GetLastError()) + "."); +#ifdef DEBUG_ENABLED + if (!p_library_handle) { + DWORD err_code = GetLastError(); + + HashSet checekd_libs; + HashSet missing_libs; + debug_dynamic_library_check_dependencies(path, path, checekd_libs, missing_libs); + if (!missing_libs.is_empty()) { + String missing; + for (const String &E : missing_libs) { + if (!missing.is_empty()) { + missing += ", "; + } + missing += E; + } + ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, missing dependencies: (%s), error: \"%s\".", p_path, missing, format_error_message(err_code))); + } else { + ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, error: \"%s\"." + p_path, format_error_message(err_code))); + } + } +#else + ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, error: \"%s\"." + p_path, format_error_message(GetLastError()))); +#endif if (cookie) { remove_dll_directory(cookie); @@ -323,7 +418,7 @@ Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, cons p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data()); if (!p_symbol_handle) { if (!p_optional) { - ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Can't resolve symbol " + p_name + ", error: " + String::num(GetLastError()) + "."); + ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, vformat("Can't resolve symbol %s, error: \"%s\".", p_name, format_error_message(GetLastError()))); } else { return ERR_CANT_RESOLVE; }