From 515b6266c53094ce2337b5accef166659dc26891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20N=C3=A4tterlund?= Date: Fri, 3 May 2013 13:52:52 +0200 Subject: [PATCH] QNX: Fix shutdown of inferior and inserting breakpoints on Windows When debugging on a QNX device on Windows, neither DebugBreakProcess(..) nor "-exec-interrupt" works for interrupting the inferior process. Neither does sending it a SIGINT signal using "kill" on the device. This changes the local gdb process to run under the CtrlC stub on Windows when debugging on QNX. This enables us to send a Ctrl+C message to gdb, which interrupts the inferior, and allows us to insert breakpoints during runtime on Windows. Change-Id: I4b01fbe81138f3fe7a939a7e64267bac4eb8bf43 Reviewed-by: Andreas Holzammer Reviewed-by: Oswald Buddenhagen Reviewed-by: hjk --- src/libs/utils/process_ctrlc_stub.cpp | 20 +++++++++++++--- src/libs/utils/qtcprocess.cpp | 24 ++++++++++++++++--- src/libs/utils/qtcprocess.h | 3 +++ src/plugins/debugger/gdb/localgdbprocess.cpp | 17 +++++++++++-- src/plugins/debugger/gdb/localgdbprocess.h | 8 ++++++- .../debugger/gdb/remotegdbserveradapter.cpp | 7 ++++++ src/plugins/qnx/qnxruncontrolfactory.cpp | 2 +- 7 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/libs/utils/process_ctrlc_stub.cpp b/src/libs/utils/process_ctrlc_stub.cpp index 9deb84652d..07e200b9db 100644 --- a/src/libs/utils/process_ctrlc_stub.cpp +++ b/src/libs/utils/process_ctrlc_stub.cpp @@ -50,10 +50,12 @@ const wchar_t szTitle[] = L"qtcctrlcstub"; const wchar_t szWindowClass[] = L"wcqtcctrlcstub"; UINT uiShutDownWindowMessage; +UINT uiInterruptMessage; HWND hwndMain = 0; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -BOOL WINAPI ctrlHandler(DWORD dwCtrlType); +BOOL WINAPI shutdownHandler(DWORD dwCtrlType); +BOOL WINAPI interruptHandler(DWORD dwCtrlType); bool isSpaceOrTab(const wchar_t c); bool startProcess(wchar_t pCommandLine[]); @@ -64,8 +66,8 @@ int main(int argc, char **) return 1; } - SetConsoleCtrlHandler(ctrlHandler, TRUE); uiShutDownWindowMessage = RegisterWindowMessage(L"qtcctrlcstub_shutdown"); + uiInterruptMessage = RegisterWindowMessage(L"qtcctrlcstub_interrupt"); WNDCLASSEX wcex = {0}; wcex.cbSize = sizeof(wcex); @@ -117,9 +119,16 @@ int main(int argc, char **) LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == uiShutDownWindowMessage) { + SetConsoleCtrlHandler(interruptHandler, FALSE); + SetConsoleCtrlHandler(shutdownHandler, TRUE); GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); PostQuitMessage(0); return 0; + } else if (message == uiInterruptMessage) { + SetConsoleCtrlHandler(interruptHandler, TRUE); + SetConsoleCtrlHandler(shutdownHandler, FALSE); + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); + return 0; } switch (message) @@ -138,12 +147,17 @@ bool isSpaceOrTab(const wchar_t c) return c == L' ' || c == L'\t'; } -BOOL WINAPI ctrlHandler(DWORD /*dwCtrlType*/) +BOOL WINAPI shutdownHandler(DWORD /*dwCtrlType*/) { PostMessage(hwndMain, WM_DESTROY, 0, 0); return TRUE; } +BOOL WINAPI interruptHandler(DWORD /*dwCtrlType*/) +{ + return TRUE; +} + DWORD WINAPI processWatcherThread(LPVOID lpParameter) { HANDLE hProcess = reinterpret_cast(lpParameter); diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index e2c9f5f824..11da30f822 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -30,6 +30,8 @@ #include "qtcprocess.h" #include "stringutils.h" +#include + #include #include #include @@ -699,17 +701,28 @@ void QtcProcess::start() } #ifdef Q_OS_WIN -BOOL CALLBACK sendShutDownMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARAM lParam) +static BOOL sendMessage(UINT message, HWND hwnd, LPARAM lParam) { - static UINT uiShutDownMessage = RegisterWindowMessage(L"qtcctrlcstub_shutdown"); DWORD dwProcessID; GetWindowThreadProcessId(hwnd, &dwProcessID); if ((DWORD)lParam == dwProcessID) { - SendNotifyMessage(hwnd, uiShutDownMessage, 0, 0); + SendNotifyMessage(hwnd, message, 0, 0); return FALSE; } return TRUE; } + +BOOL CALLBACK sendShutDownMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARAM lParam) +{ + static UINT uiShutDownMessage = RegisterWindowMessage(L"qtcctrlcstub_shutdown"); + return sendMessage(uiShutDownMessage, hwnd, lParam); +} + +BOOL CALLBACK sendInterruptMessageToAllWindowsOfProcess_enumWnd(HWND hwnd, LPARAM lParam) +{ + static UINT uiInterruptMessage = RegisterWindowMessage(L"qtcctrlcstub_interrupt"); + return sendMessage(uiInterruptMessage, hwnd, lParam); +} #endif void QtcProcess::terminate() @@ -723,6 +736,11 @@ void QtcProcess::terminate() } #ifdef Q_OS_WIN +void QtcProcess::interrupt() +{ + QTC_ASSERT(m_useCtrlCStub, return); + EnumWindows(sendInterruptMessageToAllWindowsOfProcess_enumWnd, pid()->dwProcessId); +} // This function assumes that the resulting string will be quoted. // That's irrelevant if it does not contain quotes itself. diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 80f4477959..8a95dfbaad 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -60,6 +60,9 @@ public: #endif void start(); void terminate(); +#ifdef Q_OS_WIN + void interrupt(); +#endif enum SplitError { SplitOk = 0, //! All went just fine diff --git a/src/plugins/debugger/gdb/localgdbprocess.cpp b/src/plugins/debugger/gdb/localgdbprocess.cpp index 9655625544..4710e2def2 100644 --- a/src/plugins/debugger/gdb/localgdbprocess.cpp +++ b/src/plugins/debugger/gdb/localgdbprocess.cpp @@ -66,7 +66,8 @@ QByteArray LocalGdbProcess::readAllStandardError() void LocalGdbProcess::start(const QString &cmd, const QStringList &args) { - m_gdbProc.start(cmd, args); + m_gdbProc.setCommand(cmd, Utils::QtcProcess::joinArgs(args)); + m_gdbProc.start(); } bool LocalGdbProcess::waitForStarted() @@ -95,6 +96,18 @@ bool LocalGdbProcess::interrupt() return interruptProcess(pid, GdbEngineType, &m_errorString); } +#ifdef Q_OS_WIN +void LocalGdbProcess::setUseCtrlCStub(bool enable) +{ + m_gdbProc.setUseCtrlCStub(enable); +} + +void LocalGdbProcess::winInterruptByCtrlC() +{ + m_gdbProc.interrupt(); +} +#endif + QProcess::ProcessState LocalGdbProcess::state() const { return m_gdbProc.state(); @@ -117,7 +130,7 @@ void LocalGdbProcess::setProcessEnvironment(const QProcessEnvironment &env) void LocalGdbProcess::setEnvironment(const QStringList &env) { - m_gdbProc.setEnvironment(env); + m_gdbProc.setEnvironment(Utils::Environment(env)); } void LocalGdbProcess::setWorkingDirectory(const QString &dir) diff --git a/src/plugins/debugger/gdb/localgdbprocess.h b/src/plugins/debugger/gdb/localgdbprocess.h index 079e26ade1..46db7356cf 100644 --- a/src/plugins/debugger/gdb/localgdbprocess.h +++ b/src/plugins/debugger/gdb/localgdbprocess.h @@ -32,6 +32,8 @@ #include "abstractgdbprocess.h" +#include + namespace Debugger { namespace Internal { @@ -48,6 +50,10 @@ public: virtual qint64 write(const QByteArray &data); virtual void kill(); virtual bool interrupt(); +#ifdef Q_OS_WIN + void setUseCtrlCStub(bool enable); + void winInterruptByCtrlC(); +#endif virtual QProcess::ProcessState state() const; virtual QString errorString() const; @@ -58,7 +64,7 @@ public: virtual void setWorkingDirectory(const QString &dir); private: - QProcess m_gdbProc; + Utils::QtcProcess m_gdbProc; QString m_errorString; }; diff --git a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp index 70285fea1b..d4aec4c21d 100644 --- a/src/plugins/debugger/gdb/remotegdbserveradapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbserveradapter.cpp @@ -62,6 +62,9 @@ GdbRemoteServerEngine::GdbRemoteServerEngine(const DebuggerStartParameters &star { m_isMulti = false; m_targetPid = -1; +#ifdef Q_OS_WIN + m_gdbProc.setUseCtrlCStub(!startParameters.remoteExecutable.isEmpty()); // This is only set for QNX +#endif connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)), SLOT(uploadProcError(QProcess::ProcessError))); connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()), @@ -427,6 +430,10 @@ void GdbRemoteServerEngine::interruptInferior2() if (debuggerCore()->boolSetting(TargetAsync)) { postCommand("-exec-interrupt", GdbEngine::Immediate, CB(handleInterruptInferior)); +#ifdef Q_OS_WIN + } else if (m_isQnxGdb) { + m_gdbProc.winInterruptByCtrlC(); +#endif } else { bool ok = m_gdbProc.interrupt(); if (!ok) { diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp index f10dfec02a..17f9af2d6d 100644 --- a/src/plugins/qnx/qnxruncontrolfactory.cpp +++ b/src/plugins/qnx/qnxruncontrolfactory.cpp @@ -76,7 +76,7 @@ DebuggerStartParameters createStartParameters(const QnxRunConfiguration *runConf params.remoteChannel = device->sshParameters().host + QLatin1String(":-1"); params.displayName = runConfig->displayName(); params.remoteSetupNeeded = true; - params.closeMode = DetachAtClose; + params.closeMode = KillAtClose; QnxQtVersion *qtVersion = dynamic_cast(QtSupport::QtKitInformation::qtVersion(k)); -- GitLab