From e78535540898d61a52b63b482d56b979837d7994 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Thu, 23 Jul 2026 17:06:32 -0400 Subject: [PATCH 1/5] Pin WinDbg/TTD to a known-good version instead of always downloading latest (Fix #1130) The latest WinDbg release (1.2606.22001.0) crashes the DbgEng TTD adapter on stop (#1129). The installer now downloads a pinned version (1.2603.20001.0) directly by URL, and falls back to the latest version via the appinstaller manifest if the pinned download fails. Co-Authored-By: Claude Opus 4.8 (1M context) --- installer/windbg_installer.cpp | 349 ++++++++++++++++++--------------- 1 file changed, 191 insertions(+), 158 deletions(-) diff --git a/installer/windbg_installer.cpp b/installer/windbg_installer.cpp index 95a801fb..9c1876e0 100644 --- a/installer/windbg_installer.cpp +++ b/installer/windbg_installer.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -28,9 +29,24 @@ namespace WinDbgInstaller { namespace { -/* URL for WinDbg appinstaller file */ +/* URL for WinDbg appinstaller file (resolves to the latest release manifest) */ const char* kWinDbgDownloadUrl = "https://aka.ms/windbg/download"; +/* Pinned WinDbg version. + * + * We deliberately install a known-good, pinned version instead of always pulling the + * absolute latest, because a freshly released WinDbg occasionally ships regressions that + * break the debugger's DbgEng/TTD adapter (see issues #1129 and #1130). When Microsoft + * releases a new version we can validate it and bump this constant. + * + * If the pinned version cannot be downloaded for any reason (e.g. Microsoft removed it + * from the CDN), Install() automatically falls back to downloading the latest version via + * the appinstaller manifest, so installation still succeeds. */ +const char* kPinnedVersion = "1.2603.20001.0"; + +/* Base host that serves the versioned MSIX bundles. */ +const char* kMsixBundleHost = "https://windbg.download.prss.microsoft.com/dbazure/prod"; + /* Files required for valid installation */ const std::vector kRequiredFiles = { "amd64\\dbgeng.dll", @@ -140,6 +156,137 @@ void CleanupTempFiles(const std::vector& files, LogCallback logCall } } +/* Build the direct MSIX bundle download URL for a specific WinDbg version. + * Microsoft hosts each release at a predictable path where the dotted version string is + * rewritten with dashes, e.g. "1.2603.20001.0" -> + * "https://windbg.download.prss.microsoft.com/dbazure/prod/1-2603-20001-0/windbg.msixbundle". */ +std::string BuildMsixBundleUrl(const std::string& version) { + std::string pathVersion = version; + std::replace(pathVersion.begin(), pathVersion.end(), '.', '-'); + return std::string(kMsixBundleHost) + "/" + pathVersion + "/windbg.msixbundle"; +} + +/* Read the version string from an appinstaller manifest (empty on failure). */ +std::string ParseAppInstallerVersion(const std::string& appInstallerPath) { + pugi::xml_document doc; + if (!doc.load_file(appInstallerPath.c_str())) { + return ""; + } + pugi::xml_node appInstaller = doc.child("AppInstaller"); + if (!appInstaller) { + return ""; + } + pugi::xml_attribute versionAttr = appInstaller.attribute("Version"); + return versionAttr ? std::string(versionAttr.value()) : ""; +} + +/* Download, verify, extract and install a WinDbg MSIX bundle from the given URL. + * + * This is the shared core used by both the pinned-version path and the latest-version + * fallback. On success it writes the version marker file using `version`. Any temporary + * artifacts created here are appended to `tempFiles` so the caller can clean them up. */ +InstallResult InstallFromMsixUrl(const std::string& msixUrl, const std::string& version, + const std::string& installTarget, const InstallConfig& config, + std::vector& tempFiles) { + LogCallback logCallback = config.onLog; + ProgressCallback progressCallback = config.onProgress; + + /* Download MSIX bundle (this is the main download that shows progress) */ + ReportProgress(progressCallback, "Downloading WinDbg/TTD package from:", 0); + ReportProgress(progressCallback, msixUrl, 0); + + /* Note: the extension must be a recognized MSIX/APPX extension (not .zip) so that + * WinVerifyTrust engages the AppX signature provider during signature verification. */ + std::string msixPath = GetTempFilePath(".msixbundle"); + tempFiles.push_back(msixPath); + + auto msixDownloadProgressCb = [&](const DownloadProgress& dp) { + /* Report download percentage (0-100%) directly - this is the only step that needs progress display */ + int percent = 0; + if (dp.totalBytes > 0) { + percent = (int)(100 * dp.bytesDownloaded / dp.totalBytes); + } + ReportProgress(progressCallback, "Downloading...", percent, + dp.bytesDownloaded, dp.totalBytes, dp.bytesPerSecond); + }; + + if (!DownloadFileWithProgress(msixUrl, msixPath, msixDownloadProgressCb, logCallback)) { + return InstallResult(false, "Failed to download MSIX bundle"); + } + + /* Verify the downloaded bundle is genuinely signed by Microsoft. + * This must happen before we extract or trust any of its contents so that a + * tampered or substituted package (supply-chain attack) is rejected. */ + ReportProgress(progressCallback, "Verifying package signature...", 0); + + SignatureResult sigResult = VerifyMicrosoftSignature(msixPath, logCallback); + if (!sigResult.valid) { + return InstallResult(false, sigResult.errorMessage.empty() + ? "MSIX bundle signature verification failed" + : sigResult.errorMessage); + } + + /* Extract inner MSIX file from bundle */ + ReportProgress(progressCallback, "Extracting package contents...", 0); + + std::string tempExtractDir = GetTempFilePath("_extract"); + tempFiles.push_back(tempExtractDir); + + std::string innerMsixPath = ExtractFileFromZipArchive(msixPath, kInnerMsixName, tempExtractDir, logCallback); + if (innerMsixPath.empty()) { + return InstallResult(false, "Failed to extract inner MSIX file"); + } + + /* Extract WinDbg contents to installation directory */ + ReportProgress(progressCallback, "Installing WinDbg/TTD files...", 0); + + if (!ExtractZipArchive(innerMsixPath, installTarget, nullptr, logCallback)) { + return InstallResult(false, "Failed to extract WinDbg contents"); + } + + /* Verify installation */ + ReportProgress(progressCallback, "Verifying installation...", 0); + + if (!CheckInstallation(installTarget)) { + return InstallResult(false, "Installation verification failed - required files missing"); + } + + Log(logCallback, LOG_INFO, "WinDbg/TTD installed to: " + installTarget); + + /* Write version marker file so we can report the installed version later */ + if (!version.empty()) { + std::string versionFilePath = installTarget + "\\installed_version.txt"; + std::ofstream versionFile(versionFilePath); + if (versionFile.is_open()) { + versionFile << version; + versionFile.close(); + Log(logCallback, LOG_INFO, "Wrote version marker: " + version); + } else { + Log(logCallback, LOG_WARN, "Could not write version marker file"); + } + } + + return InstallResult(true); +} + +/* Common post-install steps shared by both install paths. */ +void FinishInstall(const std::string& installTarget, const InstallConfig& config, + std::vector& tempFiles) { + LogCallback logCallback = config.onLog; + ProgressCallback progressCallback = config.onProgress; + + /* Print settings info (actual settings configuration is done by UI) */ + if (config.updateSettings) { + std::string x64dbgEngPath = installTarget + "\\amd64"; + PrintSettingsInfo(x64dbgEngPath, logCallback); + } + + CleanupTempFiles(tempFiles, logCallback); + + ReportProgress(progressCallback, "Installation completed successfully!", 0); + Log(logCallback, LOG_INFO, "Please restart Binary Ninja to use WinDbg/TTD."); +} + } // anonymous namespace std::string GetDefaultInstallPath() { @@ -186,7 +333,31 @@ InstallResult Install(const InstallConfig& config) { } Log(logCallback, LOG_INFO, "Installation target: " + installTarget); - /* Step 1: Download appinstaller file (small, no progress needed) */ + /* Attempt 1: install the pinned, known-good version directly by its versioned URL. + * We prefer a pinned version because the very latest WinDbg release occasionally + * ships regressions that break the debugger (issues #1129 and #1130). */ + { + std::string pinnedUrl = BuildMsixBundleUrl(kPinnedVersion); + Log(logCallback, LOG_INFO, "Installing pinned WinDbg version " + std::string(kPinnedVersion)); + + InstallResult pinnedResult = + InstallFromMsixUrl(pinnedUrl, kPinnedVersion, installTarget, config, tempFiles); + if (pinnedResult.success) { + FinishInstall(installTarget, config, tempFiles); + return pinnedResult; + } + + /* Pinned install failed (e.g. Microsoft removed this version from the CDN). + * Fall back to the latest version below so installation can still succeed. */ + Log(logCallback, LOG_WARN, "Failed to install pinned WinDbg version " + + std::string(kPinnedVersion) + " (" + pinnedResult.errorMessage + + "); falling back to the latest version"); + CleanupTempFiles(tempFiles, logCallback); + tempFiles.clear(); + } + + /* Attempt 2 (fallback): install the latest version the "old way" - download the + * appinstaller manifest, parse it for the current MSIX bundle URL and version. */ ReportProgress(progressCallback, "Downloading WinDbg package information from:", 0); ReportProgress(progressCallback, std::string(kWinDbgDownloadUrl), 0); @@ -200,7 +371,6 @@ InstallResult Install(const InstallConfig& config) { return InstallResult(false, error); } - /* Step 2: Parse XML to get MSIX bundle URL */ ReportProgress(progressCallback, "Parsing package information...", 0); std::string msixUrl = ParseAppInstallerXml(appInstallerPath, logCallback); @@ -211,124 +381,18 @@ InstallResult Install(const InstallConfig& config) { return InstallResult(false, error); } - /* Step 3: Download MSIX bundle (this is the main download that shows progress) */ - ReportProgress(progressCallback, "Downloading WinDbg/TTD package from:", 0); - ReportProgress(progressCallback, msixUrl, 0); - - /* Note: the extension must be a recognized MSIX/APPX extension (not .zip) so that - * WinVerifyTrust engages the AppX signature provider during Step 3.5 verification. */ - std::string msixPath = GetTempFilePath(".msixbundle"); - tempFiles.push_back(msixPath); - - auto msixDownloadProgressCb = [&](const DownloadProgress& dp) { - /* Report download percentage (0-100%) directly - this is the only step that needs progress display */ - int percent = 0; - if (dp.totalBytes > 0) { - percent = (int)(100 * dp.bytesDownloaded / dp.totalBytes); - } - ReportProgress(progressCallback, "Downloading...", percent, - dp.bytesDownloaded, dp.totalBytes, dp.bytesPerSecond); - }; - - if (!DownloadFileWithProgress(msixUrl, msixPath, msixDownloadProgressCb, logCallback)) { - std::string error = "Failed to download MSIX bundle"; - Log(logCallback, LOG_ERROR, error); - CleanupTempFiles(tempFiles, logCallback); - return InstallResult(false, error); - } - - /* Step 3.5: Verify the downloaded bundle is genuinely signed by Microsoft. - * This must happen before we extract or trust any of its contents so that a - * tampered or substituted package (supply-chain attack) is rejected. */ - ReportProgress(progressCallback, "Verifying package signature...", 0); + std::string latestVersion = ParseAppInstallerVersion(appInstallerPath); - SignatureResult sigResult = VerifyMicrosoftSignature(msixPath, logCallback); - if (!sigResult.valid) { - std::string error = sigResult.errorMessage.empty() - ? "MSIX bundle signature verification failed" - : sigResult.errorMessage; - Log(logCallback, LOG_ERROR, error); + InstallResult latestResult = + InstallFromMsixUrl(msixUrl, latestVersion, installTarget, config, tempFiles); + if (!latestResult.success) { + Log(logCallback, LOG_ERROR, latestResult.errorMessage); CleanupTempFiles(tempFiles, logCallback); - return InstallResult(false, error); + return latestResult; } - /* Step 4: Extract inner MSIX file from bundle */ - ReportProgress(progressCallback, "Extracting package contents...", 0); - - std::string tempExtractDir = GetTempFilePath("_extract"); - tempFiles.push_back(tempExtractDir); - - std::string innerMsixPath = ExtractFileFromZipArchive(msixPath, kInnerMsixName, tempExtractDir, logCallback); - if (innerMsixPath.empty()) { - std::string error = "Failed to extract inner MSIX file"; - Log(logCallback, LOG_ERROR, error); - CleanupTempFiles(tempFiles, logCallback); - return InstallResult(false, error); - } - - /* Step 5: Extract WinDbg contents to installation directory */ - ReportProgress(progressCallback, "Installing WinDbg/TTD files...", 0); - - if (!ExtractZipArchive(innerMsixPath, installTarget, nullptr, logCallback)) { - std::string error = "Failed to extract WinDbg contents"; - Log(logCallback, LOG_ERROR, error); - CleanupTempFiles(tempFiles, logCallback); - return InstallResult(false, error); - } - - /* Step 6: Verify installation */ - ReportProgress(progressCallback, "Verifying installation...", 0); - - if (!CheckInstallation(installTarget)) { - std::string error = "Installation verification failed - required files missing"; - Log(logCallback, LOG_ERROR, error); - CleanupTempFiles(tempFiles, logCallback); - return InstallResult(false, error); - } - - Log(logCallback, LOG_INFO, "WinDbg/TTD installed to: " + installTarget); - - /* Step 6b: Write version marker file */ - /* Re-parse appinstaller to get version (file is still on disk) */ - std::string installedVersion; - { - pugi::xml_document doc; - if (doc.load_file(appInstallerPath.c_str())) { - pugi::xml_node appInstaller = doc.child("AppInstaller"); - if (appInstaller) { - pugi::xml_attribute versionAttr = appInstaller.attribute("Version"); - if (versionAttr) { - installedVersion = versionAttr.value(); - } - } - } - } - - if (!installedVersion.empty()) { - std::string versionFilePath = installTarget + "\\installed_version.txt"; - std::ofstream versionFile(versionFilePath); - if (versionFile.is_open()) { - versionFile << installedVersion; - versionFile.close(); - Log(logCallback, LOG_INFO, "Wrote version marker: " + installedVersion); - } else { - Log(logCallback, LOG_WARN, "Could not write version marker file"); - } - } - - /* Step 7: Print settings info (actual settings configuration is done by UI) */ - if (config.updateSettings) { - std::string x64dbgEngPath = installTarget + "\\amd64"; - PrintSettingsInfo(x64dbgEngPath, logCallback); - } - - /* Cleanup */ - CleanupTempFiles(tempFiles, logCallback); - - ReportProgress(progressCallback, "Installation completed successfully!", 0); - Log(logCallback, LOG_INFO, "Please restart Binary Ninja to use WinDbg/TTD."); - - return InstallResult(true); + FinishInstall(installTarget, config, tempFiles); + return latestResult; } catch (const std::exception& e) { std::string error = "Exception during installation: " + std::string(e.what()); @@ -397,48 +461,17 @@ VersionInfo GetInstalledVersion(const std::string& installPath) { } VersionInfo GetLatestVersion(LogCallback logCallback) { - VersionInfo info; - - /* Download appinstaller file to temp location */ - std::string tempPath = GetTempFilePath(".appinstaller"); - - if (!DownloadFileWithProgress(kWinDbgDownloadUrl, tempPath, nullptr, logCallback)) { - Log(logCallback, LOG_ERROR, "Failed to download appinstaller for version check"); - return info; - } - - /* Parse XML to get version */ - pugi::xml_document doc; - pugi::xml_parse_result result = doc.load_file(tempPath.c_str()); - - if (!result) { - Log(logCallback, LOG_ERROR, "Failed to parse appinstaller XML: " + std::string(result.description())); - fs::remove(tempPath); - return info; - } - - /* Get version from AppInstaller element */ - pugi::xml_node appInstaller = doc.child("AppInstaller"); - if (appInstaller) { - pugi::xml_attribute versionAttr = appInstaller.attribute("Version"); - if (versionAttr) { - info.version = versionAttr.value(); - info.displayName = "WinDbg " + info.version; - } - - /* Get download URL from MainBundle */ - pugi::xml_node mainBundle = appInstaller.child("MainBundle"); - if (mainBundle) { - pugi::xml_attribute uriAttr = mainBundle.attribute("Uri"); - if (uriAttr) { - info.downloadUrl = uriAttr.value(); - } - } - } - - /* Cleanup */ - fs::remove(tempPath); + /* Report the pinned version as the "latest" version we offer, rather than whatever + * Microsoft is currently shipping. Install() installs the pinned version, so this keeps + * version checks consistent: users are only prompted to update when their installed + * version is older than the pinned one, not every time Microsoft publishes a new build + * that we have not yet validated (see issues #1129 and #1130). */ + (void)logCallback; + VersionInfo info; + info.version = kPinnedVersion; + info.displayName = "WinDbg " + info.version; + info.downloadUrl = BuildMsixBundleUrl(kPinnedVersion); return info; } From 7423bc92111e10481cf66a918c5f5548b5d7a41e Mon Sep 17 00:00:00 2001 From: Xusheng Date: Tue, 11 Aug 2026 16:08:33 -0400 Subject: [PATCH 2/5] Remove the WinDbg update check now that the version is pinned Since we install a pinned WinDbg version rather than the latest release, there is nothing to check online. The latest-version query was reduced to returning a compile-time constant, but it still went through a background thread, an FFI call and a subprocess that spawned the installer CLI to parse its JSON output. Worse, the check itself became wrong: IsVersionUpToDate() compared with >=, so a user who already had the broken 1.2606.22001.0 installed - exactly the population hit by #1129/#1130 - was told they were up to date and never offered the fix. Remove GetLatestVersion(), IsVersionUpToDate() and CompareVersions() from the installer library, the check-update CLI command and its exit code 2, the core/FFI/API GetLatestVersion() plumbing along with the now-unused subprocess and JSON helpers, and the dialog's async version fetch. The pinned version moves to windbg_version.h so the UI can display it directly. The dialog now compares the installed version against that constant and offers Reinstall when they match and Install when they do not - not Update, since replacing a newer WinDbg with the validated one is a downgrade. Co-Authored-By: Claude Opus 5 (1M context) --- api/debuggerapi.h | 1 - api/ffi.h | 1 - api/windbginstaller.cpp | 9 -- core/ffi.cpp | 13 --- core/windbginstaller.cpp | 91 -------------------- core/windbginstaller.h | 7 -- docs/guide/dbgeng-ttd.md | 18 ++-- installer/CMakeLists.txt | 1 + installer/main.cpp | 93 +++----------------- installer/windbg_installer.cpp | 69 +-------------- installer/windbg_installer.h | 34 +------- installer/windbg_version.h | 23 +++++ ui/ui.cpp | 7 +- ui/windbgupdatedialog.cpp | 149 +++++++++++++-------------------- ui/windbgupdatedialog.h | 16 ++-- 15 files changed, 115 insertions(+), 417 deletions(-) create mode 100644 installer/windbg_version.h diff --git a/api/debuggerapi.h b/api/debuggerapi.h index 0ff27f12..7605ecbd 100644 --- a/api/debuggerapi.h +++ b/api/debuggerapi.h @@ -981,6 +981,5 @@ namespace BinaryNinjaDebuggerAPI { bool IsWinDbgInstalled(const std::string& installPath = ""); std::string GetWinDbgInstallerPath(); std::string GetWinDbgInstalledVersion(const std::string& installPath = ""); - std::string GetWinDbgLatestVersion(); }; // namespace BinaryNinjaDebuggerAPI diff --git a/api/ffi.h b/api/ffi.h index 61bfc333..b6489598 100644 --- a/api/ffi.h +++ b/api/ffi.h @@ -877,7 +877,6 @@ extern "C" DEBUGGER_FFI_API bool BNDebuggerIsWinDbgInstalled(const char* installPath); DEBUGGER_FFI_API char* BNDebuggerGetWinDbgInstallerPath(void); DEBUGGER_FFI_API char* BNDebuggerGetWinDbgInstalledVersion(const char* installPath); - DEBUGGER_FFI_API char* BNDebuggerGetWinDbgLatestVersion(void); #ifdef __cplusplus } diff --git a/api/windbginstaller.cpp b/api/windbginstaller.cpp index 2a8b5a6a..8d3e46c7 100644 --- a/api/windbginstaller.cpp +++ b/api/windbginstaller.cpp @@ -57,12 +57,3 @@ std::string BinaryNinjaDebuggerAPI::GetWinDbgInstalledVersion(const std::string& BNDebuggerFreeString(version); return result; } - - -std::string BinaryNinjaDebuggerAPI::GetWinDbgLatestVersion() -{ - char* version = BNDebuggerGetWinDbgLatestVersion(); - std::string result = version ? version : ""; - BNDebuggerFreeString(version); - return result; -} diff --git a/core/ffi.cpp b/core/ffi.cpp index f6fd65f6..b6574fc5 100644 --- a/core/ffi.cpp +++ b/core/ffi.cpp @@ -2231,13 +2231,6 @@ char* BNDebuggerGetWinDbgInstalledVersion(const char* installPath) return BNAllocString(version.c_str()); } - -char* BNDebuggerGetWinDbgLatestVersion(void) -{ - std::string version = GetLatestVersion(); - return BNAllocString(version.c_str()); -} - #else // !WIN32 // Stub implementations for non-Windows platforms @@ -2280,10 +2273,4 @@ char* BNDebuggerGetWinDbgInstalledVersion(const char* installPath) return BNAllocString(""); } - -char* BNDebuggerGetWinDbgLatestVersion(void) -{ - return BNAllocString(""); -} - #endif // WIN32 diff --git a/core/windbginstaller.cpp b/core/windbginstaller.cpp index 36120685..3c7df7c9 100644 --- a/core/windbginstaller.cpp +++ b/core/windbginstaller.cpp @@ -160,92 +160,6 @@ InstallResult InstallWinDbg(const std::string& installPath, bool isUpdate) { } } -/* Helper function to run installer CLI and capture JSON output */ -static std::string RunInstallerCommand(const std::string& command, const std::string& extraArgs = "") { - std::string installerPath = GetInstallerPath(); - if (installerPath.empty()) { - return ""; - } - - std::string cmdLine = "\"" + installerPath + "\" " + command + " --json"; - if (!extraArgs.empty()) { - cmdLine += " " + extraArgs; - } - - /* Create pipes for stdout */ - SECURITY_ATTRIBUTES sa = {}; - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - - HANDLE hReadPipe, hWritePipe; - if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) { - return ""; - } - - /* Ensure read handle is not inherited */ - SetHandleInformation(hReadPipe, HANDLE_FLAG_INHERIT, 0); - - STARTUPINFOA si = {}; - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.hStdOutput = hWritePipe; - si.hStdError = hWritePipe; - si.wShowWindow = SW_HIDE; - - PROCESS_INFORMATION pi = {}; - - if (!CreateProcessA( - nullptr, - const_cast(cmdLine.c_str()), - nullptr, - nullptr, - TRUE, /* Inherit handles */ - CREATE_NO_WINDOW, - nullptr, - nullptr, - &si, - &pi)) { - CloseHandle(hReadPipe); - CloseHandle(hWritePipe); - return ""; - } - - /* Close write end in parent */ - CloseHandle(hWritePipe); - - /* Read output */ - std::string output; - char buffer[4096]; - DWORD bytesRead; - while (ReadFile(hReadPipe, buffer, sizeof(buffer) - 1, &bytesRead, nullptr) && bytesRead > 0) { - buffer[bytesRead] = '\0'; - output += buffer; - } - - CloseHandle(hReadPipe); - - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return output; -} - -/* Simple JSON value extractor - finds "key":"value" pattern */ -static std::string ExtractJsonValue(const std::string& json, const std::string& key) { - std::string searchKey = "\"" + key + "\":\""; - size_t pos = json.find(searchKey); - if (pos == std::string::npos) { - return ""; - } - pos += searchKey.length(); - size_t endPos = json.find("\"", pos); - if (endPos == std::string::npos) { - return ""; - } - return json.substr(pos, endPos - pos); -} - std::string GetInstalledVersion(const std::string& installPath) { /* Read version directly from marker file (fast, no CLI call needed) */ std::string path = installPath; @@ -278,11 +192,6 @@ std::string GetInstalledVersion(const std::string& installPath) { return ""; } -std::string GetLatestVersion() { - std::string output = RunInstallerCommand("check-update"); - return ExtractJsonValue(output, "latest"); -} - } // namespace BinaryNinjaDebugger #endif // WIN32 diff --git a/core/windbginstaller.h b/core/windbginstaller.h index bfed6377..6dc9fe02 100644 --- a/core/windbginstaller.h +++ b/core/windbginstaller.h @@ -67,13 +67,6 @@ std::string GetInstallerPath(); */ std::string GetInstalledVersion(const std::string& installPath = ""); -/* - * Get the latest available WinDbg version from Microsoft - * - * @return Version string, or empty on error - */ -std::string GetLatestVersion(); - } // namespace BinaryNinjaDebugger #endif // WIN32 diff --git a/docs/guide/dbgeng-ttd.md b/docs/guide/dbgeng-ttd.md index ec832a1b..7d50dc7f 100644 --- a/docs/guide/dbgeng-ttd.md +++ b/docs/guide/dbgeng-ttd.md @@ -21,7 +21,7 @@ The WinDbg installation only needs to be done once. - Open Binary Ninja - Click `Debugger` -> `Install WinDbg/TTD` from the menu - A dialog will appear showing the installation progress: - - The installer automatically downloads the latest WinDbg from Microsoft + - The installer downloads a specific WinDbg version from Microsoft - It extracts the necessary files (DbgEng DLLs and TTD components) - WinDbg will be installed to `%APPDATA%\Binary Ninja\windbg` - Progress and status are displayed in real-time @@ -32,17 +32,21 @@ The WinDbg installation only needs to be done once. The automatic installer handles all the complexity of downloading and extracting the WinDbg MSIX bundle. -### Update WinDbg/TTD +Note that the installer deliberately installs a pinned WinDbg version that has been validated against the debugger, rather than the newest release. +New WinDbg releases occasionally ship regressions that break the DbgEng/TTD adapter, so the pinned version is bumped only after it has been tested. -If you already have WinDbg/TTD installed and want to check for updates: +### Reinstall WinDbg/TTD + +If you already have WinDbg/TTD installed: - Click `Debugger` -> `Install WinDbg/TTD` from the menu - A dialog will appear showing: - The currently installed version - - The latest available version from Microsoft -- If a newer version is available, click "Update" to download and install it -- If you are already on the latest version, the dialog will indicate that no update is needed -- Restart Binary Ninja after updating + - The version this debugger supports +- If the two match, you can click "Reinstall" to install it again, e.g. if the installation was damaged +- If they differ, click "Install" to replace the installed version with the supported one. + Note this can be a downgrade: if you installed a newer WinDbg yourself, this replaces it with the validated version +- Restart Binary Ninja afterwards diff --git a/installer/CMakeLists.txt b/installer/CMakeLists.txt index 8d8a03da..28ba273c 100644 --- a/installer/CMakeLists.txt +++ b/installer/CMakeLists.txt @@ -52,6 +52,7 @@ set(INSTALLER_LIB_HEADERS http_downloader.h zip_extractor.h windbg_installer.h + windbg_version.h signature_verifier.h ) diff --git a/installer/main.cpp b/installer/main.cpp index bc749da5..6fd69a23 100644 --- a/installer/main.cpp +++ b/installer/main.cpp @@ -6,7 +6,6 @@ * * Usage: * windbg-installer install [--path ] [--quiet] [--json] - * windbg-installer check-update [--path ] [--json] * windbg-installer version [--path ] [--json] * windbg-installer --help * @@ -17,6 +16,7 @@ #ifdef _WIN32 #include "windbg_installer.h" +#include "windbg_version.h" #include #include #include @@ -222,14 +222,6 @@ void PrintJsonResult(bool success, const std::string& message, const std::string std::cout << "}" << std::endl; } -/* Print JSON version info */ -void PrintJsonVersion(const std::string& installed, const std::string& latest, bool updateAvailable) { - std::cout << "{\"type\":\"version\",\"installed\":\"" << installed - << "\",\"latest\":\"" << latest - << "\",\"updateAvailable\":" << (updateAvailable ? "true" : "false") - << "}" << std::endl; -} - void PrintUsage(const char* programName) { std::cout << "WinDbg/TTD Installer for Binary Ninja Debugger\n" << "\n" @@ -237,9 +229,8 @@ void PrintUsage(const char* programName) { << " " << programName << " [options]\n" << "\n" << "Commands:\n" - << " install Install or update WinDbg/TTD\n" - << " version Show installed version (local only, no network)\n" - << " check-update Check for updates (compares local vs latest online)\n" + << " install Install or reinstall WinDbg/TTD\n" + << " version Show the installed and supported versions\n" << "\n" << "Options:\n" << " --path Specify installation directory\n" @@ -252,15 +243,13 @@ void PrintUsage(const char* programName) { << "\n" << "Examples:\n" << " " << programName << " version\n" - << " " << programName << " check-update\n" << " " << programName << " install\n" << " " << programName << " install --update\n" << " " << programName << " install --path C:\\Tools\\WinDbg\n" << "\n" << "Exit codes:\n" - << " 0 Success / up to date\n" + << " 0 Success\n" << " 1 Not installed / error\n" - << " 2 Update available (for check-update)\n" << "\n"; } @@ -410,6 +399,7 @@ int CmdVersion(const std::string& installPath, OutputMode mode) { if (mode == OutputMode::Json) { std::cout << "{\"type\":\"version\",\"isInstalled\":" << (installed.isInstalled ? "true" : "false") << ",\"installed\":\"" << installed.version + << "\",\"supported\":\"" << kPinnedVersion << "\",\"installPath\":\"" << path << "\"}" << std::endl; } else if (mode == OutputMode::Human) { std::cout << "\n"; @@ -425,78 +415,17 @@ int CmdVersion(const std::string& installPath, OutputMode mode) { std::cout << installed.version; } ResetConsoleColor(); - std::cout << "\n\n"; - } - - return installed.isInstalled ? 0 : 1; -} - -/* Command: check-update */ -int CmdCheckUpdate(const std::string& installPath, OutputMode mode) { - std::string path = installPath.empty() ? GetDefaultInstallPath() : installPath; - - /* Get installed version first (local, fast) */ - VersionInfo installed = GetInstalledVersion(path); - - if (mode == OutputMode::Human) { - std::cout << "Install path: " << path << "\n"; - std::cout << "Installed: "; - if (!installed.isInstalled) { - SetConsoleColor(COLOR_YELLOW); - std::cout << "(not installed)"; - ResetConsoleColor(); - std::cout << "\n"; - return 1; /* Exit early, no need to check latest */ - } else if (installed.version.empty()) { + std::cout << "\n"; + std::cout << " Supported: " << kPinnedVersion << "\n"; + if (installed.isInstalled && installed.version != kPinnedVersion) { SetConsoleColor(COLOR_YELLOW); - std::cout << "(installed, version unknown)"; + std::cout << "\n The installed version is not the supported one; run 'install' to replace it.\n"; ResetConsoleColor(); - std::cout << "\n"; - } else { - std::cout << installed.version << "\n"; } - - std::cout << "Latest: "; - std::cout << std::flush; /* Flush before network request */ - } - - /* Fetch latest version (network request, may take time) */ - VersionInfo latest = GetLatestVersion(nullptr); - bool updateAvailable = !IsVersionUpToDate(installed, latest); - - if (mode == OutputMode::Json) { - /* Include path and isInstalled in JSON output */ - std::cout << "{\"type\":\"version\",\"isInstalled\":" << (installed.isInstalled ? "true" : "false") - << ",\"installed\":\"" << installed.version - << "\",\"latest\":\"" << latest.version - << "\",\"updateAvailable\":" << (updateAvailable ? "true" : "false") - << ",\"installPath\":\"" << path << "\"}" << std::endl; - } else if (mode == OutputMode::Human) { - if (latest.version.empty()) { - SetConsoleColor(COLOR_YELLOW); - std::cout << "(unable to check)"; - } else { - std::cout << latest.version; - } - ResetConsoleColor(); std::cout << "\n"; - - if (installed.version.empty()) { - std::cout << "Recommend reinstalling with 'install --update' for version tracking.\n"; - } else if (updateAvailable) { - SetConsoleColor(COLOR_GREEN); - std::cout << "Update available!\n"; - ResetConsoleColor(); - } else { - std::cout << "No update available.\n"; - } } - /* Exit code 2 means update available, 1 means not installed */ - if (!installed.isInstalled) { - return 1; - } - return updateAvailable ? 2 : 0; + return installed.isInstalled ? 0 : 1; } } // anonymous namespace @@ -555,8 +484,6 @@ int main(int argc, char* argv[]) { return CmdInstall(installPath, mode, isUpdate); } else if (command == "version") { return CmdVersion(installPath, mode); - } else if (command == "check-update") { - return CmdCheckUpdate(installPath, mode); } else { std::cerr << "Error: Unknown command: " << command << "\n"; PrintUsage(argv[0]); diff --git a/installer/windbg_installer.cpp b/installer/windbg_installer.cpp index 9c1876e0..46116b16 100644 --- a/installer/windbg_installer.cpp +++ b/installer/windbg_installer.cpp @@ -8,6 +8,7 @@ #ifdef _WIN32 #include "windbg_installer.h" +#include "windbg_version.h" #include "http_downloader.h" #include "zip_extractor.h" #include "signature_verifier.h" @@ -19,7 +20,6 @@ #include #include #include -#include #pragma comment(lib, "version.lib") @@ -32,17 +32,12 @@ namespace { /* URL for WinDbg appinstaller file (resolves to the latest release manifest) */ const char* kWinDbgDownloadUrl = "https://aka.ms/windbg/download"; -/* Pinned WinDbg version. - * - * We deliberately install a known-good, pinned version instead of always pulling the - * absolute latest, because a freshly released WinDbg occasionally ships regressions that - * break the debugger's DbgEng/TTD adapter (see issues #1129 and #1130). When Microsoft - * releases a new version we can validate it and bump this constant. +/* The pinned version we install lives in windbg_version.h, so that the UI can report the + * same value without asking the installer. * * If the pinned version cannot be downloaded for any reason (e.g. Microsoft removed it * from the CDN), Install() automatically falls back to downloading the latest version via * the appinstaller manifest, so installation still succeeds. */ -const char* kPinnedVersion = "1.2603.20001.0"; /* Base host that serves the versioned MSIX bundles. */ const char* kMsixBundleHost = "https://windbg.download.prss.microsoft.com/dbazure/prod"; @@ -460,64 +455,6 @@ VersionInfo GetInstalledVersion(const std::string& installPath) { return info; } -VersionInfo GetLatestVersion(LogCallback logCallback) { - /* Report the pinned version as the "latest" version we offer, rather than whatever - * Microsoft is currently shipping. Install() installs the pinned version, so this keeps - * version checks consistent: users are only prompted to update when their installed - * version is older than the pinned one, not every time Microsoft publishes a new build - * that we have not yet validated (see issues #1129 and #1130). */ - (void)logCallback; - - VersionInfo info; - info.version = kPinnedVersion; - info.displayName = "WinDbg " + info.version; - info.downloadUrl = BuildMsixBundleUrl(kPinnedVersion); - return info; -} - -int CompareVersions(const std::string& v1, const std::string& v2) { - /* Parse version strings like "1.2404.24002.0" */ - auto parseVersion = [](const std::string& v) -> std::vector { - std::vector parts; - std::istringstream iss(v); - std::string part; - while (std::getline(iss, part, '.')) { - try { - parts.push_back(std::stoi(part)); - } catch (...) { - parts.push_back(0); - } - } - return parts; - }; - - std::vector parts1 = parseVersion(v1); - std::vector parts2 = parseVersion(v2); - - /* Pad with zeros to make them equal length */ - size_t maxLen = (std::max)(parts1.size(), parts2.size()); - parts1.resize(maxLen, 0); - parts2.resize(maxLen, 0); - - /* Compare part by part */ - for (size_t i = 0; i < maxLen; i++) { - if (parts1[i] < parts2[i]) return -1; - if (parts1[i] > parts2[i]) return 1; - } - - return 0; -} - -bool IsVersionUpToDate(const VersionInfo& installed, const VersionInfo& latest) { - /* If either version is invalid, assume up to date (can't determine) */ - if (!installed.IsValid() || !latest.IsValid()) { - return true; - } - - /* Installed >= Latest means up to date */ - return CompareVersions(installed.version, latest.version) >= 0; -} - } // namespace WinDbgInstaller #endif // _WIN32 diff --git a/installer/windbg_installer.h b/installer/windbg_installer.h index bb6a0bfe..58c9fb17 100644 --- a/installer/windbg_installer.h +++ b/installer/windbg_installer.h @@ -86,50 +86,24 @@ std::string GetDefaultInstallPath(); struct VersionInfo { std::string version; /* Version string (e.g., "1.2404.24002.0"), empty if unknown */ std::string displayName; /* Display name (e.g., "WinDbg 1.2404.24002.0") */ - std::string downloadUrl; /* Download URL for this version */ std::string installPath; /* Path where this version is installed */ bool isInstalled; /* True if WinDbg is installed (even if version unknown) */ VersionInfo() : isInstalled(false) {} - - /* Returns true if version string is known */ - bool IsValid() const { return !version.empty(); } }; /* * Get version of installed WinDbg * + * There is deliberately no "latest version" query: we install the pinned version from + * windbg_version.h, so the only question worth asking is whether what is on disk matches + * that constant. + * * @param installPath Path to WinDbg installation (empty = use default) * @return Version info, or empty VersionInfo if not installed */ VersionInfo GetInstalledVersion(const std::string& installPath = ""); -/* - * Get latest available version from Microsoft - * - * @param logCallback Optional callback for log messages - * @return Version info, or empty VersionInfo on error - */ -VersionInfo GetLatestVersion(LogCallback logCallback = nullptr); - -/* - * Check if installed version is up to date - * - * @param installed Installed version info - * @param latest Latest version info - * @return true if installed version >= latest version (or if comparison fails) - */ -bool IsVersionUpToDate(const VersionInfo& installed, const VersionInfo& latest); - -/* - * Compare two version strings - * - * @param v1 First version string - * @param v2 Second version string - * @return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2 - */ -int CompareVersions(const std::string& v1, const std::string& v2); - /* ============================================================================ * Legacy API for backward compatibility with existing UI code * ============================================================================ */ diff --git a/installer/windbg_version.h b/installer/windbg_version.h new file mode 100644 index 00000000..5939b23e --- /dev/null +++ b/installer/windbg_version.h @@ -0,0 +1,23 @@ +/* + * Pinned WinDbg/TTD version + * + * Copyright 2020-2026 Vector 35 Inc. + * Licensed under the Apache License, Version 2.0 + */ + +#pragma once + +namespace WinDbgInstaller { + +/* The WinDbg version we install and support. + * + * We deliberately install a known-good, pinned version instead of always pulling the + * absolute latest, because a freshly released WinDbg occasionally ships regressions that + * break the debugger's DbgEng/TTD adapter (see issues #1129 and #1130). When Microsoft + * releases a new version we can validate it and bump this constant. + * + * This header is the single source of truth: the installer downloads this version, and the + * UI shows it as the version we support. */ +constexpr const char* kPinnedVersion = "1.2603.20001.0"; + +} // namespace WinDbgInstaller diff --git a/ui/ui.cpp b/ui/ui.cpp index f85cc332..9a1d56d6 100644 --- a/ui/ui.cpp +++ b/ui/ui.cpp @@ -1612,13 +1612,10 @@ void GlobalDebuggerUI::installTTD(const UIActionContext& ctxt) // Check if WinDbg is already installed if (std::filesystem::exists(installTarget) && IsWinDbgInstalled(installPath)) { - // Get installed version + // Get installed version (empty if the marker file is missing; the dialog reports that) std::string installedVersion = GetWinDbgInstalledVersion(installPath); - if (installedVersion.empty()) { - installedVersion = "(unknown)"; - } - // Show update dialog + // Show the version/reinstall dialog WinDbgUpdateDialog dialog(ctxt.context->mainWindow(), installPath, installedVersion); dialog.exec(); return; diff --git a/ui/windbgupdatedialog.cpp b/ui/windbgupdatedialog.cpp index af07b6d2..ceb2a1a6 100644 --- a/ui/windbgupdatedialog.cpp +++ b/ui/windbgupdatedialog.cpp @@ -17,6 +17,7 @@ limitations under the License. #ifdef WIN32 #include "windbgupdatedialog.h" +#include "../installer/windbg_version.h" #include "debuggerapi.h" #include "progresstask.h" #include @@ -29,9 +30,12 @@ using namespace BinaryNinjaDebuggerAPI; WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& installPath, const std::string& installedVersion) : QDialog(parent), m_installPath(installPath), m_installedVersion(installedVersion) { - setWindowTitle("WinDbg/TTD Update"); + setWindowTitle("WinDbg/TTD Version"); setMinimumWidth(450); + const std::string supportedVersion = WinDbgInstaller::kPinnedVersion; + const bool versionMatches = !m_installedVersion.empty() && (m_installedVersion == supportedVersion); + QVBoxLayout* mainLayout = new QVBoxLayout(this); /* Version information group */ @@ -40,38 +44,63 @@ WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& insta QHBoxLayout* installedLayout = new QHBoxLayout(); installedLayout->addWidget(new QLabel("Installed version:", this)); + QLabel* installedVersionLabel; if (m_installedVersion.empty()) { - m_installedVersionLabel = new QLabel("Unknown", this); - m_installedVersionLabel->setStyleSheet("font-weight: bold; color: gray;"); + installedVersionLabel = new QLabel("Unknown", this); + installedVersionLabel->setStyleSheet("font-weight: bold; color: gray;"); } else { - m_installedVersionLabel = new QLabel(QString::fromStdString(m_installedVersion), this); - m_installedVersionLabel->setStyleSheet("font-weight: bold;"); + installedVersionLabel = new QLabel(QString::fromStdString(m_installedVersion), this); + installedVersionLabel->setStyleSheet(versionMatches ? "font-weight: bold; color: green;" + : "font-weight: bold; color: orange;"); } - installedLayout->addWidget(m_installedVersionLabel); + installedLayout->addWidget(installedVersionLabel); installedLayout->addStretch(); versionLayout->addLayout(installedLayout); - QHBoxLayout* latestLayout = new QHBoxLayout(); - latestLayout->addWidget(new QLabel("Latest version:", this)); - m_latestVersionLabel = new QLabel("Checking...", this); - m_latestVersionLabel->setStyleSheet("font-weight: bold; color: gray;"); - latestLayout->addWidget(m_latestVersionLabel); - latestLayout->addStretch(); - versionLayout->addLayout(latestLayout); + QHBoxLayout* supportedLayout = new QHBoxLayout(); + supportedLayout->addWidget(new QLabel("Supported version:", this)); + QLabel* supportedVersionLabel = new QLabel(QString::fromStdString(supportedVersion), this); + supportedVersionLabel->setStyleSheet("font-weight: bold;"); + supportedLayout->addWidget(supportedVersionLabel); + supportedLayout->addStretch(); + versionLayout->addLayout(supportedLayout); mainLayout->addWidget(versionGroup); /* Status/explanation label */ - m_statusLabel = new QLabel(this); - m_statusLabel->setWordWrap(true); - m_statusLabel->setText( - "To update or reinstall WinDbg/TTD, Binary Ninja must be closed first.\n\n" - "Clicking 'Update' will:\n" - "1. Close Binary Ninja\n" - "2. Launch the installer to download and install the latest version\n" - "3. You can restart Binary Ninja after the installation completes" - ); - mainLayout->addWidget(m_statusLabel); + QLabel* statusLabel = new QLabel(this); + statusLabel->setWordWrap(true); + if (versionMatches) { + statusLabel->setText( + "You have the supported version of WinDbg/TTD installed.\n\n" + "To reinstall it anyway, click 'Reinstall'. Binary Ninja will be closed and the " + "installer will run." + ); + } else if (m_installedVersion.empty()) { + statusLabel->setText( + "Unable to determine which version of WinDbg/TTD is installed.\n\n" + "Click 'Install' to install the supported version. Binary Ninja will be closed and " + "the installer will run." + ); + } else { + statusLabel->setText( + "The installed version is not the version this debugger supports.\n\n" + "Clicking 'Install' will:\n" + "1. Close Binary Ninja\n" + "2. Launch the installer to download and install the supported version\n" + "3. You can restart Binary Ninja after the installation completes" + ); + } + mainLayout->addWidget(statusLabel); + + /* Explain why we do not simply track the latest WinDbg release */ + QLabel* noteLabel = new QLabel( + "Binary Ninja installs a specific WinDbg version that has been validated against the " + "debugger, rather than the newest release, because new WinDbg releases occasionally " + "break the DbgEng/TTD adapter.", this); + noteLabel->setWordWrap(true); + noteLabel->setStyleSheet("color: gray;"); + mainLayout->addWidget(noteLabel); mainLayout->addStretch(); @@ -83,80 +112,14 @@ WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& insta connect(m_cancelButton, &QPushButton::clicked, this, &WinDbgUpdateDialog::onCancelClicked); buttonLayout->addWidget(m_cancelButton); - m_updateButton = new QPushButton("Update", this); + /* Not "Update": when the installed version is newer than the supported one, this + * deliberately replaces it with an older build. */ + m_updateButton = new QPushButton(versionMatches ? "Reinstall" : "Install", this); m_updateButton->setDefault(true); connect(m_updateButton, &QPushButton::clicked, this, &WinDbgUpdateDialog::onUpdateClicked); buttonLayout->addWidget(m_updateButton); mainLayout->addLayout(buttonLayout); - - /* Connect signal for thread-safe UI update */ - connect(this, &WinDbgUpdateDialog::latestVersionReceived, - this, &WinDbgUpdateDialog::onLatestVersionReceived); - - /* Start fetching latest version in background */ - fetchLatestVersion(); -} - -void WinDbgUpdateDialog::fetchLatestVersion() -{ - /* Fetch in background thread */ - std::thread([this]() { - std::string version = GetWinDbgLatestVersion(); - emit latestVersionReceived(QString::fromStdString(version)); - }).detach(); -} - -void WinDbgUpdateDialog::onLatestVersionReceived(const QString& version) -{ - m_latestVersion = version.toStdString(); - updateUI(); -} - -void WinDbgUpdateDialog::updateUI() -{ - if (m_latestVersion.empty()) { - m_latestVersionLabel->setText("Unable to check"); - m_latestVersionLabel->setStyleSheet("font-weight: bold; color: red;"); - /* Can still reinstall even if we can't check latest version */ - m_statusLabel->setText( - "Unable to check for the latest version.\n\n" - "You can still reinstall the current version by clicking 'Reinstall'. " - "Binary Ninja will be closed and the installer will run." - ); - m_updateButton->setText("Reinstall"); - } else { - m_latestVersionLabel->setText(QString::fromStdString(m_latestVersion)); - - /* Handle case where installed version is unknown */ - if (m_installedVersion.empty()) { - m_latestVersionLabel->setStyleSheet("font-weight: bold; color: orange;"); - m_statusLabel->setText( - "Unable to determine installed version.\n\n" - "Click 'Reinstall' to install the latest version. " - "Binary Ninja will be closed and the installer will run." - ); - m_updateButton->setText("Reinstall"); - } else if (m_latestVersion == m_installedVersion) { - m_latestVersionLabel->setStyleSheet("font-weight: bold; color: green;"); - m_statusLabel->setText( - "You already have the latest version installed.\n\n" - "If you want to reinstall anyway, click 'Reinstall'. " - "Binary Ninja will be closed and the installer will run." - ); - m_updateButton->setText("Reinstall"); - } else { - m_latestVersionLabel->setStyleSheet("font-weight: bold; color: orange;"); - m_statusLabel->setText( - "A newer version is available!\n\n" - "Clicking 'Update' will:\n" - "1. Close Binary Ninja\n" - "2. Launch the installer to download and install the latest version\n" - "3. You can restart Binary Ninja after the installation completes" - ); - m_updateButton->setText("Update"); - } - } } void WinDbgUpdateDialog::onUpdateClicked() @@ -164,7 +127,7 @@ void WinDbgUpdateDialog::onUpdateClicked() /* Confirm with user */ QMessageBox::StandardButton reply = QMessageBox::question( this, - "Confirm Update", + "Confirm Installation", "Binary Ninja will now close and the WinDbg/TTD installer will start.\n\n" "Do you want to continue?", QMessageBox::Yes | QMessageBox::No, diff --git a/ui/windbgupdatedialog.h b/ui/windbgupdatedialog.h index 0ec49f36..5ccb6880 100644 --- a/ui/windbgupdatedialog.h +++ b/ui/windbgupdatedialog.h @@ -25,6 +25,11 @@ limitations under the License. #include #include +/* Dialog shown when WinDbg/TTD is already installed. + * + * The debugger installs a pinned WinDbg version rather than the latest release, so there is + * nothing to check online: we compare what is on disk against that constant and offer to + * (re)install it. */ class WinDbgUpdateDialog : public QDialog { Q_OBJECT @@ -32,27 +37,16 @@ class WinDbgUpdateDialog : public QDialog private: std::string m_installPath; std::string m_installedVersion; - std::string m_latestVersion; - QLabel* m_installedVersionLabel; - QLabel* m_latestVersionLabel; - QLabel* m_statusLabel; QPushButton* m_updateButton; QPushButton* m_cancelButton; - void fetchLatestVersion(); - void updateUI(); - public: WinDbgUpdateDialog(QWidget* parent, const std::string& installPath, const std::string& installedVersion); public Q_SLOTS: - void onLatestVersionReceived(const QString& version); void onUpdateClicked(); void onCancelClicked(); - -Q_SIGNALS: - void latestVersionReceived(const QString& version); }; #endif // WIN32 From 3b92139fa86d27cbaf4ae1cd8011f31a6a52946c Mon Sep 17 00:00:00 2001 From: Xusheng Date: Tue, 11 Aug 2026 17:28:01 -0400 Subject: [PATCH 3/5] Update the WinDbg/TTD dialog screenshot for the pinned-version UI --- docs/img/debugger/ttd_update_windbg.png | Bin 25568 -> 35316 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/img/debugger/ttd_update_windbg.png b/docs/img/debugger/ttd_update_windbg.png index 5d93dfb0a92e6a0a909ce4b870803d00ec9f491a..77e909b43b157998e9aa5ea28d934953111e56c0 100644 GIT binary patch literal 35316 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 literal 25568 zcmbTd1yCH_);2o01qi`{yIXK~cXzkogIjQS3mPoAySqCf!QI^n%}jSs_u6}}{j6s_YfXfbf+R8`E+Pm7LY9^iQvrb>*+C!(Ie1v$21YPAuKNp0@cPLJsZOSpAj6Sw4Fhq4=!*25bK|bJU}2*S7|X}H4lTc zHBWCf^K7P9MGE73adWhCS`ws5aJY=f2l%N^jBA2SxI7JY6QH}S?EUqYf!el^Mf8l6 zBb38x{GE{1T#J3$?HcQ8F&z7HJ3Qn7a&nhuljf$+tfkQ6Lbc|jD)({qf(L4IrD_!9 zdk1GH9po0CKb=!}4!pAW@Q2OOsUAtLo*YLhQa87wn1&W>O%vkd{aaeN92s#-pZ7%t zFc^R6L|7I$gp-9v?gUnTvpv4JkhHgF`kBoiRo(T7XqYX)@Dmc`5H38i$ZYz_d<1FDBUZrLo(svg%3|1qIREywaIXhc?IT{qUMs zosgmdp>&&S0K}`bwZPU$>Du{BEe%pVuxfd&7vfGbd9sftyp~ZtrY=@|-5; z+W(nxaPR6KH3JnH7dL!kHRCYO&}?)(Yu54f`egZf`HO35E#|e`7X}pmG(VWO>0!c;#N+`ONQyXk<`RlMJ1{s%;`|f;$2V3upO=?ErfVcQ zjX3CCJRuRC2aXBPk1y2(D4EejF^M}&A%f;SpUurlNCY5atBM{iIi`%So0g(kiOIVSL{^22tSWbhAN~ z2;i9D&RdOWLVg{&Y+zDNz<}IcT`l?7 zt9!VgCe`#&+;kJpp=cw{p!){%v!K6$phJ^kS!BBJ)JMKd78tHa##lBsVr~kUnPNrk zL{5*B3C`aqsRkb;cNUmBgEu%iBJUW z>R4E(=2xRDe#rIzk)pQhdd=8Ko3DP??R!+{?`dlT)@bIPzi{Zh z-Ou=QZ}=jEFE1v>e2$IBX)?p)i^f(n+I^y6`#8u{^LvzPP};bjVAlKKZpCqT?cRSr z?vtM$WL4)M(r72HPs>|9EnILzi2W^GR?F03Pz%vSVXKb6g~o?1A9sj;XRX-34d&^r znc3^k){#v`Rh8Me4_ehIAw4~^dBYbE6whLZ+jakPfmakZJ-r;6WHmEu{IU~g`eGUv zf{Bkj5cj%84kGs}`x1oIgl^rv@P>oF`IguIt?$qnS+|gzB-JBb+_hCLz z*F?Ap1vvz!k27ZYGqtrlSpD+!-h*o*;0@_CywAJBzdX6_=^}(PIG63AdqG%S*y*YM z1(kg8>~VA=z~^;}lzH>S+;z{V;O@TlRh9`ek+a0!vIoE*Wt4v}EGE*5#FDZ2weNavtRi{?TdDwKoAru6)bKy8 zI*0xaBAIjxJ^?(=tPG{TEc*-Kg>y$5g<@j@X!p4+grIrByENl&nqd_jtt@ddHmC4_ z2_tAW(EEjr4W`)o*_nl~S5`w){71*KY9hFwH`}u}<&)pDLt1`3^km}yVcpO3bK}7O z#vMMMj_Nn0=j}RiTf)B(hu-<}apwZ+XO^&{eRW#L=+=xTFB zM3GM#u)f3d)skZkRv`b|IKf!JDU~)R{eg{jy4I;nkP56bxciJlRY+P)tUpzt1}ECT zsJnZ^S2`vess|GYIK?&#+lJqLaevvpXg*(A#BId_ptJsr|NJ~9`FpkdmG0GN9Lv`G z`9P}8Br;7*3eMUFnX|uPR_*zC;}yC3bi>|KGZEM!z__cx()D$JZ@XvxE&ykmk>|ia zA@b9Exv&4lA4Vn_Ym|WB!q)~S05(P7unVW|OWW<63mU$xbVuZeb*9W~JYPx*s{Hje zJJTsBEFz_2MHg(jHvrz^EI2+ot{dWGks#mzT%K3tpMPdrrAb~)xt?4;;@N+c zX*2-#*D5eEp%3BVhZ(^3VdWtqblhR=oZi1+Gn-{eRnup1%7L{=MyUV>|Q1(f;il9YkapgBv893HCO2Osszc zv}724Lk8NE)xYf(lEChzqjvKy3f!rEDl31+-jE#i6wwOwqP zfvfb#dxyMWD&sm2-iCr*9WJCrhOUjJ zY-I6oD9rl#M^7{k>$`FMlFGr;rFuuezCVDy@5aT(QO`TE>n(l_F>!*~qOr@RKmSMz z*tx>{s+h%RWgTCBQ5r%5CXOav$t{MCBQ1X^Pm-ZYI#ZUJtdP;W+1WqXO)ER3gtv;U zxT6DT(K{2N{EyK+LvBjf%Qn?pL)!I|-#MTzZXr{t2J+1$K5*#sW8zhRi|lKli}(G_ zrRO!JRUzF9+1>GlHoN5ut*`H%T0yjQ&r_$6;qkjwt`nY)*T)l+s}zH!ZX#f{rDWyV zU6wQ;1DEP8c7*II!4ZcZ-Y;J&{7#uG{GJ_EF_ovFP(SX=%F3&+q`iUjk8J*xNlc&H zGWFwb<^km3AiJ>j75na(75nyy_=`7ew7pMENw>Dl(Y@(`@_32i1nED0^ogS?UsrsT z7}uCl%;vL#4^Db1GrRy|>a{)xuvB_E{t{?sZ-bm!oetcO6C66Npy&F$79LaieY>+e zJAlYH`s=|_G92h5Ob@Ey`ri|6TU&0}9~}_&^>vfWtI=_L;PzZ<{q|e^CQO+|RW=#E zX%$uEGxn>CHYA#vBJCpm+pFUzSXx>NeJ2`uut)k`*`ez=`z>(e4?vp?vj?jceJPNE zSNrGu-|Lv8e>B$Z(%gsrL33&hQqo9QQOrr| zKHAa%d{_DJ0tC(UTK)|UY#sN-f;;)B0zISWj5k>ibenM7jE`89Tv=(pd&w=n`*ID9 zP1`Y?8)DARtfyV4_T-NMteF5b24~35>-8aC|EDBk%ItfzDTlpG7K-N_3Fa?1mU3_R zf1TLaZ2QK_Y&=bVGh(=}5bnG=8-dRC<%Zh#seNN>2XLTP=Ys+AwY!5z{L{Lui4l1 zrEk|S{`cz#dM~htfrp{R(EAF?{__Bi|M3C;Hz(f@$C1CKL{bM9(r+UfM1*A*6BENg zCq=ZLKU)k%y!ZfQWf-mEC5yGl8L1Res(JJ{be$_owWjDAMd35BlFN1SC5y_ze2#$x zSH7k2jekR#t)9ZR7eAn(Eukwb)z@|)IG7W23K1uyW})ODc)2%5CFWHStnioDdJO8= z+M^dEb8>5GrlGKb2e&cHYZvR`7`EyA<;OnQuGb=;I5jFWw9lLTj+|@pn~Y;XLrdUC zgJCbR65`Js$+oy{$PV(v@vkoXFt=S`UzbEq4pCBFj#&&0Nf{ddo3{4rpDELU-%Wd- zO}QhTM1-{iB+c-cAz(GE6B$L76eH&&k(Ol7w&1;4^E;AS7vwt7Y-;t;5UvyjK5v2J zSIVSHYE>x86K`lkiEr6z>X1z5L7W>nMgsK><{6t4_odfXew;?x;H<8)53Ouuz{KDw zZL$>Q+kLNlIa(eVs?<82gAs(dkIQVbr^8w>FSDXPNx7o5&uIBI=i+)YH({!U1)5|a zm?^~?*5pRPS>6aen;|N;0L7i_y+0rWGCRqQ2WPaDSx`w;eO2JtxB^@ou5$kBrBjrW za@+g!s+Y?Ot(d{Vr!8lO;Dy$~9~6fdXK%(5_1X0mWl!UK1I5@jscef3&(1ba z9k)u%EBum3Me7B%q+Gj<;xat#5REf1%O;Jh@kQjER)-1QF@zbW4n8*E@Snu+XQ|bd zVBBpuWg3r5x8n6kE(gSzU%Q2K#dpr9w+d`Jji;vy;=w7nsdN z#y`=fwpY1pN|95sZoCK)PqN1Df2q9*_9ce(_2E~Onh6-}&PuA7eRD}gMx3OCd7}k#ZL5B%fU2yAL1@0qSBnE>|mvBz)M z;qeBoN)Zat{FqD(B6XhzmG#+v_2M{+i|Ue>8(8LEy|XbaM1O3~a(HNF(N zz#X(l0@zP2#!w=>LU?ND(nnBYmRlru!dTH%obY8l*qhF-#~jL)Da8vFXL-w3D4-m{ z9HO1vPzwMunK=O*n}Q|=na21(3g1eshuz|8D^<{%bkqdrO!8O7`5bg9OUK((7_@3l z@j4z9W>Z(Vx&S~{e*b&?9tacRj146n-f_SiOD-cNfRltyA2-&{kysZZtm|D2q`_VqK}`I1JnQf z@fa8$CL<9b1SCIni~7QgXYK)U++Z$z6yOQ0|7dkJ)a-mdK0cREFX2&m9;$|6{b-&_ zP+@8~SdKh^O*b*S4qTh@e+89L!pN@H6;Z-O5pCZ_3rmfA=0t|_7VN@9q5gA(|Ksrg zHzy_UR$F}~`=}i|7*N8Xc7|dG0p>cju)w5%LIOkgec697OILZ5pID*elS-`~Ss zwPDD#JN;|yB;>Da>b_6Q21qk0f)Muqz{_fLy?my(@yKv5GRRV7>8kj53Rj#_z=0>m z#8k}T7ntm@`y6dfL{9$Tu|AiVk1N>(*(qPx@^I-H=7a7RzyWu|ObPKUB{D^!dj}@7sm$$VA)U_jd!9(i8Hi zxlRY@THk0Da+K2D1p)*2%0uOaSnVFrOW0PUMWuVkii7%}_0!B0PV{wmNj`VbCs9!V53_NHX% z2$_c6-WBJEcMFoXflOFSau?&42B_q5lS`Q0OW&? zS|nSxpg<`0$pch{-~4^aH(ibIQB)mQp^b zxd$_GRa`$ zq0(p-Ff4%^Y6t%*E}%m``(YdUNP4A)XyEMqeL~WF${vl5f$I_MgrC1kRn9o|%y*qY zt5Vq-iV<()6JTY5L0X?MB9XTj;&GvH9+nBBZ02~QySFFK){b=u7>4ouRH@;^Uylsj zi!*9g%rs)ie4b0K7U}Iz{q1j+sBSYl9CNB#5lPamgG+XJhfDh_OR52USZ#Ry)m zh4%KHH;4uF#irR`qT7^}I}l;kVO_h7u)GaX0^1CF!Htn+$SZVvo4?rMuI0P+N%MMH zqXTiZw@GbjE_>^}F%csT15kk_#EjZoAeQx+W)K$F7|UG+MtJqks){lch_qI%82=D{ho>8*C#{V71l;@s&iRDW>UnG`N; z5NW5ez(llD-LI&nXU3zSf2bFJr*`uJJw{#7WHUFPi2xVATu7M&MovsjwC92-l!ASG zu(@$Y>v?@S0!8&m9xq)Nb+Zzr*aY&Q=V0r0?pY)wV@KQ4`-yE<2&Et9DAYpIt-eu! z*@z?@E^}{&AJ3<#ky2H5_~hPKiFH9&$njW)1hVW8fOV#cd-zNSg9)s4=+|%i^Bf(w zv91xKId)C&dgM5lP+Z_w=#$mn>Hqpz$cYVb>l0bh<(e1c(phO6)V!oCh_w0<11pta z$OEQNjW-nJ`c^Wt6eKia@d{#Wv!RAc=wDSJ<74wat$@SNM1Js#*gC8sR13spX>z|0t>~n}P_X*1Sjom(l+qtw;3fP`3C6 zfI}1f>T;f1{XkA3w=0XnH7ZUSx7GxD1vMA9JZ-<95fq#}`JQ2Q`uDvD~<3)41SQ}&JA~LL)o~-@pv)TR@9;;#kLuW6Bleb21hW?s+4sV zW#koKPUsEI+o8qm7IKs1-W9ZoGw$J5aWXI)eR5S+lt*w#Tma7pwc3$fV~aV5P17#L zl!`$8_8jB2+ZCcP0+FXuoAj*UkQ=qps8;Za6MybZ80w^9-X|p;QX9iQ(=+OvOFqIP`7(_O51%T zC#80dT{ee3%Bp3ba7H0gkmxz{T~h5yO{IS>JA&-qS6a~^3;kbt;r1gkil0b~8j`z> z)=OvG#;vq8}`+5O~< z?amTO+U^isfih>1n^Sy|B`L<{g1@x1)%xIf5Vmj_Y|x*Avxf8R0N;JkY@KKn+Ky zvAtIAa7M1146fT#++lFMf^ixqVE?0?esghG^p2jJO(Ap8(uwMh-b%O*Jj-jpyG=!O zEJ0oM3?BwQnU8VUKGpqTL`iaYZH_oVEEwgRMc;y;Pi(FHdV9tAr<@dC!OP>ln) zNN~Yl;FEd3_l&7I_Bl9%3dc2bjTWKVfV<{8n4<2D#W_g9TY@%=R;+6*&T;x%%J*M| zfde^sf^-$ViJHd}^5+BDBBqld(CASNm&>s9TAITZp6xnoi+#vo!?;dOR;$=z>YKtT2hGm*yy_U{4JEKQz*{^}s-dtg%`IhR zKi0E)rT2s3*Whu{Z;=1)jRFI4+G+&yQ87eofylS}1BU6{jD44FTF-f2mc5MIQnree zgN&z8)$}wswN9(B#0{fs1NM7SZYjs@gR#dki){js5T|brlF;csGFQ;k{s@HLxLlOa zHOYAfy*x?^rw!F_QBT9;`}Q^_dvr){ivCmPFFcjKrrTJ+w1=&ITF#FMR1}Kw z-f64diOIl1A@K#!hiGma;3{lLN?J>Z8|$Sja;J#jaf1R@z5Tz4HR?WJE=K&vKa^e z;%X2;QsB5*mbIVtq=ZVf|5G)PVM+em2*6+rzAnF$*L@AfASZa^nNG{j^J!3M1^Fc| zC@7c!)x46d=~Q3Op61;;{{lm3?ggX)c=Uf-j!4vW7);SJDKPm0yu2xn1wv00JSqd3 zRShaTAIn^IaLWy9I!U1tE|z1SU62a zlkN@{7RQcH#(dsy+k6_E&_fVI$x%bGJy(|bqJo|f3|7OSyKXRk>ZiEG;Ov?8ASr?3 z^7!ar@fi;?8b)u**^B^NV|nWlN4XoZ$)_CWrEfjL#z~gyDnlyN(jPt1p-}m`LAW)E*xGC+ zDJ6xnz_wn!M6uRcnOyw>vd0;lN{ru~{%dFcZ;I0=F9a{3!#f2*g_U|N%ed=0CY+>i zKgS7C#hq4NPTOXIqGU(|hv8H@ksGA4ne(N%H!o>8OmUzs2nf9-1mcfhamHWBWG9C7 zu$2s%?&#}LdU$xEAFR(Wab6`(2v?iElX3sN6VO-uu4<)Knc|%(Ubb4p@lZD-yfSM^ zfsg%D-TAM-o%It@B?fI~M`PWjjc1r#-omKy08Ff>QX6cIB0auIzlfgi6|=xmbN5mTH%+f0yRdFBL*^)8qamaXW1AUL79 z2VzosHLoM;vwwhOkH6Iw!tN-Ai5=AdEh}l>mX#J9`^?u>|I!B0G9AR9ZIR+^4D2vS zd_xlT_MXjoghDD`C-(l}Mm+#KS;G#fv$R`RTD|&hq`|^;tsY;#wBfsKbVASq(eaiinlm+Z@EnHGG8*9EpBY(mbR$ zi)G@K3hr8zztACEyZ!;SFso~t{GOMUQIDAv*IfuI_OynG+&^3?Eil?swTZSf6!;B; zf-mMooRGu~cV4Agv+_Qgpa^!=18+#)2VW< zUkLs_zhYCJ^_8Ualb0Y&aVMVmi3&p(gXWin>{1JKkT;hoSdgrfSRuWtV*t$8)Lo>m zX{D~huvk=3$RWU?VF>d%+0f?EA9gJ2=4Pc<1j*?1zz)9&e}3ICzn~CCL37#rx_Zt{ zuBW^FqJ8SBtfS*1i?aes7Fd_VJ~(y&Lzg>CE`qGqf}WDVznq@XlXTStJFnTsP>?RZ zz8wv|W3gUv@VOup4*uAL&8E0yLK zcbE?z+9%+B|GB$L;gnoSt&e%jPtqrmw#@}%H^=46;|FXC&w8gHeEHC1$5?0GyQ!Bm zSc1U|y<*vhvRk`n{Wxu@f2@GGx6npD^7You+u;!Q$69_zssuCP%6;$xe`ffhNW1@r zFQC(re!W~#e4~6U|HnBlov#M?oq6h6DoWA7u)7Hq3 zA2-8sICKhi3<3g#jwm!_Ko6Ud_nX4mG?L8khyu60>#@E1aJ{Y9bd$x4=czQau@P5m zIz()&28r)bGy7({t+LGL$H&LXnVF#Vt}cjSG-ZT;q(jDrE@ule8`ZbFvFZKa)W!aL z3GUzDd_R~&`R^ha-uzzVjAhBLXXw>O>S6DHYGR>Oj(>N7f>U2RwAFUB@S^_ExwpiX z0J0Z1pn)4GB?6^^D)65+|B6$5M_S|r>kFV>Q;UmdGe8rR`yX{NMbUP@H>Fvep+p)G zyxld)I+EpuBq*;2aDc&v!zw2Qrkm}4=Gn603QkFf1?a-{shZy|)~GtR&Yb#StX;{a zR?^K|-N*b9CD%isc_eR)0`7!<`fC|cq>FGW-*=wFVyhGV)bc&Y>pHU+{LqJrB60Vu zzOD~tzSAjoEXCL+IIe9}l545+*Wa|&YpK=w#*E5of7BT84r9-&v-eITwD>`jOe-NA z6ma`#h~Rs@HTnT6ztf!RTCW?Zk!$gz0jAnr5MI0%jXF{iJLHI#={uDFR=v_}U7A(P zQ>nNc18OM5Nw|AP2C$puWn%0}8Pm9Cxd`TT8m7M^D@!DKBI&_w+97!HYf6EGbQ(La z`e%J=AUm&`W;6$jpO|3(DLo4ojW3)zJ##T*Cgy(J%1XHOe@1%S2sFmER)g1~YFcw- zSB4$(a%MBDjjs4sl#(E3Q)N%C)LhBRCr$KuJhSaesO8{rn@wt8|Ik8|&ixK?T8Fqz z_L?-IBEUN>PJmE65^)(>(Vm9~3RrNBw7SDx1ZM)EE|i9kSd^rBN*DMiIx#q1Mq?eCV;)}nlN0qzXagmt=IA((Te zB$f*+pK{**95mt`|_KO$dFn++p@10xBV#ig9I)k70(#M z&z0vu{}aT6ML-$(llOjhgaQpYtbuAAaKHYDQ%^U>*|o#x0j{FXdfg{cPu%K6dzQ#1 z(UKYd&SreuU{o-9u~290{6g}U5m|f^`5qa=C~`?}s(2SfV}Ufi0kCn43usMkCYS&J?@y7wV{Qd6;|AZ z>2(%s2qRD!`A@ir)MiL%V#^s9#Q5-BngaNo3)DfS=J=eRpk9K~=KH_O6*f-PM%oVfT9RrVcz;oH~f4s-F)CK-nICSZC{_T?&8@`Mm1 zkcEXY3dqSAnnxC?TZ-hYpU)KP*7t$(eXm}6a%vX%58kBa1p~9@UT~rUv2md>*oJ)K zK(u{NAm;LI*`yL+*frEaw1qz6o1uw!K*g`{xuM#vvhn!1V)bS^Avu>RA>k?^IRR{~ ztMZb!S}(rvBz6{yUt>ms!5!~lLA(NB19lAO$jCf5_Wf=#ASUg37FcurmZ-2?YE(Qo z&Ts5j_M#r`49zQIK#)b6LAHCtLy?4!{)aTeM!AlDTAHKO0m86fCxbg5C1#Ba(S^9I zTwKYd7s_S7DcbCqe!f_w)9>m(ag`7g119eTF-Y)C7MUu4vOXWE6za5_W~^pQ9Ov1d z5|FRm3`k_E2+)I{?Ytbimn$`FHk1qrwSW7KSNW8>>Ddw@Gx& z5xygzgOxA9RN@&B>)!+`@a%0E3emIcmSS}#CY7pwh0)IouOs~a3i zu;S8BSs_=OE{XTO$rc^h-~IdMqkYlBKy=(ESgB#u%*?@2YC{{lwiOL=N0^>v=GMZd zNA2qh*8&<*Vn2V$732MjxW{+3E9Dn8>{T-lq-taa7(o23xB-ib8}m%IU`AMum7@BG3ldBJ$r{P&{o0X#k^z#qnng7}`-` zs@_^s?8VL&&$W^N=`*q0tOs`tFe`Wg#o=~pLeT#Iq=MGn=QwD zK>&c=!1lc|=mc~1K)oyU3S3!oP34m7$fGhpBr7^~{4drz(>0#jb!u7WB|3;b3jtV; znfhD1%BzwP*ObWvTIb`dq-v*HLG&O1K}+73-6YZSz4(5*&RyGXfm-%uW28FJ9jR_$ zm+uWIV}i#CmPwBRu_`h z7~QufpYctZgqKZNat+#}Hv-UcL~Hf`2K2*`4Ul4yKyq&~a0SMnUF(i3N@CNP_t4~~ zg_?_!T_KkOX~t5LNIFS&%4N_|@oJ9v z1<1j#Az{Mf1B1O-{2!ev`u0`?zmUCurv2i62_(sEEwmYH%Oy1wWF{35;w1i|5HAQm*V2@jUZ3VCZ-I>Qk) zOT*w&XykMV2^1+S&4u<7xAo-W)KqK=3Q>GQ1RsS|J-iu^X7pidE6o5A{;=$W+-_)D zN{l|)EU?d_?)wjP;4h2{suMFmwms75SxIY<1ZtG!N{i$nUAnr3qelm;r1AZN#b`;o zV;duG%tesbQ@~3)=Jk4`SPU@PfCH<@m|5d0p>lpz-JPygS^;p{Ow>#m*}9fjs@bkI zMvjx#utAlbcmuRY<-va)b+&7r-o$^Y;hKT>j1sOkVP?6ASVHk`D{*F~SyXvc-41I` zN~JVZ0pM)J$qqevS&^hnx`v2}(Po@KD2SbOdf%0#(}V-ldD+TRb94T#W$t-)+bAD> z$=xE<(oz9r=h%L1mLJ1M*7n?xUCBh!rc@1vcBITSW(J7Ng-I*^|7f{zUSBmpjIh~ zq!7JgIe)pF0lns=ncyw1sT4Mv;?cTQ2&bc&;XXrU37Yt%d$ zvZMOdI|`AaL`s$n578AWn$lZl_m71vk{WJJg5X(8N4_H|3X-QS=G&ggJOJx3+K}}d z0p}XY20AXMs7oUVJPEH?oRg2M!(}mmw8~Pcwm`yc>aL)R&*N58t>!H&w(NQI`pNoF zH)lfJ+*>M*!TO)o6A~2PZY}^+!Y$3-ve~h*tKk?zG6lq_=`$RCD8E!$pilC0|D?Ni zHn2@mty1OR3x1JcARn$sAs*$Yj>)S%UFKbS25eP0mT%?9jjedxUbL6q zq3j05W2bZ~DvsDEq1@Z`vzt%9ng{_&u<{3GrNpLFfm_*0^P%ROm6QYRAo_>$Nu5$5 z297bS&zM-+-tV0}RJ$e3AG!A7r{{tn8L1EncR7>a#urXq(%Z|Rg)gnHH1=UN5y+l& zi*vo-UuEYQZl=gY71%4lydLIVH5r-L&_c-QHjRE#BsY8oU!20~F;de=S=m6OKkhl+ znkEEXQ|zy$F_jkB0NJOVfMV=pu4K7g{5}#Uy_>PSIr=65r&ylT=-qi>o0VOwp)<_5 zLar=;yVQgSrl)W?dqvgAx%S3T;=fa)cylK_83!?Lt>Pz-eV~z4dEWB1rm%}YN`*g3 z-7;Ge(16rK%yhvCnHq)WHASQT#j_!u*2#GB>LsXS1^(hc+Ijtgjy_-f-0&wInKN3~ zxwTo@pU%VoF)no2(W)m^MH7|NKtJ1raAU}%8D}1D4y-i>ilmvad;!n`w_Q?Gz@SU6 zsc&`0UDkOuQ6ogdEhSN>Yu!@bU}3e?h?Twl0beYZO@x7Y8nPrs-)0Y#M|^{<|H9MC zhapm;fYh_sZ_rp!j)kXbEB@BnN(HAvL$Ijdfoa}Woz#4~OzM-%tNXLPFR$0mRUdtG zOsI;HTIp_SUCA?%rqEoR(AXz8c$p(n^fJXBGuFK1%{n%0wvq@r7AMv$A=9AJfnE<* zd&zc1+R@2Wa6?05ewzd$$C!9eZpY)wL7Nnq*78(YL+VZk( zz5qLNLkf6CLSP&*1&J_jJ1qMg3}@TaLj;G+kqSd{0h_eCL}-u1aez6sV?r2&Yk!rM zP$y#z?)z4|*y(HuoW3KgA|^YTHtFG@6{`>ZytanMZiy1Z-15w-AQw8h zSH>NfTo*=LB{I&>$g}U+FU~_8;B5brB#9jEnioUq$COw>#ea=%SS2-`i&zC=os$=Y zs7_$SQmbW2*~Jc6GneL8+l>kQGzeUk1EOgd?2VIHA?{d~p}*&L1GSWbi}kP^Nh&?S zbeEVtgyq4?{?>$KrOYL2xB1B9B?*3wA>ABvMD zBMPCwrwKK`p*e{naZA4*S6s#RfmJAegt?Q zCWVUWqDm=2s7gpKgGKi6F*<0@fCSY^X}k8iNU!!jvF;Qkh?8p#H1H;uv3Pdp@O2zh z36&y3O|~%IG(oFJ#q7y%j~tfJpx^ny9!F}wg_S$;y%j~aAESkY1pP{|Yp zsPu7Rp%1O;KsFrgv~F$xW8Fgz?(Q|MKi{v(YSpABTh+^Jn$LddLEb<1nyXO1J9|Up zgdXTsgmaZh>oy@^h8$h0CqqAIk!$1aM#Uzlvm9}G_CKjK6F{|J8h|=JCa&kaP=;RJ z^Cz7|4s7l_59kHKo@M642c_fFV+wLBsZzpmMCGYD3BN@i9W&vWXNu!klr6G|EBEiP zQCBLhLUa1_Q*AfF#J)97`c-`0UsJ5OEfukkd7#wU5w2mpaNqoZmm{aA(1%y%DW~{{ zQl&+wf}>&D^!tcH4CB+Vo|9<-A;bj{k3l=^aw>*t6nUMnl-NsicURs9Q=>*EApQN? zH34%3RkZEPej4;i#yNUi+s~Cy_&&Gkd-O?C^U5)P>O#J{`p5f(xx0)KB5-mTXjo#E zDa8tDc0l}L9>PqW+A(DZ8w5;iL0>Q_uED>zM;Fg z?*{RvIJDol1!@;J0uB%yk*BBry1m=I7W!Vi`6Nc?s`3kJ&GDTFxMw>v5k{YKdgGB( z48Y+P!d3gx z!iU-!_+A33eMiND1!|`IqS`_81%qR26Hu(vz?kQccrFqpLI#1%nOrWTW9&y%Fw*Z9GQ1>VFDL6BqhIW3$w#vHo4i2Wa5e5Y(d0 z(w$D-Dl|PTJ?8Lj<@e{?8^1hu0%Le$lZ=`Ol>3wzc-zn_FTt3ZpFs7=9hINrd~36t z_!r|ZeG2TvyZ6A(t@mKZ8b3&W3vKx9BMj3%E$ZvlRUwzScja#NlNZ>k%dO%?JDF-N z2=~E{KfZtywxF6+)+Y{lPM^C}cA45wnu^K%p!mK$s+}S=cI9+O5O-gcJX78TRv^_l zGcbRDGLKQ2B)WM<3*ku-zA9xiRl1K*XN8S&{!#oB{SPjAnXjXux708nb57b@$99do zrkBSPxhZnTx0q?3y||BX{G5>Ro<2&*o6WDtAGDQBDa;Z09u&3$@%Y()*@|noo=fVg zhSo{+WO2J2De@re&NcwQEl36*w&6*=$(wO%Pde_6ngYE@H;S5X0xLu|%P;@y5DAau zYVYQ=-j~5XRAzI8^8`N!lh?Hem?At8DUv%;r#y7aRqMqIAS!$CehsuWWLY+(7uNQS za0{?nfvS#oqaJH6=c60jbuPog+v@>DS5gvRpS7k{NOlMH*xbsOQeKqMJzP-#%j&kr zw{q(h{;oqQ0yG656#@lqZ_!>PYPjz!4%dZ%GcI3d_ zXl9Gl*@g6w0k0Tt6EWCo?-PUc^R*VkYU1OpkIADQ$VwVaW5k?kN^v<$((y76sB%Rc z68~lZN%szS5nGvw!9L){HUZ1Nr%JziG47JlUY-Z(QQmkwS*bHit8($iTr+B%(cEm< zp!elJb$D(tE&3v=RL|z}oFX1}qR+C{hS0VyT|aiu%>s$p+V?TlLE+q_ian$Jn5b~= z%NJt%sLO)of0D^%;*BJ0;D-*pWj4`PR8*nPi3ze4xF`rGrGvszIm)Xj?QcpqppwHE zM&;gFT<+u`uo1oGWK?wr(ogC-KVx<=N)Ft7^l?x)Af=_J`KAZ;f0S#nEXUp%x%T{< z2@Di#8+SL2c5{m^OH0kd(FII@wI}S=$`)1CAM$@+^ZNY#ciX!0W z%W)fJPjY}>R2eN@$_m(%9tI-NWyU_g--1>+v_s+dBYx(?mN2r3L6U4*{}R>qD?v}I z@%i^>HOmcTl7U>f z&MOysD-o}-xQpliL1~e4l?(Dj$O3y)A&IUW_<=>P-hj$J=?cY~9w77V35g;$OmJQt z0-4quP1dEKzm`>h=eF3o7tuICiOO=WmWr_BBP*1#oOu!0K2hG!i zK9a_Kp1&egp~O1jP)0)M{6ob|v!U`bMEH}oVpna{+y~F4yKFadpeJ(bvvvi3g_ai9 zA(zy+73744`i+790<@Xgo0{#GYsVYhR^{@eeFc+Eut~d#&c76w3aC@0%~MU}BPMB# zY-Hl!gwM6h>>SoW^C$*)NKAx0%Zq8|I1BQj;meNGVkxsst2ovCoV0Ah!W+*3HMVi^ z9lJ3hUH(6vePvuzZ`?kJf|P^-GE$`^C8SFb5ClX@X+)6jlm$2xq$QOODM{(>l928m z4HAO^gR$|P@q0d>|C{I4|Lx9p&b|Ab-S_vpzSngP#CRY}dO3G<<6OQKVE$BxeF1Y3 zT&YCO)&8e~KlqSNI`3!Jb=|J%*xNr<-lb?;SdXR!3POL~6s z;K=vEnrObgi<+C_B?m8bQTtru``f}k{!n+bg7s=6vUjI%4A;u<)yMr}$O!fNJhNNN z^vAnIA-*Xk#MrH*fCJLB#Z ztO|)#sx;VA2H_~{W(qt@il*4AbGK%wA_oxK7{FAPD!rtF4bel7~ z5q_Rz6dZ9_IR(np&;ZE6Hs2eu)5T@fn;%b9H~ug@(u-@EW&KM}xqj5SEoOm(sBDQ@ zv^Mb9e{xW#A0Yk5tX=@F`e(>fkuY5MWyg=@t?9mp-q5=JD?vBGH8;bHoCnjK3h|=Y z3DKNgavw;#IpbTvBUyv@NCK6m(nICTE4v}!AflnX?Fu-B7*&9mMKaM?XvdSEcysEv zzbvkb7C=p%Y4Pd*HXdodvOJeJ+7#mti52VEZnpcC3)K}UOi&wkvBZgIN(T${zFt_6 zppEd(6SLm9cYooq@E=@$qfT^ zDK6hma(cm@LZWzz$!rB2L@`D`{bGu64=tA)f0_C5*avjJh=XUJ{f%;d|0pRi$w4ra^T zS}Dy7DgOCPJweT8e(;PbK2d9~wP~PCp&s{-$$Z#`Z~l|7PRbRO{3-@ukdY%ey}xjV zheWB3G#XE&cw`-R(s;lhV#WpyDNsai?FwSsp!(&%&CXHI=ZYPNE58AmSCXYB(0;K1 z+ArY1RjNOFae-LWLx>Xf42h7=l`mCZRsC!#y^XV&=gP4<8uTSl zh58M_-ijbW@F--e_kYGNj z;SOBMNXer7o;ypYKj{y&m}~e(n&B*B$Ty)d^=r9o%v8H#1bvHX;>|u69y=v{V~z>p zW~>Ma(b5%bUm3ls>C)!#ty!7WiOC#RjB=AQ_oQdAZODdyiu-~cb6L^p+_b8?UEvFM zo|yz_I~yeGW3|Lk zl;r*08SXYM6>VDps~TATJ`CuMWuGd<3?=E0=L)==XsX~H(0Kq`(n!pm;n}!5q9QTA z9R|FkLGcVxr>n#Vi5f_rEPS@5n5p&+(jo%vo07F;?%t(IRQ~@+#8`j7?n|o~Jd!@A z8r=F-)#2V=Nxkr_2a`uJ-kXrarxuE@l%jmyAGrQPWxQ-p2x+Ibn+Pl%=IQOwkx9dz4Iu^@xh+(7u(?GS*0hy_K0O(4+ zUXI9W%X$5Bnw6i4s&S3LoOVkZ(M%p=;wrX7_o4*CO;)Y*Dna z+&Z)<;ip>oKS!BORn-LjWUtMp6`8Nx z#sR2kn|i$xjshmX0=PeFkM`naS)4;qy8xTh7%s2>w`297 zHyn3u^7BO(R&}DIeqI_)4AZ=jCvsO@zH1clOiIQN&*Qni^!rea6SyKSyS_KCDw)tU zws{y6q~ELmOm5q9#KtPYRc!;hXPoDF`z_Nb!A80%eYZpfULFx6TURF|B0Vh@140&=f_p_orMyb&$@ zgBE>p^^67ZS3xqWb7!Ey;}FO96(b;sZEy;K&emT3t!EJA(r+$T2CmVa8y(o&$;f96 zn{D?#8A{$ka|=Eu_PM2u75|`0_2j&DXu^^Upf7n=pF7Ob^4Wb=&TumEx;9P7EC#pv zNz>11qTqy9RJxTI9sQtzgJ2>cG6h8fc2d{#>9YDK%oaMLdRc{xAb zr(}NZ_&}wE&e1t@JcaRj%Mel}t?D@iS2xa;r2pj~4Y zlaFc-yC%(zY`0m)>}(BVOI4;Qt+V$Q(w4SBCMm8|k}M_I83L!Oi8BnsYUK!Dm^LJjuJI%Eo0Wij$#--Qzy~@#+KwiL|H1gHZ*f(_v2~2-u>gLSF zAKvEKuxjDkyFKgS*k0CYt1Z~#E?Cz+t*m`PT~;V`pO^cOY9F7FELYF2;gTlV1&C?M zRXA9gL4Ih3E>De1I-vON>vnT?G`YuITgf?P*PMugn%t|Udp?VS?+dt<{zDJc1bs}D zh1Uej_{!3iZS$9hA>nymmSt`Mr|GUoRPPvZvXn-)%!Hy#3!<(tLyvCk7v zxG~P=*$*Bce+QjviH~dfyMafwqxLIosHlk{v!ynmB?Xi5z5;%#Br#c==w6p>D;hwW1tVd8@4ay9ZjV8Tgo*qQq1S zR&r0a%Vx!8Zyt&EA*!8R=VJG^n|}3Dvp?|iB>Djwv#**EaQ-f+t-T{nQO z@cc8&HvR)-m`LO{%bafzq+8AHsd(~q)0&jk;~a=D@VFaaEm5EGsIIeFA1}bmXbhX7 ze7)Ff+LJU^E^lzbPm=Z8h~SLGNXL3^eS~7{Zjd&gMVz(#yM4}3>07~W{hk;SqxJ&m zwK2|@6bF^pKdN!RMNu9whOLSlF|Xj^Mx7eQc-M}xOf2bcZJ>Hn>UZ@3_&0`hhMC$t z6Kh31xD?h@I;|XKd+_qzYR=k$M1){F;iA`*4(EgSm$~08~~;* zsm6lON+-+jG9CJsq-H7jt^7C*AFnmpoe%lA_J)fpAqSH=QDm|xJcu@m^$Vfg^i~W} z_;|)VtjZy$K_(zoU;4!|HTa9%PQtb}FGEGbK25kyub=RPe6rA|wex*ZB7vL_7&3sK zCU@-K5}vMh{95{$Hzd|epe+gLmi7c+bv;E8zt6Aazr_C^3L)T{G?bs*KMW!+&X@rM zSV)Y`&5mwPbJV6bz3@aAc3|0GYQ_4I6<^CHGU2O^?agF42pQ9{bL%AfDPY=-aom#e zjt4M@c14Pm-#wYeMpbq7cB=%_5Om;m@s1xhuh4|3;}gUfomqNz_KhrB+GoU1_auB( zQ!bfM6^xzqDsq5?NZM4fgDM?RB)j9p!_<<#P7sx}di$8CF%E}TBu)xCB*R8{vS7}}E!3*2cS{IRQT@VN@kZiEIyM|;? zBPAsb2J$?AgmSce^I+fZgYo};M-I$Xrh?1%>I-}@XM#ozg&EY>F!`n8QnY&4%Ge(r zaWGmCh*DEXc8ID!FF0V zvN6kS_${4cB#iwtHo#Pf+lbC~+E>QLj6hoH@~OIpq&UScAcPLBsp(OS?$H4qQN;Fia2G9PKI1 ztx5==CZqq08f*|OvcBnV5$cQPvuD?oO+=V$z>jCBE|ilU)L~`Aw zvkyMv&O)+9xJ5KlYjUMq4nn%WY*&chNLyam={yTsPXEX03KscNS|E(-Q*yr<2hH1B zruc}cXlcg}qZz$yEY6ohiKV`e*VMz68jMxkzhkQxyFJmjaYwm3zqcwa57FMpf56G* z7DBV&Pn$@wZ1T@7N^-f7hx_h-!T7pfyvV@@G9=6g1!xotLAU< zb~f?fU--yG8!@r0Xmv>0cQ6Kr!2`33&?j;i*DqK2ePt&%&;u-yTd%9tcF4ddM!$P^ z$apVQOe7KKE;pPSjt!0HX43mCQDF?CWca|2GjP?fw2L&T5ZAcYU;A}LT_`xu{^I)j zq@ZTkajoz{k=8@`z=L^u3A&#vltFlTd@?& zD1FiLZndv({-cI;grSqlYV0;=ckFw7caKu;U9G~MARhkiI~SxdG`v#;9k3@>iX84P zMOHd(?StZ%^Ua_vaA*Cp_C7bb4t_8G6YQ9WBpF8dz%)5xCB@NlumHQi`NRT$U@&o@l#NbHT zB)`%YY_Mak7k#M{Imls!XoYd_i*g%Vu^4QXp8P$+Bk(5W{d(< zy)(x!Guf@{UU5xf5211wI5|tdE!Z*_$2*0+xI?f3Vj}q~y3k9iVLa`{N<>qbCq{GW z@I@VpUoJunx6)j?BZs>&8>zMe9>*Z-2LpZ>@YudxbERz(h7lhu!z|`YZnbQjw!{7r zG+b)qzyI=teg7;?oWfs~M|dd?B{6c3VVteO6Ad;wU^*iLpCfgEM?;Z;z=g59F1*hR z^3k}u_-%~^$HA80KEvptw?%XH^~)M8mH#DKf2zcN@pEQ|&%O~2-i+TRZr|^%5v;Ok zftws&3A`5!V;|%x>AlE^h{j z|I*r@`f$L65sqLS%@rlp;dr5K+#+oXWiL*;&WIgN3*TbF2rpn5zxy8Rbs@Fs+hk1% z@j6+C>o^5Q$wTrH{?w^O3uo;%W&2!m zii4lNh)wq#AwrPGB3%=0ybkHK+?lCLdo`iU2&IiI}j7g~Mt1{!DE+`S)pO{X~Nvr;>X$7Lh(^1f9;G0D*9 zhx-uX{$$%9Vmlrr_N7`B!I`2W*e!vUpAK`fqtXMuyVb4|noILpX}v3}#%7-EP9pt& zqShuime8*GkUl>agv`s1LVHfoXtHni%&V#W({|spM+C4|mW6Uv_2z*(s|#p;;?_Ly z98VfMzJ%TUqWa|O9-muZgFg{*n1#zB3<0e=`30(8)AxcBjnQas>HX2d;*H~ExbR5SvnuSK?J082qR3;hXek#STaq_sB0;6W@8DC^tm=ta!5_xa|{6=%gN|;9nsFunHIW0Qn_}UzrSq{v?$1f|WCzr1;6hh5X z_aP1X?$;6q&5E)m+-XuT79N35YO9z`ROC87pr7jJ?dXjNIoY3ncs(Ak!*t4R3c(1p z=#e8=FZ(~MCv0$DZgu;-Z+(B{rED2|tvk8@C9LiHZv>EK&XBIdsrByU-!#3b-JK@f zM;9}LG@ov{ce{LU&Rhg77#|#`z*4Cb1wsE?ta@Rc=GhKJ`ZC7bbtOhUfGHBO7)kIQ z>+NIRx#ok-hqdpCev`Le8xEA zn5i~2$HFB77IE8h2fvo@%11sYH`-+CXWuUt5mXw`6LN+R=Vt&118tGx4DL z*iLGPJD5l(7CkYB`?1uM>)54s-gfR)_#+m`Fg91p3S?N~YkIi615e9x8%5PyUMW<& zOK;y0)o|XY|JDTF844Hr8Md&lwvh+xpxr1cJ1B2X=LIWcEFnHLLPRxo_HhuoaG3P| z%JeblH?le{S=-k1h_xqqkxv$id_2ka6z z8i9Iy>o?3jyC)ndQ%I3W8+&I(Zv(L|GqH*6q(Q?85tMJk{0#^<4=MA4^W((Ao>KF zm4LG=M>2;$v4k(K%()*%3GI7JfF>67<%tM@(6hfa_rLz|rFVaE;5{?6B!0T~!sDrK z`y{$*jKhxLewaPFGd2v_Ye0%1)5rb*Oxbp z1OTvS6No%LUPf(=qJf#9AqgUy?~ceQsScw2f+WV&tc>?)l8w)7v##{BysEbjG> z{`~yo{VDu8OE>VA&&g2B?ucdJnE!byLl9ASB#TP*V9>(R#+$p(ff2UHHplw`KSK@kL8qS From 991d66b0d76a2bd625e374fe959aa660d07d3c99 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Fri, 14 Aug 2026 12:26:57 -0400 Subject: [PATCH 4/5] Make the WinDbg/TTD version a setting and drop the latest-version download The earlier commits on this branch pinned the version in a header but still kept the old "download whatever Microsoft released last" path around as a fallback, which is a lot of code for a path we do not want taken. Replace both with a single `debugger.windbgVersion` setting: - the installer takes `--windbg-version ` and builds the MSIX bundle URL directly from it, defaulting to `kDefaultVersion` in the new installer/windbg_version.h - the core passes the setting's value when it launches the installer, so a different released version can be installed without a new build - the appinstaller manifest download, XML parsing and version comparison are gone, along with the `check-update` command and the `GetWinDbgLatestVersion` FFI/API - the dialog compares the installed version against the setting instead of querying Microsoft in a background thread Co-Authored-By: Claude Opus 5 (1M context) --- core/debugger.cpp | 9 + core/windbginstaller.cpp | 5 + docs/guide/dbgeng-ttd.md | 11 +- installer/main.cpp | 28 ++- installer/windbg_installer.cpp | 307 +++++++++++---------------------- installer/windbg_installer.h | 5 +- installer/windbg_version.h | 17 +- ui/windbgupdatedialog.cpp | 44 +++-- ui/windbgupdatedialog.h | 6 +- 9 files changed, 170 insertions(+), 262 deletions(-) diff --git a/core/debugger.cpp b/core/debugger.cpp index d37ef548..6888d45b 100644 --- a/core/debugger.cpp +++ b/core/debugger.cpp @@ -28,6 +28,7 @@ limitations under the License. #include "adapters/localwindowskerneladapter.h" #include "adapters/windowsdumpfile.h" #include "adapters/windowsnativeadapter.h" + #include "../installer/windbg_version.h" #endif using namespace BinaryNinja; @@ -116,6 +117,14 @@ static void RegisterSettings() "description" : "Attempt to unload the already loaded DLL if they are from a wrong path. You may turn this on if the DbgEng DLLs, e.g., dbghelp.dll, is loaded from a wrong path, but it happens early than the debugger initialization", "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] })"); + settings->RegisterSetting("debugger.windbgVersion", + R"({ + "title" : "WinDbg/TTD Version", + "type" : "string", + "default" : ")" + std::string(WinDbgInstaller::kDefaultVersion) + R"(", + "description" : "The WinDbg version that 'Install WinDbg/TTD' downloads, e.g., 1.2603.20001.0. The default is a version validated against the debugger, since new WinDbg releases occasionally break the DbgEng/TTD adapter. Change it to install a different released version.", + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + })"); settings->RegisterSetting("debugger.defaultWindowsAdapter", R"({ "title" : "Default Windows Debug Adapter", diff --git a/core/windbginstaller.cpp b/core/windbginstaller.cpp index 3c7df7c9..f4aeeaef 100644 --- a/core/windbginstaller.cpp +++ b/core/windbginstaller.cpp @@ -88,6 +88,11 @@ InstallResult InstallWinDbg(const std::string& installPath, bool isUpdate) { if (!installPath.empty()) { cmdLine += " --path \"" + installPath + "\""; } + /* Install the version the user has configured, rather than the installer's built-in default */ + std::string version = Settings::Instance()->Get("debugger.windbgVersion"); + if (!version.empty()) { + cmdLine += " --windbg-version \"" + version + "\""; + } LogInfo("Running: %s", cmdLine.c_str()); diff --git a/docs/guide/dbgeng-ttd.md b/docs/guide/dbgeng-ttd.md index 7d50dc7f..ae063aad 100644 --- a/docs/guide/dbgeng-ttd.md +++ b/docs/guide/dbgeng-ttd.md @@ -32,8 +32,9 @@ The WinDbg installation only needs to be done once. The automatic installer handles all the complexity of downloading and extracting the WinDbg MSIX bundle. -Note that the installer deliberately installs a pinned WinDbg version that has been validated against the debugger, rather than the newest release. -New WinDbg releases occasionally ship regressions that break the DbgEng/TTD adapter, so the pinned version is bumped only after it has been tested. +By default, the installer installs a WinDbg version that has been validated against the debugger, rather than the newest release. +New WinDbg releases occasionally ship regressions that break the DbgEng/TTD adapter, so the default version is bumped only after the new release has been tested. +To install a different released version, set `debugger.windbgVersion` in the settings before running the installer. ### Reinstall WinDbg/TTD @@ -42,10 +43,10 @@ If you already have WinDbg/TTD installed: - Click `Debugger` -> `Install WinDbg/TTD` from the menu - A dialog will appear showing: - The currently installed version - - The version this debugger supports + - The version that will be installed, i.e., the value of `debugger.windbgVersion` - If the two match, you can click "Reinstall" to install it again, e.g. if the installation was damaged -- If they differ, click "Install" to replace the installed version with the supported one. - Note this can be a downgrade: if you installed a newer WinDbg yourself, this replaces it with the validated version +- If they differ, click "Install" to replace the installed version with the configured one. + Note this can be a downgrade: if you installed a newer WinDbg yourself, this replaces it with the configured version - Restart Binary Ninja afterwards diff --git a/installer/main.cpp b/installer/main.cpp index 6fd69a23..be2d5b4f 100644 --- a/installer/main.cpp +++ b/installer/main.cpp @@ -5,7 +5,7 @@ * Can be invoked directly by users or spawned by Binary Ninja API. * * Usage: - * windbg-installer install [--path ] [--quiet] [--json] + * windbg-installer install [--path ] [--windbg-version ] [--quiet] [--json] * windbg-installer version [--path ] [--json] * windbg-installer --help * @@ -230,11 +230,13 @@ void PrintUsage(const char* programName) { << "\n" << "Commands:\n" << " install Install or reinstall WinDbg/TTD\n" - << " version Show the installed and supported versions\n" + << " version Show the installed and the default version\n" << "\n" << "Options:\n" << " --path Specify installation directory\n" << " (default: %APPDATA%\\Binary Ninja\\windbg)\n" + << " --windbg-version \n" + << " WinDbg version to install (default: " << kDefaultVersion << ")\n" << " --update Update mode: wait for Binary Ninja to exit first\n" << " (use this when WinDbg DLLs may be loaded)\n" << " --quiet Suppress progress output (exit code only)\n" @@ -246,6 +248,7 @@ void PrintUsage(const char* programName) { << " " << programName << " install\n" << " " << programName << " install --update\n" << " " << programName << " install --path C:\\Tools\\WinDbg\n" + << " " << programName << " install --windbg-version 1.2603.20001.0\n" << "\n" << "Exit codes:\n" << " 0 Success\n" @@ -264,7 +267,7 @@ void PrintBanner() { } /* Command: install */ -int CmdInstall(const std::string& installPath, OutputMode mode, bool isUpdate) { +int CmdInstall(const std::string& installPath, const std::string& version, OutputMode mode, bool isUpdate) { /* Determine and print install path */ std::string targetPath = installPath.empty() ? GetDefaultInstallPath() : installPath; @@ -290,6 +293,7 @@ int CmdInstall(const std::string& installPath, OutputMode mode, bool isUpdate) { InstallConfig config; config.installPath = targetPath; + config.version = version; config.updateSettings = true; std::string lastStep; @@ -399,7 +403,7 @@ int CmdVersion(const std::string& installPath, OutputMode mode) { if (mode == OutputMode::Json) { std::cout << "{\"type\":\"version\",\"isInstalled\":" << (installed.isInstalled ? "true" : "false") << ",\"installed\":\"" << installed.version - << "\",\"supported\":\"" << kPinnedVersion + << "\",\"default\":\"" << kDefaultVersion << "\",\"installPath\":\"" << path << "\"}" << std::endl; } else if (mode == OutputMode::Human) { std::cout << "\n"; @@ -416,10 +420,10 @@ int CmdVersion(const std::string& installPath, OutputMode mode) { } ResetConsoleColor(); std::cout << "\n"; - std::cout << " Supported: " << kPinnedVersion << "\n"; - if (installed.isInstalled && installed.version != kPinnedVersion) { + std::cout << " Default: " << kDefaultVersion << "\n"; + if (installed.isInstalled && installed.version != kDefaultVersion) { SetConsoleColor(COLOR_YELLOW); - std::cout << "\n The installed version is not the supported one; run 'install' to replace it.\n"; + std::cout << "\n The installed version is not the default one; run 'install' to replace it.\n"; ResetConsoleColor(); } std::cout << "\n"; @@ -434,6 +438,7 @@ int main(int argc, char* argv[]) { /* Parse command line arguments */ std::string command; std::string installPath; + std::string version; OutputMode mode = OutputMode::Human; bool isUpdate = false; @@ -448,6 +453,13 @@ int main(int argc, char* argv[]) { std::cerr << "Error: --path requires a directory argument\n"; return 1; } + } else if (strcmp(argv[i], "--windbg-version") == 0) { + if (i + 1 < argc) { + version = argv[++i]; + } else { + std::cerr << "Error: --windbg-version requires a version argument\n"; + return 1; + } } else if (strcmp(argv[i], "--quiet") == 0 || strcmp(argv[i], "-q") == 0) { mode = OutputMode::Quiet; } else if (strcmp(argv[i], "--json") == 0) { @@ -481,7 +493,7 @@ int main(int argc, char* argv[]) { /* Execute command */ if (command == "install") { - return CmdInstall(installPath, mode, isUpdate); + return CmdInstall(installPath, version, mode, isUpdate); } else if (command == "version") { return CmdVersion(installPath, mode); } else { diff --git a/installer/windbg_installer.cpp b/installer/windbg_installer.cpp index 46116b16..ce72b2e3 100644 --- a/installer/windbg_installer.cpp +++ b/installer/windbg_installer.cpp @@ -12,7 +12,6 @@ #include "http_downloader.h" #include "zip_extractor.h" #include "signature_verifier.h" -#include "../vendor/pugixml/pugixml.hpp" #include #include #include @@ -29,18 +28,8 @@ namespace WinDbgInstaller { namespace { -/* URL for WinDbg appinstaller file (resolves to the latest release manifest) */ -const char* kWinDbgDownloadUrl = "https://aka.ms/windbg/download"; - -/* The pinned version we install lives in windbg_version.h, so that the UI can report the - * same value without asking the installer. - * - * If the pinned version cannot be downloaded for any reason (e.g. Microsoft removed it - * from the CDN), Install() automatically falls back to downloading the latest version via - * the appinstaller manifest, so installation still succeeds. */ - -/* Base host that serves the versioned MSIX bundles. */ -const char* kMsixBundleHost = "https://windbg.download.prss.microsoft.com/dbazure/prod"; +/* Base URL that serves the MSIX bundle of every WinDbg release */ +const char* kMsixBundleBaseUrl = "https://windbg.download.prss.microsoft.com/dbazure/prod"; /* Files required for valid installation */ const std::vector kRequiredFiles = { @@ -100,34 +89,14 @@ std::string GetTempFilePath(const std::string& extension) { return std::string(tempPath) + "windbg_" + guidStr + extension; } -/* Parse appinstaller XML to get MSIX bundle URL */ -std::string ParseAppInstallerXml(const std::string& appInstallerPath, LogCallback logCallback) { - Log(logCallback, LOG_INFO, "Parsing appinstaller XML: " + appInstallerPath); - - pugi::xml_document doc; - pugi::xml_parse_result result = doc.load_file(appInstallerPath.c_str()); - - if (!result) { - Log(logCallback, LOG_ERROR, "Failed to parse XML: " + std::string(result.description())); - return ""; - } - - /* Look for MainBundle element with Uri attribute */ - pugi::xml_node mainBundle = doc.child("AppInstaller").child("MainBundle"); - if (!mainBundle) { - Log(logCallback, LOG_ERROR, "MainBundle element not found in XML"); - return ""; - } - - pugi::xml_attribute uriAttr = mainBundle.attribute("Uri"); - if (!uriAttr) { - Log(logCallback, LOG_ERROR, "Uri attribute not found in MainBundle element"); - return ""; - } - - std::string msixUrl = uriAttr.value(); - Log(logCallback, LOG_INFO, "Found MSIX bundle URL: " + msixUrl); - return msixUrl; +/* Build the MSIX bundle URL for a specific WinDbg version. + * Microsoft hosts every release at a predictable path where the dots of the version are + * replaced with dashes, e.g. version "1.2603.20001.0" lives at + * "https://windbg.download.prss.microsoft.com/dbazure/prod/1-2603-20001-0/windbg.msixbundle" */ +std::string BuildMsixBundleUrl(const std::string& version) { + std::string pathVersion = version; + std::replace(pathVersion.begin(), pathVersion.end(), '.', '-'); + return std::string(kMsixBundleBaseUrl) + "/" + pathVersion + "/windbg.msixbundle"; } /* Print info about Binary Ninja settings (settings are configured by UI after install) */ @@ -151,137 +120,6 @@ void CleanupTempFiles(const std::vector& files, LogCallback logCall } } -/* Build the direct MSIX bundle download URL for a specific WinDbg version. - * Microsoft hosts each release at a predictable path where the dotted version string is - * rewritten with dashes, e.g. "1.2603.20001.0" -> - * "https://windbg.download.prss.microsoft.com/dbazure/prod/1-2603-20001-0/windbg.msixbundle". */ -std::string BuildMsixBundleUrl(const std::string& version) { - std::string pathVersion = version; - std::replace(pathVersion.begin(), pathVersion.end(), '.', '-'); - return std::string(kMsixBundleHost) + "/" + pathVersion + "/windbg.msixbundle"; -} - -/* Read the version string from an appinstaller manifest (empty on failure). */ -std::string ParseAppInstallerVersion(const std::string& appInstallerPath) { - pugi::xml_document doc; - if (!doc.load_file(appInstallerPath.c_str())) { - return ""; - } - pugi::xml_node appInstaller = doc.child("AppInstaller"); - if (!appInstaller) { - return ""; - } - pugi::xml_attribute versionAttr = appInstaller.attribute("Version"); - return versionAttr ? std::string(versionAttr.value()) : ""; -} - -/* Download, verify, extract and install a WinDbg MSIX bundle from the given URL. - * - * This is the shared core used by both the pinned-version path and the latest-version - * fallback. On success it writes the version marker file using `version`. Any temporary - * artifacts created here are appended to `tempFiles` so the caller can clean them up. */ -InstallResult InstallFromMsixUrl(const std::string& msixUrl, const std::string& version, - const std::string& installTarget, const InstallConfig& config, - std::vector& tempFiles) { - LogCallback logCallback = config.onLog; - ProgressCallback progressCallback = config.onProgress; - - /* Download MSIX bundle (this is the main download that shows progress) */ - ReportProgress(progressCallback, "Downloading WinDbg/TTD package from:", 0); - ReportProgress(progressCallback, msixUrl, 0); - - /* Note: the extension must be a recognized MSIX/APPX extension (not .zip) so that - * WinVerifyTrust engages the AppX signature provider during signature verification. */ - std::string msixPath = GetTempFilePath(".msixbundle"); - tempFiles.push_back(msixPath); - - auto msixDownloadProgressCb = [&](const DownloadProgress& dp) { - /* Report download percentage (0-100%) directly - this is the only step that needs progress display */ - int percent = 0; - if (dp.totalBytes > 0) { - percent = (int)(100 * dp.bytesDownloaded / dp.totalBytes); - } - ReportProgress(progressCallback, "Downloading...", percent, - dp.bytesDownloaded, dp.totalBytes, dp.bytesPerSecond); - }; - - if (!DownloadFileWithProgress(msixUrl, msixPath, msixDownloadProgressCb, logCallback)) { - return InstallResult(false, "Failed to download MSIX bundle"); - } - - /* Verify the downloaded bundle is genuinely signed by Microsoft. - * This must happen before we extract or trust any of its contents so that a - * tampered or substituted package (supply-chain attack) is rejected. */ - ReportProgress(progressCallback, "Verifying package signature...", 0); - - SignatureResult sigResult = VerifyMicrosoftSignature(msixPath, logCallback); - if (!sigResult.valid) { - return InstallResult(false, sigResult.errorMessage.empty() - ? "MSIX bundle signature verification failed" - : sigResult.errorMessage); - } - - /* Extract inner MSIX file from bundle */ - ReportProgress(progressCallback, "Extracting package contents...", 0); - - std::string tempExtractDir = GetTempFilePath("_extract"); - tempFiles.push_back(tempExtractDir); - - std::string innerMsixPath = ExtractFileFromZipArchive(msixPath, kInnerMsixName, tempExtractDir, logCallback); - if (innerMsixPath.empty()) { - return InstallResult(false, "Failed to extract inner MSIX file"); - } - - /* Extract WinDbg contents to installation directory */ - ReportProgress(progressCallback, "Installing WinDbg/TTD files...", 0); - - if (!ExtractZipArchive(innerMsixPath, installTarget, nullptr, logCallback)) { - return InstallResult(false, "Failed to extract WinDbg contents"); - } - - /* Verify installation */ - ReportProgress(progressCallback, "Verifying installation...", 0); - - if (!CheckInstallation(installTarget)) { - return InstallResult(false, "Installation verification failed - required files missing"); - } - - Log(logCallback, LOG_INFO, "WinDbg/TTD installed to: " + installTarget); - - /* Write version marker file so we can report the installed version later */ - if (!version.empty()) { - std::string versionFilePath = installTarget + "\\installed_version.txt"; - std::ofstream versionFile(versionFilePath); - if (versionFile.is_open()) { - versionFile << version; - versionFile.close(); - Log(logCallback, LOG_INFO, "Wrote version marker: " + version); - } else { - Log(logCallback, LOG_WARN, "Could not write version marker file"); - } - } - - return InstallResult(true); -} - -/* Common post-install steps shared by both install paths. */ -void FinishInstall(const std::string& installTarget, const InstallConfig& config, - std::vector& tempFiles) { - LogCallback logCallback = config.onLog; - ProgressCallback progressCallback = config.onProgress; - - /* Print settings info (actual settings configuration is done by UI) */ - if (config.updateSettings) { - std::string x64dbgEngPath = installTarget + "\\amd64"; - PrintSettingsInfo(x64dbgEngPath, logCallback); - } - - CleanupTempFiles(tempFiles, logCallback); - - ReportProgress(progressCallback, "Installation completed successfully!", 0); - Log(logCallback, LOG_INFO, "Please restart Binary Ninja to use WinDbg/TTD."); -} - } // anonymous namespace std::string GetDefaultInstallPath() { @@ -328,66 +166,115 @@ InstallResult Install(const InstallConfig& config) { } Log(logCallback, LOG_INFO, "Installation target: " + installTarget); - /* Attempt 1: install the pinned, known-good version directly by its versioned URL. - * We prefer a pinned version because the very latest WinDbg release occasionally - * ships regressions that break the debugger (issues #1129 and #1130). */ - { - std::string pinnedUrl = BuildMsixBundleUrl(kPinnedVersion); - Log(logCallback, LOG_INFO, "Installing pinned WinDbg version " + std::string(kPinnedVersion)); - - InstallResult pinnedResult = - InstallFromMsixUrl(pinnedUrl, kPinnedVersion, installTarget, config, tempFiles); - if (pinnedResult.success) { - FinishInstall(installTarget, config, tempFiles); - return pinnedResult; + /* Step 1: Determine which version to install and where to download it from. + * We install a specific version rather than whatever is newest, see windbg_version.h */ + std::string version = config.version.empty() ? kDefaultVersion : config.version; + std::string msixUrl = BuildMsixBundleUrl(version); + Log(logCallback, LOG_INFO, "Installing WinDbg/TTD version " + version); + + /* Step 2: Download MSIX bundle (this is the main download that shows progress) */ + ReportProgress(progressCallback, "Downloading WinDbg/TTD package from:", 0); + ReportProgress(progressCallback, msixUrl, 0); + + /* Note: the extension must be a recognized MSIX/APPX extension (not .zip) so that + * WinVerifyTrust engages the AppX signature provider during Step 2.5 verification. */ + std::string msixPath = GetTempFilePath(".msixbundle"); + tempFiles.push_back(msixPath); + + auto msixDownloadProgressCb = [&](const DownloadProgress& dp) { + /* Report download percentage (0-100%) directly - this is the only step that needs progress display */ + int percent = 0; + if (dp.totalBytes > 0) { + percent = (int)(100 * dp.bytesDownloaded / dp.totalBytes); } + ReportProgress(progressCallback, "Downloading...", percent, + dp.bytesDownloaded, dp.totalBytes, dp.bytesPerSecond); + }; - /* Pinned install failed (e.g. Microsoft removed this version from the CDN). - * Fall back to the latest version below so installation can still succeed. */ - Log(logCallback, LOG_WARN, "Failed to install pinned WinDbg version " - + std::string(kPinnedVersion) + " (" + pinnedResult.errorMessage - + "); falling back to the latest version"); + if (!DownloadFileWithProgress(msixUrl, msixPath, msixDownloadProgressCb, logCallback)) { + std::string error = "Failed to download MSIX bundle"; + Log(logCallback, LOG_ERROR, error); CleanupTempFiles(tempFiles, logCallback); - tempFiles.clear(); + return InstallResult(false, error); } - /* Attempt 2 (fallback): install the latest version the "old way" - download the - * appinstaller manifest, parse it for the current MSIX bundle URL and version. */ - ReportProgress(progressCallback, "Downloading WinDbg package information from:", 0); - ReportProgress(progressCallback, std::string(kWinDbgDownloadUrl), 0); + /* Step 2.5: Verify the downloaded bundle is genuinely signed by Microsoft. + * This must happen before we extract or trust any of its contents so that a + * tampered or substituted package (supply-chain attack) is rejected. */ + ReportProgress(progressCallback, "Verifying package signature...", 0); - std::string appInstallerPath = GetTempFilePath(".appinstaller"); - tempFiles.push_back(appInstallerPath); + SignatureResult sigResult = VerifyMicrosoftSignature(msixPath, logCallback); + if (!sigResult.valid) { + std::string error = sigResult.errorMessage.empty() + ? "MSIX bundle signature verification failed" + : sigResult.errorMessage; + Log(logCallback, LOG_ERROR, error); + CleanupTempFiles(tempFiles, logCallback); + return InstallResult(false, error); + } + + /* Step 3: Extract inner MSIX file from bundle */ + ReportProgress(progressCallback, "Extracting package contents...", 0); - if (!DownloadFileWithProgress(kWinDbgDownloadUrl, appInstallerPath, nullptr, logCallback)) { - std::string error = "Failed to download appinstaller file"; + std::string tempExtractDir = GetTempFilePath("_extract"); + tempFiles.push_back(tempExtractDir); + + std::string innerMsixPath = ExtractFileFromZipArchive(msixPath, kInnerMsixName, tempExtractDir, logCallback); + if (innerMsixPath.empty()) { + std::string error = "Failed to extract inner MSIX file"; Log(logCallback, LOG_ERROR, error); CleanupTempFiles(tempFiles, logCallback); return InstallResult(false, error); } - ReportProgress(progressCallback, "Parsing package information...", 0); + /* Step 4: Extract WinDbg contents to installation directory */ + ReportProgress(progressCallback, "Installing WinDbg/TTD files...", 0); - std::string msixUrl = ParseAppInstallerXml(appInstallerPath, logCallback); - if (msixUrl.empty()) { - std::string error = "Failed to parse appinstaller XML"; + if (!ExtractZipArchive(innerMsixPath, installTarget, nullptr, logCallback)) { + std::string error = "Failed to extract WinDbg contents"; Log(logCallback, LOG_ERROR, error); CleanupTempFiles(tempFiles, logCallback); return InstallResult(false, error); } - std::string latestVersion = ParseAppInstallerVersion(appInstallerPath); + /* Step 5: Verify installation */ + ReportProgress(progressCallback, "Verifying installation...", 0); - InstallResult latestResult = - InstallFromMsixUrl(msixUrl, latestVersion, installTarget, config, tempFiles); - if (!latestResult.success) { - Log(logCallback, LOG_ERROR, latestResult.errorMessage); + if (!CheckInstallation(installTarget)) { + std::string error = "Installation verification failed - required files missing"; + Log(logCallback, LOG_ERROR, error); CleanupTempFiles(tempFiles, logCallback); - return latestResult; + return InstallResult(false, error); + } + + Log(logCallback, LOG_INFO, "WinDbg/TTD installed to: " + installTarget); + + /* Step 5b: Write version marker file */ + { + std::string versionFilePath = installTarget + "\\installed_version.txt"; + std::ofstream versionFile(versionFilePath); + if (versionFile.is_open()) { + versionFile << version; + versionFile.close(); + Log(logCallback, LOG_INFO, "Wrote version marker: " + version); + } else { + Log(logCallback, LOG_WARN, "Could not write version marker file"); + } } - FinishInstall(installTarget, config, tempFiles); - return latestResult; + /* Step 6: Print settings info (actual settings configuration is done by UI) */ + if (config.updateSettings) { + std::string x64dbgEngPath = installTarget + "\\amd64"; + PrintSettingsInfo(x64dbgEngPath, logCallback); + } + + /* Cleanup */ + CleanupTempFiles(tempFiles, logCallback); + + ReportProgress(progressCallback, "Installation completed successfully!", 0); + Log(logCallback, LOG_INFO, "Please restart Binary Ninja to use WinDbg/TTD."); + + return InstallResult(true); } catch (const std::exception& e) { std::string error = "Exception during installation: " + std::string(e.what()); diff --git a/installer/windbg_installer.h b/installer/windbg_installer.h index 58c9fb17..d20af7e7 100644 --- a/installer/windbg_installer.h +++ b/installer/windbg_installer.h @@ -39,6 +39,7 @@ enum LogLevel { /* Installation configuration */ struct InstallConfig { std::string installPath; /* Override default install path (empty = use default) */ + std::string version; /* WinDbg version to install (empty = kDefaultVersion) */ bool updateSettings; /* Whether to update Binary Ninja settings (default: true) */ ProgressCallback onProgress; /* Progress callback */ LogCallback onLog; /* Logging callback */ @@ -95,10 +96,6 @@ struct VersionInfo { /* * Get version of installed WinDbg * - * There is deliberately no "latest version" query: we install the pinned version from - * windbg_version.h, so the only question worth asking is whether what is on disk matches - * that constant. - * * @param installPath Path to WinDbg installation (empty = use default) * @return Version info, or empty VersionInfo if not installed */ diff --git a/installer/windbg_version.h b/installer/windbg_version.h index 5939b23e..735dc20c 100644 --- a/installer/windbg_version.h +++ b/installer/windbg_version.h @@ -1,5 +1,5 @@ /* - * Pinned WinDbg/TTD version + * Default WinDbg/TTD version * * Copyright 2020-2026 Vector 35 Inc. * Licensed under the Apache License, Version 2.0 @@ -9,15 +9,14 @@ namespace WinDbgInstaller { -/* The WinDbg version we install and support. +/* The WinDbg version that the debugger installs by default. * - * We deliberately install a known-good, pinned version instead of always pulling the - * absolute latest, because a freshly released WinDbg occasionally ships regressions that - * break the debugger's DbgEng/TTD adapter (see issues #1129 and #1130). When Microsoft - * releases a new version we can validate it and bump this constant. + * We install a known-good version instead of the newest release, because a freshly + * released WinDbg occasionally ships regressions that break the DbgEng/TTD adapter (see + * issues #1129 and #1130). Bump this once a newer release has been validated. * - * This header is the single source of truth: the installer downloads this version, and the - * UI shows it as the version we support. */ -constexpr const char* kPinnedVersion = "1.2603.20001.0"; + * It is only the default: the "debugger.windbgVersion" setting overrides it, which allows + * installing any released version without a new build. */ +constexpr const char* kDefaultVersion = "1.2603.20001.0"; } // namespace WinDbgInstaller diff --git a/ui/windbgupdatedialog.cpp b/ui/windbgupdatedialog.cpp index ceb2a1a6..ebb35036 100644 --- a/ui/windbgupdatedialog.cpp +++ b/ui/windbgupdatedialog.cpp @@ -17,7 +17,6 @@ limitations under the License. #ifdef WIN32 #include "windbgupdatedialog.h" -#include "../installer/windbg_version.h" #include "debuggerapi.h" #include "progresstask.h" #include @@ -33,8 +32,10 @@ WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& insta setWindowTitle("WinDbg/TTD Version"); setMinimumWidth(450); - const std::string supportedVersion = WinDbgInstaller::kPinnedVersion; - const bool versionMatches = !m_installedVersion.empty() && (m_installedVersion == supportedVersion); + /* The version to install comes from a setting, so that a different released version can + * be installed without a new Binary Ninja build */ + const std::string targetVersion = BinaryNinja::Settings::Instance()->Get("debugger.windbgVersion"); + const bool versionMatches = !m_installedVersion.empty() && (m_installedVersion == targetVersion); QVBoxLayout* mainLayout = new QVBoxLayout(this); @@ -57,13 +58,13 @@ WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& insta installedLayout->addStretch(); versionLayout->addLayout(installedLayout); - QHBoxLayout* supportedLayout = new QHBoxLayout(); - supportedLayout->addWidget(new QLabel("Supported version:", this)); - QLabel* supportedVersionLabel = new QLabel(QString::fromStdString(supportedVersion), this); - supportedVersionLabel->setStyleSheet("font-weight: bold;"); - supportedLayout->addWidget(supportedVersionLabel); - supportedLayout->addStretch(); - versionLayout->addLayout(supportedLayout); + QHBoxLayout* targetLayout = new QHBoxLayout(); + targetLayout->addWidget(new QLabel("Version to install:", this)); + QLabel* targetVersionLabel = new QLabel(QString::fromStdString(targetVersion), this); + targetVersionLabel->setStyleSheet("font-weight: bold;"); + targetLayout->addWidget(targetVersionLabel); + targetLayout->addStretch(); + versionLayout->addLayout(targetLayout); mainLayout->addWidget(versionGroup); @@ -72,22 +73,18 @@ WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& insta statusLabel->setWordWrap(true); if (versionMatches) { statusLabel->setText( - "You have the supported version of WinDbg/TTD installed.\n\n" + "You already have this version of WinDbg/TTD installed.\n\n" "To reinstall it anyway, click 'Reinstall'. Binary Ninja will be closed and the " "installer will run." ); - } else if (m_installedVersion.empty()) { - statusLabel->setText( - "Unable to determine which version of WinDbg/TTD is installed.\n\n" - "Click 'Install' to install the supported version. Binary Ninja will be closed and " - "the installer will run." - ); } else { - statusLabel->setText( - "The installed version is not the version this debugger supports.\n\n" + statusLabel->setText(QString(m_installedVersion.empty() + ? "Unable to determine which version of WinDbg/TTD is installed." + : "The installed version differs from the version to install.") + + "\n\n" "Clicking 'Install' will:\n" "1. Close Binary Ninja\n" - "2. Launch the installer to download and install the supported version\n" + "2. Launch the installer to download and install the version listed above\n" "3. You can restart Binary Ninja after the installation completes" ); } @@ -95,9 +92,10 @@ WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& insta /* Explain why we do not simply track the latest WinDbg release */ QLabel* noteLabel = new QLabel( - "Binary Ninja installs a specific WinDbg version that has been validated against the " + "By default Binary Ninja installs a WinDbg version that has been validated against the " "debugger, rather than the newest release, because new WinDbg releases occasionally " - "break the DbgEng/TTD adapter.", this); + "break the DbgEng/TTD adapter. Use the \"debugger.windbgVersion\" setting to install a " + "different version.", this); noteLabel->setWordWrap(true); noteLabel->setStyleSheet("color: gray;"); mainLayout->addWidget(noteLabel); @@ -112,7 +110,7 @@ WinDbgUpdateDialog::WinDbgUpdateDialog(QWidget* parent, const std::string& insta connect(m_cancelButton, &QPushButton::clicked, this, &WinDbgUpdateDialog::onCancelClicked); buttonLayout->addWidget(m_cancelButton); - /* Not "Update": when the installed version is newer than the supported one, this + /* Not "Update": when the installed version is newer than the configured one, this * deliberately replaces it with an older build. */ m_updateButton = new QPushButton(versionMatches ? "Reinstall" : "Install", this); m_updateButton->setDefault(true); diff --git a/ui/windbgupdatedialog.h b/ui/windbgupdatedialog.h index 5ccb6880..d0fb9d3a 100644 --- a/ui/windbgupdatedialog.h +++ b/ui/windbgupdatedialog.h @@ -27,9 +27,9 @@ limitations under the License. /* Dialog shown when WinDbg/TTD is already installed. * - * The debugger installs a pinned WinDbg version rather than the latest release, so there is - * nothing to check online: we compare what is on disk against that constant and offer to - * (re)install it. */ + * The version to install comes from the "debugger.windbgVersion" setting rather than from + * whatever Microsoft released last, so there is nothing to check online: we compare what is + * on disk against that setting and offer to (re)install it. */ class WinDbgUpdateDialog : public QDialog { Q_OBJECT From 9e027b0d5ef6c82d66b78804f8c0176ebe0c83d8 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Fri, 14 Aug 2026 12:35:34 -0400 Subject: [PATCH 5/5] Document the debugger.windbgVersion setting, refresh the dialog screenshot Co-Authored-By: Claude Opus 5 (1M context) --- docs/guide/dbgeng-ttd.md | 13 ++++++++++++- docs/img/debugger/ttd_update_windbg.png | Bin 35316 -> 38744 bytes 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/guide/dbgeng-ttd.md b/docs/guide/dbgeng-ttd.md index ae063aad..a852cdbe 100644 --- a/docs/guide/dbgeng-ttd.md +++ b/docs/guide/dbgeng-ttd.md @@ -34,7 +34,18 @@ The automatic installer handles all the complexity of downloading and extracting By default, the installer installs a WinDbg version that has been validated against the debugger, rather than the newest release. New WinDbg releases occasionally ship regressions that break the DbgEng/TTD adapter, so the default version is bumped only after the new release has been tested. -To install a different released version, set `debugger.windbgVersion` in the settings before running the installer. + +#### Select the WinDbg Version to Install + +The version that the installer downloads is controlled by the `debugger.windbgVersion` setting: + +- In Binary Ninja, open the Settings view via the menu `Edit` -> `Settings`, or use the shortcut (Ctrl+,) +- Search for `debugger.windbgVersion` +- Set it to the version you wish to install, e.g., `1.2603.20001.0` + - Any released WinDbg version can be used, as long as Microsoft still hosts its MSIX bundle at + `https://windbg.download.prss.microsoft.com/dbazure/prod//windbg.msixbundle` + - Leave it at its default value unless you have a reason to use a different version +- Click `Debugger` -> `Install WinDbg/TTD` to install the version you have set ### Reinstall WinDbg/TTD diff --git a/docs/img/debugger/ttd_update_windbg.png b/docs/img/debugger/ttd_update_windbg.png index 77e909b43b157998e9aa5ea28d934953111e56c0..1a40b915ef7c5c82514c3de9c2f6e16c31b9225c 100644 GIT binary patch literal 38744 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
LfZO@0g0VlYvjTivC9{-sSDZQLqSdt%oR(w4z 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