forked from qt-creator/qt-creator
CDB: Perform dumper initialization in a thread.
... with an event loop with disabled user input to keep the GUI alive.
This commit is contained in:
@@ -1878,9 +1878,6 @@ void CdbDebugEnginePrivate::updateStackTrace()
|
|||||||
m_firstActivatedFrame = true;
|
m_firstActivatedFrame = true;
|
||||||
if (current >= 0) {
|
if (current >= 0) {
|
||||||
manager()->stackHandler()->setCurrentIndex(current);
|
manager()->stackHandler()->setCurrentIndex(current);
|
||||||
// First time : repaint
|
|
||||||
if (m_dumper->isEnabled() && m_dumper->state() != CdbDumperHelper::Initialized)
|
|
||||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
||||||
m_engine->activateFrame(current);
|
m_engine->activateFrame(current);
|
||||||
} else {
|
} else {
|
||||||
// Clean out variables
|
// Clean out variables
|
||||||
|
|||||||
@@ -42,6 +42,9 @@
|
|||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QTextStream>
|
#include <QtCore/QTextStream>
|
||||||
#include <QtCore/QTime>
|
#include <QtCore/QTime>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
#include <QtCore/QEventLoop>
|
||||||
|
#include <QtGui/QApplication>
|
||||||
|
|
||||||
enum { loadDebug = 0 };
|
enum { loadDebug = 0 };
|
||||||
enum { dumpDebug = 0 };
|
enum { dumpDebug = 0 };
|
||||||
@@ -228,6 +231,111 @@ static QString msgLoadSucceeded(const QString &library, bool injectOrCall)
|
|||||||
arg(library, msgMethod(injectOrCall));
|
arg(library, msgMethod(injectOrCall));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dumper initialization as a background thread.
|
||||||
|
// Befriends CdbDumperHelper and calls its methods
|
||||||
|
class CdbDumperInitThread : public QThread {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static inline bool ensureDumperInitialized(CdbDumperHelper &h, QString *errorMessage);
|
||||||
|
|
||||||
|
virtual void run();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void logMessage(int channel, const QString &m);
|
||||||
|
void statusMessage(const QString &m, int timeOut);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit CdbDumperInitThread(CdbDumperHelper &h, QString *errorMessage);
|
||||||
|
|
||||||
|
CdbDumperHelper &m_helper;
|
||||||
|
bool m_ok;
|
||||||
|
QString *m_errorMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
CdbDumperInitThread::CdbDumperInitThread(CdbDumperHelper &h, QString *errorMessage) :
|
||||||
|
m_helper(h),
|
||||||
|
m_ok(false),
|
||||||
|
m_errorMessage(errorMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CdbDumperInitThread::ensureDumperInitialized(CdbDumperHelper &h, QString *errorMessage)
|
||||||
|
{
|
||||||
|
// Quick state check
|
||||||
|
switch (h.state()) {
|
||||||
|
case CdbDumperHelper::Disabled:
|
||||||
|
*errorMessage = QLatin1String("Internal error, attempt to call disabled dumper");
|
||||||
|
return false;
|
||||||
|
case CdbDumperHelper::Initialized:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Need a thread to do initialization work. Typically
|
||||||
|
// takes several seconds depending on debuggee size.
|
||||||
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
|
CdbDumperInitThread thread(h, errorMessage);
|
||||||
|
connect(&thread, SIGNAL(statusMessage(QString,int)),
|
||||||
|
h.m_manager, SLOT(showStatusMessage(QString,int)),
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
connect(&thread, SIGNAL(logMessage(int,QString)),
|
||||||
|
h.m_manager, SLOT(showDebuggerOutput(int,QString)),
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
QEventLoop eventLoop;
|
||||||
|
connect(&thread, SIGNAL(finished()), &eventLoop, SLOT(quit()), Qt::QueuedConnection);
|
||||||
|
thread.start();
|
||||||
|
if (thread.isRunning())
|
||||||
|
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
if (thread.m_ok) {
|
||||||
|
h.m_manager->showStatusMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Stopped / Custom dumper library initialized."), -1);
|
||||||
|
h.m_manager->showDebuggerOutput(LogMisc, h.m_helper.toString());
|
||||||
|
h.m_state = CdbDumperHelper::Initialized;
|
||||||
|
} else {
|
||||||
|
h.m_state = CdbDumperHelper::Disabled; // No message here
|
||||||
|
*errorMessage = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The custom dumper library could not be initialized: %1").arg(*errorMessage);
|
||||||
|
h.m_manager->showStatusMessage(*errorMessage, -1);
|
||||||
|
h.m_manager->showQtDumperLibraryWarning(*errorMessage);
|
||||||
|
}
|
||||||
|
if (loadDebug)
|
||||||
|
qDebug() << Q_FUNC_INFO << '\n' << thread.m_ok;
|
||||||
|
return thread.m_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CdbDumperInitThread ::run()
|
||||||
|
{
|
||||||
|
switch (m_helper.state()) {
|
||||||
|
// Injection load failed or disabled: Try a call load.
|
||||||
|
case CdbDumperHelper::NotLoaded:
|
||||||
|
case CdbDumperHelper::InjectLoading:
|
||||||
|
case CdbDumperHelper::InjectLoadFailed:
|
||||||
|
// Also shows up in the log window.
|
||||||
|
emit statusMessage(msgLoading(m_helper.m_library, false), -1);
|
||||||
|
switch (m_helper.initCallLoad(m_errorMessage)) {
|
||||||
|
case CdbDumperHelper::CallLoadOk:
|
||||||
|
case CdbDumperHelper::CallLoadAlreadyLoaded:
|
||||||
|
emit logMessage(LogMisc, msgLoadSucceeded(m_helper.m_library, false));
|
||||||
|
m_helper.m_state = CdbDumperHelper::Loaded;
|
||||||
|
break;
|
||||||
|
case CdbDumperHelper::CallLoadError:
|
||||||
|
*m_errorMessage = msgLoadFailed(m_helper.m_library, false, *m_errorMessage);
|
||||||
|
m_ok = false;
|
||||||
|
return;
|
||||||
|
case CdbDumperHelper::CallLoadNoQtApp:
|
||||||
|
emit logMessage(LogMisc, QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The debuggee does not appear to be Qt application."));
|
||||||
|
m_helper.m_state = CdbDumperHelper::Disabled; // No message here
|
||||||
|
m_ok = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CdbDumperHelper::Loaded: // Injection load succeeded, ideally
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Perform remaining initialization
|
||||||
|
emit statusMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Initializing dumpers..."), -1);
|
||||||
|
m_ok = m_helper.initResolveSymbols(m_errorMessage) && m_helper.initKnownTypes(m_errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------- CdbDumperHelper
|
// ------------------- CdbDumperHelper
|
||||||
|
|
||||||
CdbDumperHelper::CdbDumperHelper(DebuggerManager *manager,
|
CdbDumperHelper::CdbDumperHelper(DebuggerManager *manager,
|
||||||
@@ -337,63 +445,6 @@ CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMess
|
|||||||
return CallLoadOk;
|
return CallLoadOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdbDumperHelper::ensureInitialized(QString *errorMessage)
|
|
||||||
{
|
|
||||||
if (loadDebug)
|
|
||||||
qDebug() << "ensureInitialized thread: " << m_dumperCallThread << " state: " << m_state;
|
|
||||||
|
|
||||||
switch (m_state) {
|
|
||||||
case Disabled:
|
|
||||||
*errorMessage = QLatin1String("Internal error, attempt to call disabled dumper");
|
|
||||||
return false;
|
|
||||||
case Initialized:
|
|
||||||
return true;
|
|
||||||
// Injection load failed or disabled: Try a call load.
|
|
||||||
case NotLoaded:
|
|
||||||
case InjectLoading:
|
|
||||||
case InjectLoadFailed:
|
|
||||||
// Also shows up in the log window.
|
|
||||||
m_manager->showStatusMessage(msgLoading(m_library, false), 10000);
|
|
||||||
switch (initCallLoad(errorMessage)) {
|
|
||||||
case CallLoadOk:
|
|
||||||
case CallLoadAlreadyLoaded:
|
|
||||||
m_manager->showDebuggerOutput(LogMisc, msgLoadSucceeded(m_library, false));
|
|
||||||
m_state = Loaded;
|
|
||||||
break;
|
|
||||||
case CallLoadError:
|
|
||||||
*errorMessage = msgLoadFailed(m_library, false, *errorMessage);
|
|
||||||
m_manager->showDebuggerOutput(LogError, *errorMessage);
|
|
||||||
m_manager->showQtDumperLibraryWarning(*errorMessage);
|
|
||||||
m_state = Disabled; // No message here, no point in retrying
|
|
||||||
return false;
|
|
||||||
case CallLoadNoQtApp:
|
|
||||||
m_manager->showDebuggerOutput(LogMisc, QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The debuggee does not appear to be Qt application."));
|
|
||||||
m_state = Disabled; // No message here
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Loaded: // Injection load succeeded, ideally
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Perform remaining initialization
|
|
||||||
m_manager->showStatusMessage(QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Initializing dumpers..."), 10000);
|
|
||||||
const bool ok = initResolveSymbols(errorMessage) && initKnownTypes(errorMessage);
|
|
||||||
if (ok) {
|
|
||||||
m_manager->showDebuggerOutput(LogMisc, QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "Custom dumper library initialized."));
|
|
||||||
m_manager->showDebuggerOutput(LogMisc, m_helper.toString());
|
|
||||||
m_state = Initialized;
|
|
||||||
} else {
|
|
||||||
m_state = Disabled; // No message here
|
|
||||||
*errorMessage = QCoreApplication::translate("Debugger::Internal::CdbDumperHelper", "The custom dumper library could not be initialized: %1").arg(*errorMessage);
|
|
||||||
m_manager->showDebuggerOutput(LogMisc, *errorMessage);
|
|
||||||
m_manager->showQtDumperLibraryWarning(*errorMessage);
|
|
||||||
}
|
|
||||||
if (loadDebug)
|
|
||||||
qDebug() << Q_FUNC_INFO << '\n' << ok;
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve address and optionally size of a symbol.
|
// Retrieve address and optionally size of a symbol.
|
||||||
static inline bool getSymbolAddress(CIDebugSymbols *sg,
|
static inline bool getSymbolAddress(CIDebugSymbols *sg,
|
||||||
const QString &name,
|
const QString &name,
|
||||||
@@ -429,6 +480,8 @@ bool CdbDumperHelper::initResolveSymbols(QString *errorMessage)
|
|||||||
{
|
{
|
||||||
// Resolve the symbols we need (potentially namespaced).
|
// Resolve the symbols we need (potentially namespaced).
|
||||||
// There is a 'qDumpInBuffer' in QtCore as well.
|
// There is a 'qDumpInBuffer' in QtCore as well.
|
||||||
|
if (loadDebug)
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
m_dumpObjectSymbol = QLatin1String("*qDumpObjectData440");
|
m_dumpObjectSymbol = QLatin1String("*qDumpObjectData440");
|
||||||
QString inBufferSymbol = QLatin1String("*qDumpInBuffer");
|
QString inBufferSymbol = QLatin1String("*qDumpInBuffer");
|
||||||
QString outBufferSymbol = QLatin1String("*qDumpOutBuffer");
|
QString outBufferSymbol = QLatin1String("*qDumpOutBuffer");
|
||||||
@@ -455,6 +508,8 @@ bool CdbDumperHelper::initResolveSymbols(QString *errorMessage)
|
|||||||
// Call query protocol to retrieve known types and sizes
|
// Call query protocol to retrieve known types and sizes
|
||||||
bool CdbDumperHelper::initKnownTypes(QString *errorMessage)
|
bool CdbDumperHelper::initKnownTypes(QString *errorMessage)
|
||||||
{
|
{
|
||||||
|
if (loadDebug)
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
const double dumperVersionRequired = 1.3;
|
const double dumperVersionRequired = 1.3;
|
||||||
QByteArray output;
|
QByteArray output;
|
||||||
QString callCmd;
|
QString callCmd;
|
||||||
@@ -471,7 +526,7 @@ bool CdbDumperHelper::initKnownTypes(QString *errorMessage)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (loadDebug || dumpDebug)
|
if (loadDebug || dumpDebug)
|
||||||
qDebug() << Q_FUNC_INFO << m_helper.toString(true);
|
qDebug() << Q_FUNC_INFO << '\n' << m_helper.toString(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,7 +676,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpTypeI(const WatchData &wd, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure types are parsed and known.
|
// Ensure types are parsed and known.
|
||||||
if (!ensureInitialized(errorMessage)) {
|
if (!CdbDumperInitThread::ensureDumperInitialized(*this, errorMessage)) {
|
||||||
*errorMessage = msgDumpFailed(wd, errorMessage);
|
*errorMessage = msgDumpFailed(wd, errorMessage);
|
||||||
m_manager->showDebuggerOutput(LogError, *errorMessage);
|
m_manager->showDebuggerOutput(LogError, *errorMessage);
|
||||||
return DumpError;
|
return DumpError;
|
||||||
@@ -768,3 +823,5 @@ void CdbDumperHelper::setDumperCallThread(unsigned long t)
|
|||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
#include "cdbdumperhelper.moc"
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class DebuggerManager;
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
struct CdbComInterfaces;
|
struct CdbComInterfaces;
|
||||||
|
class CdbDumperInitThread;
|
||||||
|
|
||||||
/* For code clarity, all the stuff related to custom dumpers goes here.
|
/* For code clarity, all the stuff related to custom dumpers goes here.
|
||||||
* "Custom dumper" is a library compiled against the current
|
* "Custom dumper" is a library compiled against the current
|
||||||
@@ -108,11 +109,10 @@ public:
|
|||||||
void setDumperCallThread(unsigned long t);
|
void setDumperCallThread(unsigned long t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class CdbDumperInitThread;
|
||||||
enum CallLoadResult { CallLoadOk, CallLoadError, CallLoadNoQtApp, CallLoadAlreadyLoaded };
|
enum CallLoadResult { CallLoadOk, CallLoadError, CallLoadNoQtApp, CallLoadAlreadyLoaded };
|
||||||
|
|
||||||
void clearBuffer();
|
void clearBuffer();
|
||||||
|
|
||||||
bool ensureInitialized(QString *errorMessage);
|
|
||||||
CallLoadResult initCallLoad(QString *errorMessage);
|
CallLoadResult initCallLoad(QString *errorMessage);
|
||||||
bool initResolveSymbols(QString *errorMessage);
|
bool initResolveSymbols(QString *errorMessage);
|
||||||
bool initKnownTypes(QString *errorMessage);
|
bool initKnownTypes(QString *errorMessage);
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ struct DebuggerManagerActions;
|
|||||||
class DebuggerPlugin;
|
class DebuggerPlugin;
|
||||||
class CdbDebugEventCallback;
|
class CdbDebugEventCallback;
|
||||||
class CdbDumperHelper;
|
class CdbDumperHelper;
|
||||||
|
class CdbDumperInitThread;
|
||||||
class CdbExceptionLoggerEventCallback;
|
class CdbExceptionLoggerEventCallback;
|
||||||
class GdbEngine;
|
class GdbEngine;
|
||||||
class CdbDebugEngine;
|
class CdbDebugEngine;
|
||||||
@@ -153,6 +154,7 @@ public:
|
|||||||
friend class Internal::DebuggerPlugin;
|
friend class Internal::DebuggerPlugin;
|
||||||
friend class Internal::CdbDebugEventCallback;
|
friend class Internal::CdbDebugEventCallback;
|
||||||
friend class Internal::CdbDumperHelper;
|
friend class Internal::CdbDumperHelper;
|
||||||
|
friend class Internal::CdbDumperInitThread;
|
||||||
friend class Internal::CdbExceptionLoggerEventCallback;
|
friend class Internal::CdbExceptionLoggerEventCallback;
|
||||||
friend class Internal::GdbEngine;
|
friend class Internal::GdbEngine;
|
||||||
friend class Internal::ScriptEngine;
|
friend class Internal::ScriptEngine;
|
||||||
|
|||||||
Reference in New Issue
Block a user