Commit 515b6266 authored by Tobias Nätterlund's avatar Tobias Nätterlund Committed by hjk

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: default avatarAndreas Holzammer <andreas.holzammer@kdab.com>
Reviewed-by: default avatarOswald Buddenhagen <oswald.buddenhagen@digia.com>
Reviewed-by: default avatarhjk <hjk121@nokiamail.com>
parent 14eee567
......@@ -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<HANDLE>(lpParameter);
......
......@@ -30,6 +30,8 @@
#include "qtcprocess.h"
#include "stringutils.h"
#include <utils/qtcassert.h>
#include <QDir>
#include <QDebug>
#include <QCoreApplication>
......@@ -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.
......
......@@ -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
......
......@@ -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)
......
......@@ -32,6 +32,8 @@
#include "abstractgdbprocess.h"
#include <utils/qtcprocess.h>
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;
};
......
......@@ -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) {
......
......@@ -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<QnxQtVersion *>(QtSupport::QtKitInformation::qtVersion(k));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment