forked from qt-creator/qt-creator
debugger: work on a "synchroneous" mode
For the case that gdb can give all the interesting data in one go.
This commit is contained in:
@@ -89,7 +89,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
// FIXME: temporary hack to evalute tbreak based step-over behaviour
|
// FIXME: temporary hack to evalaute tbreak based step-over behaviour
|
||||||
static QString lastFile;
|
static QString lastFile;
|
||||||
static int lastLine;
|
static int lastLine;
|
||||||
|
|
||||||
@@ -2648,8 +2648,6 @@ static void setWatchDataSAddress(WatchData &data, const GdbMi &mi)
|
|||||||
void GdbEngine::setUseDebuggingHelpers(const QVariant &on)
|
void GdbEngine::setUseDebuggingHelpers(const QVariant &on)
|
||||||
{
|
{
|
||||||
//qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on;
|
//qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on;
|
||||||
// FIXME: a bit too harsh, but otherwise the treeview sometimes look funny
|
|
||||||
//m_expandedINames.clear();
|
|
||||||
Q_UNUSED(on)
|
Q_UNUSED(on)
|
||||||
setTokenBarrier();
|
setTokenBarrier();
|
||||||
updateLocals();
|
updateLocals();
|
||||||
@@ -2916,6 +2914,7 @@ void GdbEngine::updateSubItem(const WatchData &data0)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#if !X
|
||||||
if (data.isHasChildrenNeeded() && data.variable.isEmpty()) {
|
if (data.isHasChildrenNeeded() && data.variable.isEmpty()) {
|
||||||
#if DEBUG_SUBITEM
|
#if DEBUG_SUBITEM
|
||||||
qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDCOUNT";
|
qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDCOUNT";
|
||||||
@@ -2925,6 +2924,7 @@ void GdbEngine::updateSubItem(const WatchData &data0)
|
|||||||
// item, with childrenNeeded() set.
|
// item, with childrenNeeded() set.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//#endif
|
||||||
|
|
||||||
if (data.isHasChildrenNeeded()) {
|
if (data.isHasChildrenNeeded()) {
|
||||||
QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
|
QTC_ASSERT(!data.variable.isEmpty(), return); // tested above
|
||||||
@@ -2939,6 +2939,21 @@ void GdbEngine::updateSubItem(const WatchData &data0)
|
|||||||
|
|
||||||
void GdbEngine::updateWatchData(const WatchData &data)
|
void GdbEngine::updateWatchData(const WatchData &data)
|
||||||
{
|
{
|
||||||
|
if (isSynchroneous()) {
|
||||||
|
// This should only be called for fresh expanded items, not for
|
||||||
|
// items that had their children retrieved earlier.
|
||||||
|
qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n";
|
||||||
|
#if 0
|
||||||
|
WatchData data1 = data;
|
||||||
|
data1.setAllUnneeded();
|
||||||
|
insertData(data1);
|
||||||
|
rebuildModel();
|
||||||
|
#else
|
||||||
|
if (data.iname.endsWith(_(".")))
|
||||||
|
return;
|
||||||
|
updateLocals();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
// Bump requests to avoid model rebuilding during the nested
|
// Bump requests to avoid model rebuilding during the nested
|
||||||
// updateWatchModel runs.
|
// updateWatchModel runs.
|
||||||
++m_pendingRequests;
|
++m_pendingRequests;
|
||||||
@@ -2949,6 +2964,7 @@ void GdbEngine::updateWatchData(const WatchData &data)
|
|||||||
#else
|
#else
|
||||||
updateWatchDataHelper(data);
|
updateWatchDataHelper(data);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::updateWatchDataHelper(const WatchData &data)
|
void GdbEngine::updateWatchDataHelper(const WatchData &data)
|
||||||
@@ -3341,12 +3357,6 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResponse &response)
|
|||||||
|
|
||||||
void GdbEngine::updateLocals()
|
void GdbEngine::updateLocals()
|
||||||
{
|
{
|
||||||
// Asynchronous load of injected library, initialize in first stop
|
|
||||||
if (m_dumperInjectionLoad && m_debuggingHelperState == DebuggingHelperLoadTried
|
|
||||||
&& m_dumperHelper.typeCount() == 0
|
|
||||||
&& inferiorPid() > 0)
|
|
||||||
tryQueryDebuggingHelpers();
|
|
||||||
|
|
||||||
m_pendingRequests = 0;
|
m_pendingRequests = 0;
|
||||||
m_processedNames.clear();
|
m_processedNames.clear();
|
||||||
|
|
||||||
@@ -3355,6 +3365,19 @@ void GdbEngine::updateLocals()
|
|||||||
m_toolTipExpression.clear();
|
m_toolTipExpression.clear();
|
||||||
manager()->watchHandler()->beginCycle();
|
manager()->watchHandler()->beginCycle();
|
||||||
|
|
||||||
|
// Asynchronous load of injected library, initialize in first stop
|
||||||
|
if (m_dumperInjectionLoad && m_debuggingHelperState == DebuggingHelperLoadTried
|
||||||
|
&& m_dumperHelper.typeCount() == 0
|
||||||
|
&& inferiorPid() > 0)
|
||||||
|
tryQueryDebuggingHelpers();
|
||||||
|
|
||||||
|
if (isSynchroneous()) {
|
||||||
|
QStringList expanded = m_manager->watchHandler()->expandedINames().toList();
|
||||||
|
qDebug() << "EXPANDED: " << expanded;
|
||||||
|
postCommand(_("bb %1").arg(expanded.join(_(","))),
|
||||||
|
WatchUpdate, CB(handleStackFrame1));
|
||||||
|
postCommand(_("p 0"), WatchUpdate, CB(handleStackFrame2));
|
||||||
|
} else {
|
||||||
QString level = QString::number(currentFrame());
|
QString level = QString::number(currentFrame());
|
||||||
// '2' is 'list with type and value'
|
// '2' is 'list with type and value'
|
||||||
QString cmd = _("-stack-list-arguments 2 ") + level + _c(' ') + level;
|
QString cmd = _("-stack-list-arguments 2 ") + level + _c(' ') + level;
|
||||||
@@ -3362,6 +3385,50 @@ void GdbEngine::updateLocals()
|
|||||||
// '2' is 'list with type and value'
|
// '2' is 'list with type and value'
|
||||||
postCommand(_("-stack-list-locals 2"), WatchUpdate,
|
postCommand(_("-stack-list-locals 2"), WatchUpdate,
|
||||||
CB(handleStackListLocals)); // stage 2/2
|
CB(handleStackListLocals)); // stage 2/2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleStackFrame1(const GdbResponse &response)
|
||||||
|
{
|
||||||
|
if (response.resultClass == GdbResultDone) {
|
||||||
|
QByteArray out = response.data.findChild("consolestreamoutput").data();
|
||||||
|
while (out.endsWith(' ') || out.endsWith('\n'))
|
||||||
|
out.chop(1);
|
||||||
|
//qDebug() << "FIRST CHUNK: " << out;
|
||||||
|
m_firstChunk = out;
|
||||||
|
} else if (response.resultClass == GdbResultError) {
|
||||||
|
QTC_ASSERT(false, /**/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleStackFrame2(const GdbResponse &response)
|
||||||
|
{
|
||||||
|
if (response.resultClass == GdbResultDone) {
|
||||||
|
QByteArray out = response.data.findChild("consolestreamoutput").data();
|
||||||
|
while (out.endsWith(' ') || out.endsWith('\n'))
|
||||||
|
out.chop(1);
|
||||||
|
//qDebug() << "SECOND CHUNK: " << out;
|
||||||
|
out = m_firstChunk + out;
|
||||||
|
// FIXME: Hack, make sure dumper does not return "{}"
|
||||||
|
out.replace(",{}", "");
|
||||||
|
GdbMi all("[" + out + "]");
|
||||||
|
qDebug() << "ALL: " << all.toString();
|
||||||
|
QList<GdbMi> locals = all.children();
|
||||||
|
//manager()->watchHandler()->insertBulkData(locals);
|
||||||
|
//setLocals(locals);
|
||||||
|
WatchData *data = manager()->watchHandler()->findItem(_("local"));
|
||||||
|
QTC_ASSERT(data, return);
|
||||||
|
|
||||||
|
QList<WatchData> list;
|
||||||
|
foreach (const GdbMi &local, locals)
|
||||||
|
handleChildren(*data, local, &list);
|
||||||
|
|
||||||
|
manager()->watchHandler()->insertBulkData(list);
|
||||||
|
|
||||||
|
manager()->watchHandler()->updateWatchers();
|
||||||
|
} else if (response.resultClass == GdbResultError) {
|
||||||
|
QTC_ASSERT(false, /**/);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::handleStackListArguments(const GdbResponse &response)
|
void GdbEngine::handleStackListArguments(const GdbResponse &response)
|
||||||
@@ -3456,6 +3523,13 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
|
|||||||
data.exp = nam;
|
data.exp = nam;
|
||||||
data.framekey = m_currentFrame + data.name;
|
data.framekey = m_currentFrame + data.name;
|
||||||
setWatchDataType(data, item.findChild("type"));
|
setWatchDataType(data, item.findChild("type"));
|
||||||
|
if (isSynchroneous()) {
|
||||||
|
setWatchDataValue(data, item.findChild("value"),
|
||||||
|
item.findChild("valueencoded").data().toInt());
|
||||||
|
// We know that the complete list of children is
|
||||||
|
// somewhere in the response.
|
||||||
|
data.setChildrenUnneeded();
|
||||||
|
} else {
|
||||||
// set value only directly if it is simple enough, otherwise
|
// set value only directly if it is simple enough, otherwise
|
||||||
// pass through the insertData() machinery
|
// pass through the insertData() machinery
|
||||||
if (isIntOrFloatType(data.type) || isPointerType(data.type))
|
if (isIntOrFloatType(data.type) || isPointerType(data.type))
|
||||||
@@ -3464,6 +3538,8 @@ void GdbEngine::setLocals(const QList<GdbMi> &locals)
|
|||||||
setWatchDataValue(data, item.findChild("value"));
|
setWatchDataValue(data, item.findChild("value"));
|
||||||
data.setHasChildren(false);
|
data.setHasChildren(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Let's be a bit more bold:
|
// Let's be a bit more bold:
|
||||||
//if (!hasDebuggingHelperForType(data.type)) {
|
//if (!hasDebuggingHelperForType(data.type)) {
|
||||||
// QByteArray value = item.findChild("value").data();
|
// QByteArray value = item.findChild("value").data();
|
||||||
@@ -3515,7 +3591,8 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
|
|||||||
//qDebug() << "DATA" << data.toString();
|
//qDebug() << "DATA" << data.toString();
|
||||||
QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
|
QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
|
||||||
//iname += '.' + exp;
|
//iname += '.' + exp;
|
||||||
postCommand(cmd, WatchUpdate, CB(handleVarListChildren), QVariant::fromValue(data));
|
postCommand(cmd, WatchUpdate,
|
||||||
|
CB(handleVarListChildren), QVariant::fromValue(data));
|
||||||
} else if (item.findChild("numchild").data() == "0") {
|
} else if (item.findChild("numchild").data() == "0") {
|
||||||
// happens for structs without data, e.g. interfaces.
|
// happens for structs without data, e.g. interfaces.
|
||||||
WatchData data;
|
WatchData data;
|
||||||
@@ -3533,7 +3610,8 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item,
|
|||||||
WatchData data;
|
WatchData data;
|
||||||
data.iname = _(name);
|
data.iname = _(name);
|
||||||
QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
|
QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"');
|
||||||
postCommand(cmd, WatchUpdate, CB(handleVarListChildren), QVariant::fromValue(data));
|
postCommand(cmd, WatchUpdate,
|
||||||
|
CB(handleVarListChildren), QVariant::fromValue(data));
|
||||||
} else if (exp == "staticMetaObject") {
|
} else if (exp == "staticMetaObject") {
|
||||||
// && item.findChild("type").data() == "const QMetaObject")
|
// && item.findChild("type").data() == "const QMetaObject")
|
||||||
// FIXME: Namespaces?
|
// FIXME: Namespaces?
|
||||||
@@ -3655,6 +3733,9 @@ void GdbEngine::assignValueInDebugger(const QString &expression, const QString &
|
|||||||
|
|
||||||
void GdbEngine::tryLoadDebuggingHelpers()
|
void GdbEngine::tryLoadDebuggingHelpers()
|
||||||
{
|
{
|
||||||
|
if (isSynchroneous())
|
||||||
|
return;
|
||||||
|
|
||||||
if (m_debuggingHelperState != DebuggingHelperUninitialized)
|
if (m_debuggingHelperState != DebuggingHelperUninitialized)
|
||||||
return;
|
return;
|
||||||
if (!startModeAllowsDumpers()) {
|
if (!startModeAllowsDumpers()) {
|
||||||
@@ -3735,9 +3816,13 @@ void GdbEngine::tryLoadDebuggingHelpers()
|
|||||||
|
|
||||||
void GdbEngine::tryQueryDebuggingHelpers()
|
void GdbEngine::tryQueryDebuggingHelpers()
|
||||||
{
|
{
|
||||||
|
#if !X
|
||||||
// retrieve list of dumpable classes
|
// retrieve list of dumpable classes
|
||||||
postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken);
|
postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken);
|
||||||
postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper));
|
postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper));
|
||||||
|
#else
|
||||||
|
m_debuggingHelperState = DebuggingHelperUnavailable;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::recheckDebuggingHelperAvailability()
|
void GdbEngine::recheckDebuggingHelperAvailability()
|
||||||
@@ -4186,6 +4271,10 @@ void GdbEngine::showMessageBox(int icon, const QString &title, const QString &te
|
|||||||
m_manager->showMessageBox(icon, title, text);
|
m_manager->showMessageBox(icon, title, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GdbEngine::isSynchroneous() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Factory
|
// Factory
|
||||||
|
@@ -146,9 +146,10 @@ private:
|
|||||||
Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
|
Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
|
||||||
Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
|
Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
|
||||||
Q_SLOT void setAutoDerefPointers(const QVariant &on);
|
Q_SLOT void setAutoDerefPointers(const QVariant &on);
|
||||||
virtual bool isGdbEngine() const { return true; }
|
bool isGdbEngine() const { return true; }
|
||||||
|
bool isSynchroneous() const;
|
||||||
|
|
||||||
virtual bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const;
|
bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Own stuff
|
// Own stuff
|
||||||
@@ -347,6 +348,9 @@ private:
|
|||||||
void handleStackListFrames(const GdbResponse &response);
|
void handleStackListFrames(const GdbResponse &response);
|
||||||
void handleStackSelectThread(const GdbResponse &response);
|
void handleStackSelectThread(const GdbResponse &response);
|
||||||
void handleStackListThreads(const GdbResponse &response);
|
void handleStackListThreads(const GdbResponse &response);
|
||||||
|
void handleStackFrame1(const GdbResponse &response);
|
||||||
|
void handleStackFrame2(const GdbResponse &response);
|
||||||
|
QByteArray m_firstChunk;
|
||||||
Q_SLOT void reloadStack(bool forceGotoLocation);
|
Q_SLOT void reloadStack(bool forceGotoLocation);
|
||||||
Q_SLOT void reloadFullStack();
|
Q_SLOT void reloadFullStack();
|
||||||
|
|
||||||
|
@@ -119,6 +119,7 @@ public:
|
|||||||
virtual bool isGdbEngine() const { return false; }
|
virtual bool isGdbEngine() const { return false; }
|
||||||
virtual bool checkConfiguration(int /* toolChain */, QString * /* errorMessage */, QString * /* settingsPage */ = 0) const { return true; }
|
virtual bool checkConfiguration(int /* toolChain */, QString * /* errorMessage */, QString * /* settingsPage */ = 0) const { return true; }
|
||||||
|
|
||||||
|
virtual bool isSynchroneous() const { return false; }
|
||||||
protected:
|
protected:
|
||||||
void showStatusMessage(const QString &msg, int timeout = -1);
|
void showStatusMessage(const QString &msg, int timeout = -1);
|
||||||
DebuggerState state() const;
|
DebuggerState state() const;
|
||||||
|
Reference in New Issue
Block a user