forked from qt-creator/qt-creator
CDB: Use GdbMi parser for everything.
..preparing recursive dumpers. Add recursive parser to watchutils.cpp Use insertBulkData() within CDB, add sizeof() information for some Qt containers in order to be able to dump QList<QList<KnownType> > .
This commit is contained in:
@@ -37,6 +37,7 @@
|
|||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
#include <QtCore/QLinkedList>
|
#include <QtCore/QLinkedList>
|
||||||
#include <QtCore/QList>
|
#include <QtCore/QList>
|
||||||
|
#include <QtCore/QQueue>
|
||||||
#include <QtCore/QLocale>
|
#include <QtCore/QLocale>
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
#include <QtCore/QMetaEnum>
|
#include <QtCore/QMetaEnum>
|
||||||
@@ -3622,6 +3623,10 @@ static inline void dumpSizes(QDumper &d)
|
|||||||
sizeMap.insert(sizeof(QStringList), NS"QStringList");
|
sizeMap.insert(sizeof(QStringList), NS"QStringList");
|
||||||
#ifndef QT_BOOTSTRAPPED
|
#ifndef QT_BOOTSTRAPPED
|
||||||
sizeMap.insert(sizeof(QObject), NS"QObject");
|
sizeMap.insert(sizeof(QObject), NS"QObject");
|
||||||
|
sizeMap.insert(sizeof(QList<int>), NS"QList<int>");
|
||||||
|
sizeMap.insert(sizeof(QLinkedList<int>), NS"QLinkedList<int>");
|
||||||
|
sizeMap.insert(sizeof(QVector<int>), NS"QVector<int>");
|
||||||
|
sizeMap.insert(sizeof(QQueue<int>), NS"QQueue<int>");
|
||||||
#endif
|
#endif
|
||||||
#if USE_QT_GUI
|
#if USE_QT_GUI
|
||||||
sizeMap.insert(sizeof(QWidget), NS"QWidget");
|
sizeMap.insert(sizeof(QWidget), NS"QWidget");
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#include <QtCore/QStringList>
|
#include <QtCore/QStringList>
|
||||||
|
#include <QtCore/QLinkedList>
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
@@ -138,6 +139,16 @@ static int dumpQIntList()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dumpQIntLinkedList()
|
||||||
|
{
|
||||||
|
QLinkedList<int> test = QLinkedList<int>() << 1 << 2;
|
||||||
|
prepareInBuffer("QLinkedList", "local.qintlinkedlist", "local.qlinkedintlist", "int");
|
||||||
|
qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(int), 0, 0, 0);
|
||||||
|
fputs(qDumpOutBuffer, stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dumpQIntVector()
|
static int dumpQIntVector()
|
||||||
{
|
{
|
||||||
QVector<int> test = QVector<int>() << 42 << 43;
|
QVector<int> test = QVector<int>() << 42 << 43;
|
||||||
@@ -176,6 +187,20 @@ static int dumpQMapIntString()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dumpQMapQStringString()
|
||||||
|
{
|
||||||
|
QMap<QString,QString> test;
|
||||||
|
QMapNode<QString,QString> mapNode;
|
||||||
|
const int valueOffset = (char*)&(mapNode.value) - (char*)&mapNode;
|
||||||
|
test.insert(QLatin1String("42s"), QLatin1String("fortytwo"));
|
||||||
|
test.insert(QLatin1String("423"), QLatin1String("fortytree"));
|
||||||
|
prepareInBuffer("QMap", "local.qmapqstringqstring", "local.qmapqstringqstring", "QString@QString");
|
||||||
|
qDumpObjectData440(2, 42, testAddress(&test), 1, sizeof(QString), sizeof(QString), sizeof(mapNode), valueOffset);
|
||||||
|
fputs(qDumpOutBuffer, stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dumpQVariant()
|
static int dumpQVariant()
|
||||||
{
|
{
|
||||||
QVariant test(QLatin1String("item"));
|
QVariant test(QLatin1String("item"));
|
||||||
@@ -417,9 +442,11 @@ static TypeDumpFunctionMap registerTypes()
|
|||||||
rc.insert("QSharedPointer<QString>", dumpQSharedPointerQString);
|
rc.insert("QSharedPointer<QString>", dumpQSharedPointerQString);
|
||||||
rc.insert("QStringList", dumpQStringList);
|
rc.insert("QStringList", dumpQStringList);
|
||||||
rc.insert("QList<int>", dumpQIntList);
|
rc.insert("QList<int>", dumpQIntList);
|
||||||
|
rc.insert("QLinkedList<int>", dumpQIntLinkedList);
|
||||||
rc.insert("QList<std::string>", dumpStdStringQList);
|
rc.insert("QList<std::string>", dumpStdStringQList);
|
||||||
rc.insert("QVector<int>", dumpQIntVector);
|
rc.insert("QVector<int>", dumpQIntVector);
|
||||||
rc.insert("QMap<int,QString>", dumpQMapIntString);
|
rc.insert("QMap<int,QString>", dumpQMapIntString);
|
||||||
|
rc.insert("QMap<QString,QString>", dumpQMapQStringString);
|
||||||
rc.insert("QMap<int,int>", dumpQMapIntInt);
|
rc.insert("QMap<int,int>", dumpQMapIntInt);
|
||||||
rc.insert("string", dumpStdString);
|
rc.insert("string", dumpStdString);
|
||||||
rc.insert("wstring", dumpStdWString);
|
rc.insert("wstring", dumpStdWString);
|
||||||
|
@@ -554,7 +554,7 @@ static inline QString msgNotHandled(const QString &type)
|
|||||||
return QString::fromLatin1("The type '%1' is not handled.").arg(type);
|
return QString::fromLatin1("The type '%1' is not handled.").arg(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, int source,
|
CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren,
|
||||||
QList<WatchData> *result, QString *errorMessage)
|
QList<WatchData> *result, QString *errorMessage)
|
||||||
{
|
{
|
||||||
// Check failure cache and supported types
|
// Check failure cache and supported types
|
||||||
@@ -593,7 +593,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
|
|||||||
arg(wd.name, wd.exp, wd.type);
|
arg(wd.name, wd.exp, wd.type);
|
||||||
m_access->showDebuggerOutput(LogMisc, message);
|
m_access->showDebuggerOutput(LogMisc, message);
|
||||||
|
|
||||||
const DumpExecuteResult der = executeDump(wd, td, dumpChildren, source, result, errorMessage);
|
const DumpExecuteResult der = executeDump(wd, td, dumpChildren, result, errorMessage);
|
||||||
if (der == DumpExecuteOk)
|
if (der == DumpExecuteOk)
|
||||||
return DumpOk;
|
return DumpOk;
|
||||||
// Cache types that fail due to complicated template size expressions.
|
// Cache types that fail due to complicated template size expressions.
|
||||||
@@ -610,7 +610,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
|
|||||||
|
|
||||||
CdbDumperHelper::DumpExecuteResult
|
CdbDumperHelper::DumpExecuteResult
|
||||||
CdbDumperHelper::executeDump(const WatchData &wd,
|
CdbDumperHelper::executeDump(const WatchData &wd,
|
||||||
const QtDumperHelper::TypeData& td, bool dumpChildren, int source,
|
const QtDumperHelper::TypeData& td, bool dumpChildren,
|
||||||
QList<WatchData> *result, QString *errorMessage)
|
QList<WatchData> *result, QString *errorMessage)
|
||||||
{
|
{
|
||||||
QByteArray inBuffer;
|
QByteArray inBuffer;
|
||||||
@@ -658,12 +658,10 @@ CdbDumperHelper::DumpExecuteResult
|
|||||||
}
|
}
|
||||||
if (!callDumper(callCmd, inBuffer, &outputData, true, errorMessage))
|
if (!callDumper(callCmd, inBuffer, &outputData, true, errorMessage))
|
||||||
return DumpExecuteCallFailed;
|
return DumpExecuteCallFailed;
|
||||||
QtDumperResult dumpResult;
|
if (!QtDumperHelper::parseValue(outputData, result)) {
|
||||||
if (!QtDumperHelper::parseValue(outputData, &dumpResult)) {
|
|
||||||
*errorMessage = QLatin1String("Parsing of value query output failed.");
|
*errorMessage = QLatin1String("Parsing of value query output failed.");
|
||||||
return DumpExecuteCallFailed;
|
return DumpExecuteCallFailed;
|
||||||
}
|
}
|
||||||
*result = dumpResult.toWatchData(source);
|
|
||||||
return DumpExecuteOk;
|
return DumpExecuteOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -89,7 +89,7 @@ public:
|
|||||||
|
|
||||||
// Dump a WatchData item.
|
// Dump a WatchData item.
|
||||||
enum DumpResult { DumpNotHandled, DumpOk, DumpError };
|
enum DumpResult { DumpNotHandled, DumpOk, DumpError };
|
||||||
DumpResult dumpType(const WatchData &d, bool dumpChildren, int source,
|
DumpResult dumpType(const WatchData &d, bool dumpChildren,
|
||||||
QList<WatchData> *result, QString *errorMessage);
|
QList<WatchData> *result, QString *errorMessage);
|
||||||
|
|
||||||
inline CdbComInterfaces *comInterfaces() const { return m_cif; }
|
inline CdbComInterfaces *comInterfaces() const { return m_cif; }
|
||||||
@@ -113,7 +113,7 @@ private:
|
|||||||
DumpComplexExpressionEncountered,
|
DumpComplexExpressionEncountered,
|
||||||
DumpExecuteCallFailed };
|
DumpExecuteCallFailed };
|
||||||
DumpExecuteResult executeDump(const WatchData &wd,
|
DumpExecuteResult executeDump(const WatchData &wd,
|
||||||
const QtDumperHelper::TypeData& td, bool dumpChildren, int source,
|
const QtDumperHelper::TypeData& td, bool dumpChildren,
|
||||||
QList<WatchData> *result, QString *errorMessage);
|
QList<WatchData> *result, QString *errorMessage);
|
||||||
|
|
||||||
static bool writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage);
|
static bool writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage);
|
||||||
|
@@ -156,7 +156,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt
|
|||||||
derefedWd.name = QString(QLatin1Char('*'));
|
derefedWd.name = QString(QLatin1Char('*'));
|
||||||
derefedWd.iname = wd.iname + QLatin1String(".*");
|
derefedWd.iname = wd.iname + QLatin1String(".*");
|
||||||
derefedWd.source = OwnerDumper | CdbStackFrameContext::ChildrenKnownBit;
|
derefedWd.source = OwnerDumper | CdbStackFrameContext::ChildrenKnownBit;
|
||||||
const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, OwnerDumper, &m_dumperResult, errorMessage);
|
const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, &m_dumperResult, errorMessage);
|
||||||
if (dr != CdbDumperHelper::DumpOk)
|
if (dr != CdbDumperHelper::DumpOk)
|
||||||
break;
|
break;
|
||||||
// Insert the pointer item with 1 additional child + its dumper results
|
// Insert the pointer item with 1 additional child + its dumper results
|
||||||
@@ -166,8 +166,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt
|
|||||||
ptrWd.setHasChildren(true);
|
ptrWd.setHasChildren(true);
|
||||||
ptrWd.setChildrenUnneeded();
|
ptrWd.setChildrenUnneeded();
|
||||||
m_wh->insertData(ptrWd);
|
m_wh->insertData(ptrWd);
|
||||||
foreach(const WatchData &dwd, m_dumperResult)
|
m_wh->insertBulkData(m_dumperResult);
|
||||||
m_wh->insertData(dwd);
|
|
||||||
handled = true;
|
handled = true;
|
||||||
} while (false);
|
} while (false);
|
||||||
if (debugCDBWatchHandling)
|
if (debugCDBWatchHandling)
|
||||||
@@ -184,7 +183,8 @@ static inline void fixDumperResult(const WatchData &source,
|
|||||||
const int size = result->size();
|
const int size = result->size();
|
||||||
if (!size)
|
if (!size)
|
||||||
return;
|
return;
|
||||||
// debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult");
|
if (debugCDBWatchHandling)
|
||||||
|
debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult");
|
||||||
WatchData &returned = result->front();
|
WatchData &returned = result->front();
|
||||||
if (returned.iname != source.iname)
|
if (returned.iname != source.iname)
|
||||||
return;
|
return;
|
||||||
@@ -198,6 +198,10 @@ static inline void fixDumperResult(const WatchData &source,
|
|||||||
returned.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
|
returned.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Indicate owner and known children
|
||||||
|
returned.source = OwnerDumper;
|
||||||
|
if (returned.isChildrenKnown() && returned.isHasChildrenKnown() && returned.hasChildren)
|
||||||
|
returned.source |= CdbStackFrameContext::ChildrenKnownBit;
|
||||||
if (size == 1)
|
if (size == 1)
|
||||||
return;
|
return;
|
||||||
// If the model queries the expanding item by pretending childrenNeeded=1,
|
// If the model queries the expanding item by pretending childrenNeeded=1,
|
||||||
@@ -208,6 +212,10 @@ static inline void fixDumperResult(const WatchData &source,
|
|||||||
QList<WatchData>::iterator it = result->begin();
|
QList<WatchData>::iterator it = result->begin();
|
||||||
for (++it; it != wend; ++it) {
|
for (++it; it != wend; ++it) {
|
||||||
WatchData &wd = *it;
|
WatchData &wd = *it;
|
||||||
|
// Indicate owner and known children
|
||||||
|
it->source = OwnerDumper;
|
||||||
|
if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren)
|
||||||
|
it->source |= CdbStackFrameContext::ChildrenKnownBit;
|
||||||
if (wd.addr.isEmpty() && wd.isSomethingNeeded()) {
|
if (wd.addr.isEmpty() && wd.isSomethingNeeded()) {
|
||||||
wd.setHasChildren(false);
|
wd.setHasChildren(false);
|
||||||
wd.setAllUnneeded();
|
wd.setAllUnneeded();
|
||||||
@@ -218,7 +226,8 @@ static inline void fixDumperResult(const WatchData &source,
|
|||||||
wd.setHasChildren(false);
|
wd.setHasChildren(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// debugWatchDataList(*result, "<fixDumperResult");
|
if (debugCDBWatchHandling)
|
||||||
|
debugWatchDataList(*result, "<fixDumperResult");
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
|
WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
|
||||||
@@ -238,15 +247,14 @@ WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
// Try library dumpers.
|
// Try library dumpers.
|
||||||
switch (m_dumper->dumpType(wd, true, OwnerDumper, &m_dumperResult, &errorMessage)) {
|
switch (m_dumper->dumpType(wd, true, &m_dumperResult, &errorMessage)) {
|
||||||
case CdbDumperHelper::DumpOk:
|
case CdbDumperHelper::DumpOk:
|
||||||
if (debugCDBWatchHandling)
|
if (debugCDBWatchHandling)
|
||||||
qDebug() << "dumper triggered";
|
qDebug() << "dumper triggered";
|
||||||
// Dumpers omit types for complicated templates
|
// Dumpers omit types for complicated templates
|
||||||
fixDumperResult(wd, &m_dumperResult, false);
|
fixDumperResult(wd, &m_dumperResult, false);
|
||||||
// Discard the original item and insert the dumper results
|
// Discard the original item and insert the dumper results
|
||||||
foreach(const WatchData &dwd, m_dumperResult)
|
m_wh->insertBulkData(m_dumperResult);
|
||||||
m_wh->insertData(dwd);
|
|
||||||
// Nasty side effect: Modify owner for the ignore predicate
|
// Nasty side effect: Modify owner for the ignore predicate
|
||||||
wd.source = OwnerDumper;
|
wd.source = OwnerDumper;
|
||||||
break;
|
break;
|
||||||
@@ -325,13 +333,12 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
QList<WatchData> dumperResult;
|
QList<WatchData> dumperResult;
|
||||||
const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, OwnerDumper, &dumperResult, errorMessage);
|
const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, &dumperResult, errorMessage);
|
||||||
if (dr == CdbDumperHelper::DumpOk) {
|
if (dr == CdbDumperHelper::DumpOk) {
|
||||||
// Hack to stop endless model recursion
|
// Hack to stop endless model recursion
|
||||||
const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname);
|
const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname);
|
||||||
fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren);
|
fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren);
|
||||||
foreach(const WatchData &dwd, dumperResult)
|
wh->insertBulkData(dumperResult);
|
||||||
wh->insertData(dwd);
|
|
||||||
} else {
|
} else {
|
||||||
const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage);
|
const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage);
|
||||||
qWarning("%s", qPrintable(msg));
|
qWarning("%s", qPrintable(msg));
|
||||||
@@ -372,7 +379,7 @@ bool CdbStackFrameContext::editorToolTip(const QString &iname,
|
|||||||
// Check dumpers. Should actually be just one item.
|
// Check dumpers. Should actually be just one item.
|
||||||
if (m_useDumpers && m_dumper->state() != CdbDumperHelper::Disabled) {
|
if (m_useDumpers && m_dumper->state() != CdbDumperHelper::Disabled) {
|
||||||
QList<WatchData> result;
|
QList<WatchData> result;
|
||||||
if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, OwnerDumper, &result, errorMessage)) {
|
if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, &result, errorMessage)) {
|
||||||
foreach (const WatchData &dwd, result) {
|
foreach (const WatchData &dwd, result) {
|
||||||
if (!value->isEmpty())
|
if (!value->isEmpty())
|
||||||
value->append(QLatin1Char('\n'));
|
value->append(QLatin1Char('\n'));
|
||||||
|
@@ -227,6 +227,8 @@ QString WatchData::toString() const
|
|||||||
str << QLatin1Char('{');
|
str << QLatin1Char('{');
|
||||||
if (!iname.isEmpty())
|
if (!iname.isEmpty())
|
||||||
str << "iname=\"" << iname << doubleQuoteComma;
|
str << "iname=\"" << iname << doubleQuoteComma;
|
||||||
|
if (!name.isEmpty() && name != iname)
|
||||||
|
str << "name=\"" << name << doubleQuoteComma;
|
||||||
if (!addr.isEmpty())
|
if (!addr.isEmpty())
|
||||||
str << "addr=\"" << addr << doubleQuoteComma;
|
str << "addr=\"" << addr << doubleQuoteComma;
|
||||||
if (!exp.isEmpty())
|
if (!exp.isEmpty())
|
||||||
|
@@ -492,172 +492,6 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos,
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------- QtDumperResult
|
|
||||||
|
|
||||||
QtDumperResult::Child::Child() :
|
|
||||||
keyEncoded(0),
|
|
||||||
valueEncoded(0),
|
|
||||||
childCount(-1),
|
|
||||||
valueEnabled(true),
|
|
||||||
valueEncountered(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QtDumperResult::QtDumperResult() :
|
|
||||||
valueEncountered(false),
|
|
||||||
valueEncoded(0),
|
|
||||||
valueEnabled(true),
|
|
||||||
childCount(-1),
|
|
||||||
internal(false),
|
|
||||||
childChildCount(-1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void QtDumperResult::clear()
|
|
||||||
{
|
|
||||||
iname.clear();
|
|
||||||
value.clear();
|
|
||||||
address.clear();
|
|
||||||
addressInfo.clear();
|
|
||||||
type.clear();
|
|
||||||
extra.clear();
|
|
||||||
displayedType.clear();
|
|
||||||
valueEncoded = 0;
|
|
||||||
valueEncountered = false;
|
|
||||||
valueEnabled = false;
|
|
||||||
childCount = -1;
|
|
||||||
internal = false;
|
|
||||||
childType.clear();
|
|
||||||
children.clear();
|
|
||||||
childChildCount = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<WatchData> QtDumperResult::toWatchData(int source) const
|
|
||||||
{
|
|
||||||
QList<WatchData> rc;
|
|
||||||
rc.push_back(WatchData());
|
|
||||||
WatchData &root = rc.front();
|
|
||||||
root.iname = iname;
|
|
||||||
const QChar dot = QLatin1Char('.');
|
|
||||||
const int lastDotIndex = root.iname.lastIndexOf(dot);
|
|
||||||
root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1);
|
|
||||||
if (valueEncountered) {
|
|
||||||
root.setValue(decodeData(value, valueEncoded));
|
|
||||||
root.valueEnabled = valueEnabled;
|
|
||||||
}
|
|
||||||
root.setType(type);
|
|
||||||
if (!displayedType.isEmpty())
|
|
||||||
root.displayedType = displayedType;
|
|
||||||
root.setAddress(address);
|
|
||||||
root.source = source;
|
|
||||||
if (childCount >= 0)
|
|
||||||
root.setHasChildren(childCount > 0);
|
|
||||||
// Children. Sanity check after parsing sets childcount to list size
|
|
||||||
// if list is not empty
|
|
||||||
if (children.empty()) {
|
|
||||||
if (childCount > 0)
|
|
||||||
root.setChildrenNeeded();
|
|
||||||
} else {
|
|
||||||
root.setChildrenUnneeded();
|
|
||||||
for (int c = 0; c < childCount; c++) {
|
|
||||||
const Child &dchild = children.at(c);
|
|
||||||
rc.push_back(WatchData());
|
|
||||||
WatchData &wchild = rc.back();
|
|
||||||
wchild.source = source;
|
|
||||||
wchild.iname = iname;
|
|
||||||
// Name can be empty for array-like things
|
|
||||||
const QString iname = dchild.name.isEmpty() ? QString::number(c) : dchild.name;
|
|
||||||
// Use key entry as name (which is used for map nodes)
|
|
||||||
if (dchild.key.isEmpty()) {
|
|
||||||
wchild.name = iname;
|
|
||||||
} else {
|
|
||||||
// Do not use map keys as iname since they might contain quotes.
|
|
||||||
wchild.name = decodeData(dchild.key, dchild.keyEncoded);
|
|
||||||
if (wchild.name.size() > 13) {
|
|
||||||
wchild.name.truncate(12);
|
|
||||||
wchild.name += QLatin1String("...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Append iname to total iname.
|
|
||||||
wchild.iname += dot;
|
|
||||||
wchild.iname += iname;
|
|
||||||
wchild.exp = dchild.exp;
|
|
||||||
if (dchild.valueEncountered) {
|
|
||||||
wchild.valueEnabled = dchild.valueEnabled;
|
|
||||||
wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
|
|
||||||
}
|
|
||||||
wchild.setAddress(dchild.address);
|
|
||||||
// The type setter sets hasChildren for known types.
|
|
||||||
wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
|
|
||||||
if (!dchild.displayedType.isEmpty())
|
|
||||||
wchild.displayedType = dchild.displayedType;
|
|
||||||
// Child overrides.
|
|
||||||
const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount;
|
|
||||||
switch (effectiveChildChildCount) {
|
|
||||||
case -1: // In this case, trust WatchData::setType().
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
wchild.setHasChildren(false);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wchild.setHasChildren(true);
|
|
||||||
wchild.setChildrenNeeded();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug) {
|
|
||||||
QDebug nospace = qDebug().nospace();
|
|
||||||
nospace << "QtDumperResult::toWatchData" << *this << '\n';
|
|
||||||
foreach(const WatchData &wd, rc)
|
|
||||||
nospace << " " << wd.toString() << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug in, const QtDumperResult &d)
|
|
||||||
{
|
|
||||||
QDebug nospace = in.nospace();
|
|
||||||
nospace << " iname=" << d.iname << " type=" << d.type
|
|
||||||
<< " displayed=" << d.displayedType
|
|
||||||
<< " address=" << d.address;
|
|
||||||
if (!d.addressInfo.isEmpty())
|
|
||||||
nospace << " addressInfo=" << d.addressInfo;
|
|
||||||
if (d.valueEncountered) {
|
|
||||||
nospace << " encoded=" << d.valueEncoded
|
|
||||||
<< " value=" << d.value
|
|
||||||
<< " enabled=" << d.valueEnabled;
|
|
||||||
} else {
|
|
||||||
nospace << " <no value>";
|
|
||||||
}
|
|
||||||
nospace << " childnumchild=" << d.childChildCount
|
|
||||||
<< " internal=" << d.internal
|
|
||||||
<< " extra='" << d.extra << "'\n";
|
|
||||||
|
|
||||||
const int realChildCount = d.children.size();
|
|
||||||
if (d.childCount || realChildCount) {
|
|
||||||
nospace << "childCount=" << d.childCount << '/' << realChildCount
|
|
||||||
<< " childType=" << d.childType << '\n';
|
|
||||||
for (int i = 0; i < realChildCount; i++) {
|
|
||||||
const QtDumperResult::Child &c = d.children.at(i);
|
|
||||||
nospace << " #" << i << " addr=" << c.address
|
|
||||||
<< " enabled=" << c.valueEnabled
|
|
||||||
<< " type=" << c.type << " exp=" << c.exp
|
|
||||||
<< " name=" << c.name;
|
|
||||||
if (!c.key.isEmpty())
|
|
||||||
nospace << " keyencoded=" << c.keyEncoded << " key=" << c.key;
|
|
||||||
if (c.valueEncountered) {
|
|
||||||
nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value;
|
|
||||||
} else {
|
|
||||||
nospace << " <no value>";
|
|
||||||
}
|
|
||||||
nospace << "childcount=" << c.childCount << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------- QtDumperHelper::TypeData
|
// ----------------- QtDumperHelper::TypeData
|
||||||
QtDumperHelper::TypeData::TypeData() :
|
QtDumperHelper::TypeData::TypeData() :
|
||||||
type(UnknownType),
|
type(UnknownType),
|
||||||
@@ -1049,6 +883,9 @@ void QtDumperHelper::setQClassPrefixes(const QString &qNamespace)
|
|||||||
m_qSharedPointerPrefix = qClassName(qNamespace, "QSharedPointer");
|
m_qSharedPointerPrefix = qClassName(qNamespace, "QSharedPointer");
|
||||||
m_qSharedDataPointerPrefix = qClassName(qNamespace, "QSharedDataPointer");
|
m_qSharedDataPointerPrefix = qClassName(qNamespace, "QSharedDataPointer");
|
||||||
m_qWeakPointerPrefix = qClassName(qNamespace, "QWeakPointer");
|
m_qWeakPointerPrefix = qClassName(qNamespace, "QWeakPointer");
|
||||||
|
m_qListPrefix = qClassName(qNamespace, "QList");
|
||||||
|
m_qLinkedListPrefix = qClassName(qNamespace, "QLinkedList");
|
||||||
|
m_qVectorPrefix = qClassName(qNamespace, "QVector");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double getDumperVersion(const GdbMi &contents)
|
static inline double getDumperVersion(const GdbMi &contents)
|
||||||
@@ -1205,6 +1042,14 @@ QtDumperHelper::SpecialSizeType QtDumperHelper::specialSizeType(const QString &t
|
|||||||
return QSharedDataPointerSize;
|
return QSharedDataPointerSize;
|
||||||
if (typeName.startsWith(m_qWeakPointerPrefix))
|
if (typeName.startsWith(m_qWeakPointerPrefix))
|
||||||
return QWeakPointerSize;
|
return QWeakPointerSize;
|
||||||
|
if (typeName.startsWith(m_qListPrefix))
|
||||||
|
return QListSize;
|
||||||
|
if (typeName.startsWith(m_qLinkedListPrefix))
|
||||||
|
return QLinkedListSize;
|
||||||
|
if (typeName.startsWith(m_qVectorPrefix))
|
||||||
|
return QVectorSize;
|
||||||
|
if (typeName.startsWith(m_qQueuePrefix))
|
||||||
|
return QQueueSize;
|
||||||
return SpecialSizeCount;
|
return SpecialSizeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1393,233 +1238,173 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
|
|||||||
qDebug() << '\n' << Q_FUNC_INFO << '\n' << data.toString() << "\n-->" << outertype << td.type << extraArgs;
|
qDebug() << '\n' << Q_FUNC_INFO << '\n' << data.toString() << "\n-->" << outertype << td.type << extraArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse value:
|
// GdbMi parsing helpers for parsing dumper value results
|
||||||
* "iname="local.sl",addr="0x0012BA84",value="<3 items>",valuedisabled="true",
|
|
||||||
* numchild="3",childtype="QString",childnumchild="0",
|
|
||||||
* children=[{name="0",value="<binhex>",valueencoded="2"},
|
|
||||||
* {name="1",value="dAB3AG8A",valueencoded="2"},
|
|
||||||
* {name="2",value="dABoAHIAZQBlAA==",valueencoded="2"}]" */
|
|
||||||
|
|
||||||
class ValueDumperParser : public DumperParser
|
static bool gdbMiGetIntValue(int *target,
|
||||||
|
const GdbMi &node,
|
||||||
|
const char *child)
|
||||||
{
|
{
|
||||||
public:
|
*target = -1;
|
||||||
explicit ValueDumperParser(const char *s);
|
const GdbMi childNode = node.findChild(child);
|
||||||
|
if (!childNode.isValid())
|
||||||
|
return false;
|
||||||
|
bool ok;
|
||||||
|
*target = childNode.data().toInt(&ok);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
inline QtDumperResult result() const { return m_result; }
|
// Find a string child node and assign value if it exists.
|
||||||
|
// Optionally decode.
|
||||||
|
static bool gdbMiGetStringValue(QString *target,
|
||||||
|
const GdbMi &node,
|
||||||
|
const char *child,
|
||||||
|
const char *encodingChild = 0)
|
||||||
|
{
|
||||||
|
target->clear();
|
||||||
|
const GdbMi childNode = node.findChild(child);
|
||||||
|
if (!childNode.isValid())
|
||||||
|
return false;
|
||||||
|
// Encoded data
|
||||||
|
if (encodingChild) {
|
||||||
|
int encoding;
|
||||||
|
if (!gdbMiGetIntValue(&encoding, node, encodingChild))
|
||||||
|
encoding = 0;
|
||||||
|
*target = decodeData(childNode.data(), encoding);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Plain data
|
||||||
|
*target = QLatin1String(childNode.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
static bool gdbMiGetBoolValue(bool *target,
|
||||||
virtual bool handleKeyword(const char *k, int size);
|
const GdbMi &node,
|
||||||
virtual bool handleHashStart();
|
const char *child)
|
||||||
virtual bool handleValue(const char *k, int size);
|
{
|
||||||
|
*target = false;
|
||||||
|
const GdbMi childNode = node.findChild(child);
|
||||||
|
if (!childNode.isValid())
|
||||||
|
return false;
|
||||||
|
*target = childNode.data() == "true";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
/* Context to store parameters that influence the next level children.
|
||||||
enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue,
|
* (next level only, it is not further inherited). For example, the root item
|
||||||
ExpectingType, ExpectingDisplayedType, ExpectingInternal,
|
* can provide a "childtype" node that specifies the type of the children. */
|
||||||
ExpectingValueEnabled, ExpectingValueEncoded,
|
|
||||||
ExpectingCommonChildType, ExpectingChildCount,
|
|
||||||
ExpectingChildChildOverrideCount,
|
|
||||||
ExpectingExtra,
|
|
||||||
IgnoreNext,
|
|
||||||
ChildModeStart,
|
|
||||||
ExpectingChildren,ExpectingChildName, ExpectingChildAddress,
|
|
||||||
ExpectingChildExpression, ExpectingChildType,
|
|
||||||
ExpectingChildDisplayedType,
|
|
||||||
ExpectingChildKey, ExpectingChildKeyEncoded,
|
|
||||||
ExpectingChildValue, ExpectingChildValueEncoded,
|
|
||||||
ExpectingChildValueEnabled, ExpectingChildChildCount,
|
|
||||||
IgnoreNextChildMode
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline Mode nextMode(Mode in, const char *keyword, int size);
|
struct GdbMiRecursionContext {
|
||||||
|
GdbMiRecursionContext(int recursionLevelIn = 0) :
|
||||||
|
recursionLevel(recursionLevelIn), childNumChild(-1), childIndex(0) {}
|
||||||
|
|
||||||
Mode m_mode;
|
int recursionLevel;
|
||||||
QtDumperResult m_result;
|
int childNumChild;
|
||||||
|
int childIndex;
|
||||||
|
QString childType;
|
||||||
|
QString parentIName;
|
||||||
};
|
};
|
||||||
|
|
||||||
ValueDumperParser::ValueDumperParser(const char *s) :
|
static void gbdMiToWatchData(const GdbMi &root,
|
||||||
DumperParser(s),
|
const GdbMiRecursionContext &ctx,
|
||||||
m_mode(None)
|
QList<WatchData> *wl)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
// Check key words
|
|
||||||
ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword, int size)
|
|
||||||
{
|
|
||||||
// Careful with same prefix
|
|
||||||
switch (size) {
|
|
||||||
case 3:
|
|
||||||
if (!qstrncmp(keyword, "exp", size))
|
|
||||||
return ExpectingChildExpression;
|
|
||||||
if (!qstrncmp(keyword, "key", size))
|
|
||||||
return ExpectingChildKey;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (!qstrncmp(keyword, "addr", size))
|
|
||||||
return in > ChildModeStart ? ExpectingChildAddress : ExpectingAddress;
|
|
||||||
if (!qstrncmp(keyword, "type", size))
|
|
||||||
return in > ChildModeStart ? ExpectingChildType : ExpectingType;
|
|
||||||
if (!qstrncmp(keyword, "name", size))
|
|
||||||
return ExpectingChildName;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if (!qstrncmp(keyword, "iname", size))
|
|
||||||
return ExpectingIName;
|
|
||||||
if (!qstrncmp(keyword, "value", size))
|
|
||||||
return in > ChildModeStart ? ExpectingChildValue : ExpectingValue;
|
|
||||||
if (!qstrncmp(keyword, "extra", size))
|
|
||||||
return ExpectingExtra;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
if (!qstrncmp(keyword, "children", size))
|
|
||||||
return ExpectingChildren;
|
|
||||||
if (!qstrncmp(keyword, "numchild", size))
|
|
||||||
return in > ChildModeStart ? ExpectingChildChildCount : ExpectingChildCount;
|
|
||||||
if (!qstrncmp(keyword, "internal", size))
|
|
||||||
return ExpectingInternal;
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
if (!qstrncmp(keyword, "childtype", size))
|
|
||||||
return ExpectingCommonChildType;
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
if (!qstrncmp(keyword, "keyencoded", size))
|
|
||||||
return ExpectingChildKeyEncoded;
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
if (!qstrncmp(keyword, "valueencoded", size))
|
|
||||||
return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded;
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
if (!qstrncmp(keyword, "valueenabled", size))
|
|
||||||
return in > ChildModeStart ? ExpectingChildValueEnabled : ExpectingValueEnabled;
|
|
||||||
if (!qstrncmp(keyword, "displayedtype", size))
|
|
||||||
return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType;
|
|
||||||
if (!qstrncmp(keyword, "childnumchild", size))
|
|
||||||
return ExpectingChildChildOverrideCount;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValueDumperParser::handleKeyword(const char *k, int size)
|
|
||||||
{
|
|
||||||
const Mode newMode = nextMode(m_mode, k, size);
|
|
||||||
if (debug && newMode == IgnoreNext)
|
|
||||||
qWarning("%s Unexpected keyword %s.\n", Q_FUNC_INFO, QByteArray(k, size).constData());
|
|
||||||
m_mode = newMode;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValueDumperParser::handleHashStart()
|
|
||||||
{
|
|
||||||
m_result.children.push_back(QtDumperResult::Child());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ValueDumperParser::handleValue(const char *k, int size)
|
|
||||||
{
|
|
||||||
const QByteArray valueBA(k, size);
|
|
||||||
switch (m_mode) {
|
|
||||||
case None:
|
|
||||||
case ChildModeStart:
|
|
||||||
return false;
|
|
||||||
case ExpectingIName:
|
|
||||||
m_result.iname = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingAddress: {
|
|
||||||
const QString address = QString::fromLatin1(valueBA);
|
|
||||||
if (address.startsWith(QLatin1String("0x"))) {
|
|
||||||
m_result.address = address;
|
|
||||||
} else {
|
|
||||||
m_result.addressInfo = address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ExpectingValue:
|
|
||||||
m_result.valueEncountered = true;
|
|
||||||
m_result.value = valueBA;
|
|
||||||
break;
|
|
||||||
case ExpectingValueEnabled:
|
|
||||||
m_result.valueEnabled = valueBA == "true";
|
|
||||||
break;
|
|
||||||
case ExpectingValueEncoded:
|
|
||||||
m_result.valueEncoded = QString::fromLatin1(valueBA).toInt();
|
|
||||||
break;
|
|
||||||
case ExpectingType:
|
|
||||||
m_result.type = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingDisplayedType:
|
|
||||||
m_result.displayedType = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingExtra:
|
|
||||||
m_result.extra = valueBA;
|
|
||||||
break;
|
|
||||||
case ExpectingInternal:
|
|
||||||
m_result.internal = valueBA == "true";
|
|
||||||
break;
|
|
||||||
case ExpectingCommonChildType:
|
|
||||||
m_result.childType = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingChildCount:
|
|
||||||
m_result.childCount = QString::fromLatin1(valueBA).toInt();
|
|
||||||
break;
|
|
||||||
case ExpectingChildChildOverrideCount:
|
|
||||||
m_result.childChildCount = QString::fromLatin1(valueBA).toInt();
|
|
||||||
break;
|
|
||||||
case ExpectingChildren:
|
|
||||||
case IgnoreNextChildMode:
|
|
||||||
case IgnoreNext:
|
|
||||||
break;
|
|
||||||
case ExpectingChildName:
|
|
||||||
m_result.children.back().name = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingChildAddress:
|
|
||||||
m_result.children.back().address = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingChildKeyEncoded:
|
|
||||||
m_result.children.back().keyEncoded = QString::fromLatin1(valueBA).toInt();
|
|
||||||
break;
|
|
||||||
case ExpectingChildKey:
|
|
||||||
m_result.children.back().key = valueBA;
|
|
||||||
break;
|
|
||||||
case ExpectingChildValue:
|
|
||||||
m_result.children.back().valueEncountered = true;
|
|
||||||
m_result.children.back().value = valueBA;
|
|
||||||
break;
|
|
||||||
case ExpectingChildExpression:
|
|
||||||
m_result.children.back().exp = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingChildValueEncoded:
|
|
||||||
m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt();
|
|
||||||
break;
|
|
||||||
case ExpectingChildValueEnabled:
|
|
||||||
m_result.children.back().valueEnabled = valueBA == "true";
|
|
||||||
break;
|
|
||||||
case ExpectingChildType:
|
|
||||||
m_result.children.back().type = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingChildDisplayedType:
|
|
||||||
m_result.children.back().displayedType = QString::fromLatin1(valueBA);
|
|
||||||
break;
|
|
||||||
case ExpectingChildChildCount:
|
|
||||||
m_result.children.back().childCount = QString::fromLatin1(valueBA).toInt();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
|
|
||||||
{
|
|
||||||
ValueDumperParser parser(data);
|
|
||||||
|
|
||||||
if (!parser.run())
|
|
||||||
return false;
|
|
||||||
*r = parser.result();
|
|
||||||
// Sanity
|
|
||||||
if (!r->children.empty() && r->childCount != r->children.size())
|
|
||||||
r->childCount = r->children.size();
|
|
||||||
if (debug > 1)
|
if (debug > 1)
|
||||||
qDebug() << '\n' << data << '\n' << *r;
|
qDebug() << Q_FUNC_INFO << '\n' << root.toString(false, 0);
|
||||||
|
WatchData w;
|
||||||
|
QString v;
|
||||||
|
// Check for name/iname and use as expression default
|
||||||
|
if (ctx.recursionLevel == 0) {
|
||||||
|
// parents have only iname, from which name is derived
|
||||||
|
if (!gdbMiGetStringValue(&w.iname, root, "iname"))
|
||||||
|
qWarning("Internal error: iname missing");
|
||||||
|
w.name = w.iname;
|
||||||
|
const int lastDotPos = w.name.lastIndexOf(QLatin1Char('.'));
|
||||||
|
if (lastDotPos != -1)
|
||||||
|
w.name.remove(0, lastDotPos + 1);
|
||||||
|
w.exp = w.name;
|
||||||
|
} else {
|
||||||
|
// Children can have a 'name' attribute. If missing, assume array index
|
||||||
|
// For display purposes, it can be overridden by "key"
|
||||||
|
if (!gdbMiGetStringValue(&w.name, root, "name")) {
|
||||||
|
w.name = QString::number(ctx.childIndex);
|
||||||
|
}
|
||||||
|
// Set iname
|
||||||
|
w.iname = ctx.parentIName;
|
||||||
|
w.iname += QLatin1Char('.');
|
||||||
|
w.iname += w.name;
|
||||||
|
// Key?
|
||||||
|
QString key;
|
||||||
|
if (gdbMiGetStringValue(&key, root, "key", "keyencoded")) {
|
||||||
|
w.name = key.size() > 13 ? key.mid(0, 13) + QLatin1String("...") : key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (w.name.isEmpty()) {
|
||||||
|
const QString msg = QString::fromLatin1("Internal error: Unable to determine name at level %1/%2 for %3").arg(ctx.recursionLevel).arg(w.iname, QLatin1String(root.toString(true, 2)));
|
||||||
|
qWarning("%s\n", qPrintable(msg));
|
||||||
|
}
|
||||||
|
gdbMiGetStringValue(&w.displayedType, root, "displayedtype");
|
||||||
|
if (gdbMiGetStringValue(&v, root, "editvalue"))
|
||||||
|
w.editvalue = v.toLatin1();
|
||||||
|
if (gdbMiGetStringValue(&v, root, "exp"))
|
||||||
|
w.exp = v;
|
||||||
|
gdbMiGetStringValue(&w.addr, root, "addr");
|
||||||
|
gdbMiGetStringValue(&w.saddr, root, "saddr");
|
||||||
|
gdbMiGetBoolValue(&w.valueEnabled, root, "valueenabled");
|
||||||
|
gdbMiGetBoolValue(&w.valueEditable, root, "valueeditable");
|
||||||
|
if (gdbMiGetStringValue(&v, root, "valuetooltip", "valuetooltipencoded"))
|
||||||
|
w.setValue(v);
|
||||||
|
if (gdbMiGetStringValue(&v, root, "value", "valueencoded"))
|
||||||
|
w.setValue(v);
|
||||||
|
// Type from context or self
|
||||||
|
if (ctx.childType.isEmpty()) {
|
||||||
|
if (gdbMiGetStringValue(&v, root, "type"))
|
||||||
|
w.setType(v);
|
||||||
|
} else {
|
||||||
|
w.setType(ctx.childType);
|
||||||
|
}
|
||||||
|
// child count?
|
||||||
|
int numChild = -1;
|
||||||
|
if (ctx.childNumChild >= 0) {
|
||||||
|
numChild = ctx.childNumChild;
|
||||||
|
} else {
|
||||||
|
gdbMiGetIntValue(&numChild, root, "numchild");
|
||||||
|
}
|
||||||
|
if (numChild >= 0)
|
||||||
|
w.setHasChildren(numChild > 0);
|
||||||
|
wl->push_back(w);
|
||||||
|
// Parse children with a new context
|
||||||
|
if (numChild == 0)
|
||||||
|
return;
|
||||||
|
const GdbMi childrenNode = root.findChild("children");
|
||||||
|
if (!childrenNode.isValid())
|
||||||
|
return;
|
||||||
|
const QList<GdbMi> children =childrenNode.children();
|
||||||
|
if (children.empty())
|
||||||
|
return;
|
||||||
|
wl->back().setChildrenUnneeded();
|
||||||
|
GdbMiRecursionContext nextLevelContext(ctx.recursionLevel + 1);
|
||||||
|
nextLevelContext.parentIName = w.iname;
|
||||||
|
gdbMiGetStringValue(&nextLevelContext.childType, root, "childtype");
|
||||||
|
if (!gdbMiGetIntValue(&nextLevelContext.childNumChild, root, "childnumchild"))
|
||||||
|
nextLevelContext.childNumChild = -1;
|
||||||
|
foreach(const GdbMi &child, children) {
|
||||||
|
gbdMiToWatchData(child, nextLevelContext, wl);
|
||||||
|
nextLevelContext.childIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtDumperHelper::parseValue(const char *data,
|
||||||
|
QList<WatchData> *l)
|
||||||
|
{
|
||||||
|
l->clear();
|
||||||
|
QByteArray fullData = data;
|
||||||
|
fullData.insert(0, '{');
|
||||||
|
fullData.append(data);
|
||||||
|
fullData.append('}');
|
||||||
|
GdbMi root(fullData);
|
||||||
|
if (!root.isValid())
|
||||||
|
return false;
|
||||||
|
gbdMiToWatchData(root, GdbMiRecursionContext(), l);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -90,49 +90,6 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos,
|
|||||||
// Decode string data as returned by the dumper helpers.
|
// Decode string data as returned by the dumper helpers.
|
||||||
QString decodeData(const QByteArray &baIn, int encoding);
|
QString decodeData(const QByteArray &baIn, int encoding);
|
||||||
|
|
||||||
// Result of a dumper call.
|
|
||||||
struct QtDumperResult
|
|
||||||
{
|
|
||||||
struct Child {
|
|
||||||
Child();
|
|
||||||
|
|
||||||
int keyEncoded;
|
|
||||||
int valueEncoded;
|
|
||||||
int childCount;
|
|
||||||
bool valueEnabled;
|
|
||||||
QString name;
|
|
||||||
QString address;
|
|
||||||
QString exp;
|
|
||||||
QString type;
|
|
||||||
QString displayedType;
|
|
||||||
QByteArray key;
|
|
||||||
bool valueEncountered;
|
|
||||||
QByteArray value;
|
|
||||||
};
|
|
||||||
|
|
||||||
QtDumperResult();
|
|
||||||
void clear();
|
|
||||||
QList<WatchData> toWatchData(int source = 0) const;
|
|
||||||
|
|
||||||
QString iname;
|
|
||||||
QString address;
|
|
||||||
QString addressInfo; // "<synthetic>" or such, in the 2nd adress field.
|
|
||||||
QString type;
|
|
||||||
QString extra;
|
|
||||||
QString displayedType;
|
|
||||||
bool valueEncountered;
|
|
||||||
QByteArray value;
|
|
||||||
int valueEncoded;
|
|
||||||
bool valueEnabled;
|
|
||||||
int childCount;
|
|
||||||
bool internal;
|
|
||||||
QString childType;
|
|
||||||
int childChildCount;
|
|
||||||
QList <Child> children;
|
|
||||||
};
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug in, const QtDumperResult &d);
|
|
||||||
|
|
||||||
/* Attempt to put common code of the dumper handling into a helper
|
/* Attempt to put common code of the dumper handling into a helper
|
||||||
* class.
|
* class.
|
||||||
* "Custom dumper" is a library compiled against the current
|
* "Custom dumper" is a library compiled against the current
|
||||||
@@ -210,7 +167,7 @@ public:
|
|||||||
|
|
||||||
// Parse the value response (protocol 2) from debuggee buffer.
|
// Parse the value response (protocol 2) from debuggee buffer.
|
||||||
// 'data' excludes the leading indicator character.
|
// 'data' excludes the leading indicator character.
|
||||||
static bool parseValue(const char *data, QtDumperResult *r);
|
static bool parseValue(const char *data, QList<WatchData> *l);
|
||||||
|
|
||||||
// What kind of debugger expressions are required to dump that type.
|
// What kind of debugger expressions are required to dump that type.
|
||||||
// A debugger with restricted expression syntax can handle
|
// A debugger with restricted expression syntax can handle
|
||||||
@@ -245,7 +202,9 @@ private:
|
|||||||
// They are not complete (std::allocator<X>).
|
// They are not complete (std::allocator<X>).
|
||||||
enum SpecialSizeType { IntSize, PointerSize, StdAllocatorSize,
|
enum SpecialSizeType { IntSize, PointerSize, StdAllocatorSize,
|
||||||
QSharedPointerSize, QSharedDataPointerSize,
|
QSharedPointerSize, QSharedDataPointerSize,
|
||||||
QWeakPointerSize, QPointerSize, SpecialSizeCount };
|
QWeakPointerSize, QPointerSize,
|
||||||
|
QListSize, QLinkedListSize, QVectorSize, QQueueSize,
|
||||||
|
SpecialSizeCount };
|
||||||
|
|
||||||
// Resolve name to enumeration or SpecialSizeCount (invalid)
|
// Resolve name to enumeration or SpecialSizeCount (invalid)
|
||||||
SpecialSizeType specialSizeType(const QString &t) const;
|
SpecialSizeType specialSizeType(const QString &t) const;
|
||||||
@@ -263,6 +222,10 @@ private:
|
|||||||
QString m_qSharedPointerPrefix;
|
QString m_qSharedPointerPrefix;
|
||||||
QString m_qSharedDataPointerPrefix;
|
QString m_qSharedDataPointerPrefix;
|
||||||
QString m_qWeakPointerPrefix;
|
QString m_qWeakPointerPrefix;
|
||||||
|
QString m_qListPrefix;
|
||||||
|
QString m_qLinkedListPrefix;
|
||||||
|
QString m_qVectorPrefix;
|
||||||
|
QString m_qQueuePrefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
QDebug operator<<(QDebug in, const QtDumperHelper::TypeData &d);
|
QDebug operator<<(QDebug in, const QtDumperHelper::TypeData &d);
|
||||||
|
Reference in New Issue
Block a user