forked from qt-creator/qt-creator
Fix up Debugger helpers to be able to dump QObject's with CDB.
- Make container dumper routines set "childnumchild" when known in order to avoid roundtrips; avoid repeated invocations of container.end(). - Completed dumper information in some places to avoid roundtrips. - Extended QVariant helpers by dumpers for common GUI types (rectangles, points, sizes, fonts, size policies). - Introduced artificial QObjectChildList/QObjectProperty types to be able to dump QObject children and properties without using gdb expressions. - Fixed dumping of Signal/Slot list to pass on correct types. Avoid recursions if signal is connected to self. - Replaced expressions by addresses in the dumpers to it make work for CDB. - Reworked dumper test program to have -a, making it usable for tests, add further types. - Gdb: Clear output buffer before calling dumpers, avoiding mixups in case evaluation of expression fails. - Fix the dumper parser used by CDB, do not be fooled by "<synthetic>" addresses, etc. - Pass on a "dumperVersion" in initial query.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -4,8 +4,6 @@
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT -= gui
|
||||
|
||||
TARGET = dumpertest
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtGui/QAction>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
@@ -174,6 +176,20 @@ static int dumpQMapIntString()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dumpQVariant()
|
||||
{
|
||||
QVariant test(QLatin1String("item"));
|
||||
prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
|
||||
qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputs("\n\n", stdout);
|
||||
test = QVariant(QStringList(QLatin1String("item1")));
|
||||
prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
|
||||
qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --------------- std types
|
||||
|
||||
static int dumpStdString()
|
||||
@@ -309,76 +325,127 @@ static int dumpStdMapIntString()
|
||||
static int dumpQObject()
|
||||
{
|
||||
// Requires the childOffset to be know, but that is not critical
|
||||
QTimer t;
|
||||
QAction action(0);
|
||||
QObject x;
|
||||
QAction *a2= new QAction(&action);
|
||||
a2->setObjectName(QLatin1String("a2"));
|
||||
action.setObjectName(QLatin1String("action"));
|
||||
QObject::connect(&action, SIGNAL(triggered()), &x, SLOT(deleteLater()));
|
||||
prepareInBuffer("QObject", "local.qobject", "local.qobject", "");
|
||||
qDumpObjectData440(2, 42, testAddress(&t), 1, 0, 0, 0, 0);
|
||||
qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputs("\n\n", stdout);
|
||||
// Property list
|
||||
prepareInBuffer("QObjectPropertyList", "local.qobjectpropertylist", "local.qobjectpropertylist", "");
|
||||
qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputs("\n\n", stdout);
|
||||
// Signal list
|
||||
prepareInBuffer("QObjectSignalList", "local.qobjectsignallist", "local.qobjectsignallist", "");
|
||||
qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
// Slot list
|
||||
prepareInBuffer("QObjectSlotList", "local.qobjectslotlist", "local.qobjectslotlist", "");
|
||||
qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputs("\n\n", stdout);
|
||||
// Signal list
|
||||
prepareInBuffer("QObjectChildList", "local.qobjectchildlist", "local.qobjectchildlist", "");
|
||||
qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool dumpType(const char *arg)
|
||||
static int dumpQObjectList()
|
||||
{
|
||||
if (!qstrcmp(arg, "QString"))
|
||||
{ dumpQString(); return true; }
|
||||
if (!qstrcmp(arg, "QSharedPointer<QString>"))
|
||||
{ dumpQSharedPointerQString(); return true; }
|
||||
if (!qstrcmp(arg, "QStringList"))
|
||||
{ dumpQStringList(); return true; }
|
||||
if (!qstrcmp(arg, "QList<int>"))
|
||||
{ dumpQIntList(); return true; }
|
||||
if (!qstrcmp(arg, "QList<std::string>"))
|
||||
{ dumpStdStringQList(); return true; }
|
||||
if (!qstrcmp(arg, "QVector<int>"))
|
||||
{ dumpQIntVector(); return true; }
|
||||
if (!qstrcmp(arg, "QMap<int,QString>"))
|
||||
{ dumpQMapIntString(); return true; }
|
||||
if (!qstrcmp(arg, "QMap<int,int>"))
|
||||
{ dumpQMapIntInt(); return true; }
|
||||
if (!qstrcmp(arg, "string"))
|
||||
{ dumpStdString(); return true; }
|
||||
if (!qstrcmp(arg, "wstring"))
|
||||
{ dumpStdWString(); return true; }
|
||||
if (!qstrcmp(arg, "list<int>"))
|
||||
{ dumpStdIntList(); return true; }
|
||||
if (!qstrcmp(arg, "list<string>"))
|
||||
{ dumpStdStringList(); return true; }
|
||||
if (!qstrcmp(arg, "vector<int>"))
|
||||
{ dumpStdIntVector(); return true; }
|
||||
if (!qstrcmp(arg, "vector<string>"))
|
||||
{ dumpStdStringVector(); return true; }
|
||||
if (!qstrcmp(arg, "vector<wstring>"))
|
||||
{ dumpStdWStringVector(); return true; }
|
||||
if (!qstrcmp(arg, "set<int>"))
|
||||
{ dumpStdIntSet(); return true; }
|
||||
if (!qstrcmp(arg, "set<string>"))
|
||||
{ dumpStdStringSet(); return true; }
|
||||
if (!qstrcmp(arg, "map<int,string>"))
|
||||
{ dumpStdMapIntString(); return true; }
|
||||
if (!qstrcmp(arg, "QObject"))
|
||||
{ dumpQObject(); return true; }
|
||||
return false;
|
||||
// Requires the childOffset to be know, but that is not critical
|
||||
QObject *root = new QObject;
|
||||
root ->setObjectName("root");
|
||||
QTimer *t1 = new QTimer;
|
||||
t1 ->setObjectName("t1");
|
||||
QTimer *t2 = new QTimer;
|
||||
t2 ->setObjectName("t2");
|
||||
QObjectList test;
|
||||
test << root << t1 << t2;
|
||||
prepareInBuffer("QList", "local.qobjectlist", "local.qobjectlist", "QObject *");
|
||||
qDumpObjectData440(2, 42, testAddress(&test), sizeof(QObject*), 0, 0, 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputc('\n', stdout);
|
||||
delete root;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*DumpFunction)();
|
||||
typedef QMap<QString, DumpFunction> TypeDumpFunctionMap;
|
||||
|
||||
static TypeDumpFunctionMap registerTypes()
|
||||
{
|
||||
TypeDumpFunctionMap rc;
|
||||
rc.insert("QString", dumpQString);
|
||||
rc.insert("QSharedPointer<QString>", dumpQSharedPointerQString);
|
||||
rc.insert("QStringList", dumpQStringList);
|
||||
rc.insert("QList<int>", dumpQIntList);
|
||||
rc.insert("QList<std::string>", dumpStdStringQList);
|
||||
rc.insert("QVector<int>", dumpQIntVector);
|
||||
rc.insert("QMap<int,QString>", dumpQMapIntString);
|
||||
rc.insert("QMap<int,int>", dumpQMapIntInt);
|
||||
rc.insert("string", dumpStdString);
|
||||
rc.insert("wstring", dumpStdWString);
|
||||
rc.insert("list<int>", dumpStdIntList);
|
||||
rc.insert("list<string>", dumpStdStringList);
|
||||
rc.insert("vector<int>", dumpStdIntVector);
|
||||
rc.insert("vector<string>", dumpStdStringVector);
|
||||
rc.insert("vector<wstring>", dumpStdWStringVector);
|
||||
rc.insert("set<int>", dumpStdIntSet);
|
||||
rc.insert("set<string>", dumpStdStringSet);
|
||||
rc.insert("map<int,string>", dumpStdMapIntString);
|
||||
rc.insert("QObject", dumpQObject);
|
||||
rc.insert("QObjectList", dumpQObjectList);
|
||||
rc.insert("QVariant", dumpQVariant);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("\nQt Creator Debugging Helper testing tool\n\n");
|
||||
printf("Running query protocol\n");
|
||||
qDumpObjectData440(1, 42, 0, 1, 0, 0, 0, 0);
|
||||
fputs(qDumpOutBuffer, stdout);
|
||||
fputc('\n', stdout);
|
||||
fputc('\n', stdout);
|
||||
if (argc < 2)
|
||||
return 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "-u")) {
|
||||
optTestUninitialized = true;
|
||||
printf("\nTesting uninitialized...\n");
|
||||
continue;
|
||||
|
||||
const TypeDumpFunctionMap tdm = registerTypes();
|
||||
const TypeDumpFunctionMap::const_iterator cend = tdm.constEnd();
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s [-a]|<type1> <type2..>\n", argv[0]);
|
||||
printf("Supported types: ");
|
||||
for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) {
|
||||
fputs(qPrintable(it.key()), stdout);
|
||||
fputc(' ', stdout);
|
||||
}
|
||||
printf("\nTesting %s\n", arg);
|
||||
if (!dumpType(arg))
|
||||
printf("\nUnhandled type: %s\n", arg);
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
int rc = 0;
|
||||
if (argc == 2 && !qstrcmp(argv[1], "-a")) {
|
||||
for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) {
|
||||
printf("\nTesting: %s\n", qPrintable(it.key()));
|
||||
rc += (*it.value())();
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
printf("\nTesting: %s\n", arg);
|
||||
const TypeDumpFunctionMap::const_iterator it = tdm.constFind(QLatin1String(arg));
|
||||
if (it == cend) {
|
||||
rc = -1;
|
||||
fprintf(stderr, "\nUnhandled type: %s\n", argv[i]);
|
||||
} else {
|
||||
rc = (*it.value())();
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@@ -561,6 +561,10 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
|
||||
*errorMessage = msgNotHandled(wd.type);
|
||||
return DumpNotHandled;
|
||||
}
|
||||
if (wd.addr.isEmpty()) {
|
||||
*errorMessage = QString::fromLatin1("Adress is missing for '%1' (%2).").arg(wd.exp, wd.type);
|
||||
return DumpNotHandled;
|
||||
}
|
||||
|
||||
// Ensure types are parsed and known.
|
||||
if (!ensureInitialized(errorMessage)) {
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "watchhandler.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
@@ -164,6 +165,46 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt
|
||||
return handled;
|
||||
}
|
||||
|
||||
// When querying an item, the queried item is sometimes returned in incomplete form.
|
||||
// Take over values from source.
|
||||
static inline void fixDumperResult(const WatchData &source,
|
||||
QList<WatchData> *result,
|
||||
bool suppressGrandChildren)
|
||||
{
|
||||
const int size = result->size();
|
||||
if (!size)
|
||||
return;
|
||||
WatchData &returned = result->front();
|
||||
if (returned.iname != source.iname)
|
||||
return;
|
||||
if (returned.type.isEmpty())
|
||||
returned.setType(source.type);
|
||||
if (returned.isValueNeeded()) {
|
||||
if (source.isValueKnown()) {
|
||||
returned.setValue(source.value);
|
||||
} else {
|
||||
// Should not happen
|
||||
returned.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
|
||||
}
|
||||
}
|
||||
if (size == 1)
|
||||
return;
|
||||
// Fix the children: If the address is missing, we cannot query any further.
|
||||
const QList<WatchData>::iterator wend = result->end();
|
||||
QList<WatchData>::iterator it = result->begin();
|
||||
for (++it; it != wend; ++it) {
|
||||
WatchData &wd = *it;
|
||||
if (wd.addr.isEmpty() && wd.isSomethingNeeded()) {
|
||||
wd.setAllUnneeded();
|
||||
} else {
|
||||
// Hack: Suppress endless recursion of the model. To be fixed,
|
||||
// the model should not query non-visible items.
|
||||
if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded()))
|
||||
wd.setHasChildren(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
|
||||
{
|
||||
if (debugCDBWatchHandling)
|
||||
@@ -180,9 +221,7 @@ WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
|
||||
if (debugCDBWatchHandling)
|
||||
qDebug() << "dumper triggered";
|
||||
// Dumpers omit types for complicated templates
|
||||
if (!m_dumperResult.isEmpty() && m_dumperResult.front().type.isEmpty()
|
||||
&& m_dumperResult.front().iname == wd.iname)
|
||||
m_dumperResult.front().setType(wd.type);
|
||||
fixDumperResult(wd, &m_dumperResult, false);
|
||||
// Discard the original item and insert the dumper results
|
||||
foreach(const WatchData &dwd, m_dumperResult)
|
||||
m_wh->insertData(dwd);
|
||||
@@ -254,12 +293,17 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
|
||||
QList<WatchData> dumperResult;
|
||||
const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, OwnerDumper, &dumperResult, errorMessage);
|
||||
if (dr == CdbDumperHelper::DumpOk) {
|
||||
// Hack to stop endless model recursion
|
||||
const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname);
|
||||
fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren);
|
||||
foreach(const WatchData &dwd, dumperResult)
|
||||
wh->insertData(dwd);
|
||||
} 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);
|
||||
qWarning("%s", qPrintable(msg));
|
||||
WatchData wd = incompleteLocal;
|
||||
if (wd.isValueNeeded())
|
||||
wd.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
|
||||
wd.setAllUnneeded();
|
||||
wh->insertData(wd);
|
||||
}
|
||||
|
@@ -3192,24 +3192,36 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const
|
||||
//qDebug() << m_availableSimpleDebuggingHelpers << "DATA DUMPERS AVAILABLE";
|
||||
}
|
||||
|
||||
void GdbEngine::sendWatchParameters(const QByteArray ¶ms0)
|
||||
static inline QString arrayFillCommand(const char *array, const QByteArray ¶ms)
|
||||
{
|
||||
QByteArray params = params0;
|
||||
params.append('\0');
|
||||
char buf[50];
|
||||
sprintf(buf, "set {char[%d]} &qDumpInBuffer = {", params.size());
|
||||
sprintf(buf, "set {char[%d]} &%s = {", params.size(), array);
|
||||
QByteArray encoded;
|
||||
encoded.append(buf);
|
||||
for (int i = 0; i != params.size(); ++i) {
|
||||
const int size = params.size();
|
||||
for (int i = 0; i != size; ++i) {
|
||||
sprintf(buf, "%d,", int(params[i]));
|
||||
encoded.append(buf);
|
||||
}
|
||||
encoded[encoded.size() - 1] = '}';
|
||||
return _(encoded);
|
||||
}
|
||||
|
||||
void GdbEngine::sendWatchParameters(const QByteArray ¶ms0)
|
||||
{
|
||||
QByteArray params = params0;
|
||||
params.append('\0');
|
||||
const QString inBufferCmd = arrayFillCommand("qDumpInBuffer", params);
|
||||
|
||||
params.replace('\0','!');
|
||||
emit gdbInputAvailable(LogMisc, QString::fromUtf8(params));
|
||||
|
||||
postCommand(_(encoded));
|
||||
params.clear();
|
||||
params.append('\0');
|
||||
const QString outBufferCmd = arrayFillCommand("qDumpOutBuffer", params);
|
||||
|
||||
postCommand(inBufferCmd);
|
||||
postCommand(outBufferCmd);
|
||||
}
|
||||
|
||||
void GdbEngine::handleVarAssign(const GdbResultRecord &, const QVariant &)
|
||||
|
@@ -209,6 +209,8 @@ QString WatchData::toString() const
|
||||
QTextStream str(&res);
|
||||
if (!iname.isEmpty())
|
||||
str << "iname=\"" << iname << doubleQuoteComma;
|
||||
if (!addr.isEmpty())
|
||||
str << "addr=\"" << addr << doubleQuoteComma;
|
||||
if (!exp.isEmpty())
|
||||
str << "exp=\"" << exp << doubleQuoteComma;
|
||||
|
||||
@@ -780,6 +782,7 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
|
||||
|
||||
void WatchModel::insertData(const WatchData &data)
|
||||
{
|
||||
// qDebug() << "WMI:" << data.toString();
|
||||
QTC_ASSERT(!data.iname.isEmpty(), return);
|
||||
WatchItem *parent = findItem(parentName(data.iname), m_root);
|
||||
if (!parent) {
|
||||
|
@@ -470,16 +470,19 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos,
|
||||
QtDumperResult::Child::Child() :
|
||||
keyEncoded(0),
|
||||
valueEncoded(0),
|
||||
childCount(0),
|
||||
valuedisabled(false)
|
||||
childCount(-1),
|
||||
valuedisabled(false),
|
||||
valueEncountered(false)
|
||||
{
|
||||
}
|
||||
|
||||
QtDumperResult::QtDumperResult() :
|
||||
valueEncountered(false),
|
||||
valueEncoded(0),
|
||||
valuedisabled(false),
|
||||
childCount(0),
|
||||
internal(false)
|
||||
childCount(-1),
|
||||
internal(false),
|
||||
childChildCount(-1)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -488,15 +491,17 @@ void QtDumperResult::clear()
|
||||
iname.clear();
|
||||
value.clear();
|
||||
address.clear();
|
||||
addressInfo.clear();
|
||||
type.clear();
|
||||
extra.clear();
|
||||
displayedType.clear();
|
||||
valueEncoded = 0;
|
||||
valuedisabled = false;
|
||||
childCount = 0;
|
||||
valueEncountered = valuedisabled = false;
|
||||
childCount = -1;
|
||||
internal = false;
|
||||
childType.clear();
|
||||
children.clear();
|
||||
childChildCount = -1;
|
||||
}
|
||||
|
||||
QList<WatchData> QtDumperResult::toWatchData(int source) const
|
||||
@@ -508,45 +513,70 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
|
||||
const QChar dot = QLatin1Char('.');
|
||||
const int lastDotIndex = root.iname.lastIndexOf(dot);
|
||||
root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1);
|
||||
root.setValue(decodeData(value, valueEncoded));
|
||||
if (valueEncountered) {
|
||||
root.setValue(decodeData(value, valueEncoded));
|
||||
root.valuedisabled = valuedisabled;
|
||||
}
|
||||
root.setType(displayedType.isEmpty() ? type : displayedType);
|
||||
root.valuedisabled = valuedisabled;
|
||||
root.setAddress(address);
|
||||
root.source = source;
|
||||
root.setHasChildren(childCount > 0);
|
||||
// Children
|
||||
if (childCount > 0) {
|
||||
if (children.size() == childCount) {
|
||||
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;
|
||||
wchild.iname += dot;
|
||||
wchild.iname += dchild.name;
|
||||
// Use key entry as name (which is used for map nodes)
|
||||
if (dchild.key.isEmpty()) {
|
||||
wchild.name = dchild.name;
|
||||
} else {
|
||||
wchild.name = decodeData(dchild.key, dchild.keyEncoded);
|
||||
if (wchild.name.size() > 13) {
|
||||
wchild.name.truncate(12);
|
||||
wchild.name += QLatin1String("...");
|
||||
}
|
||||
}
|
||||
wchild.exp = dchild.exp;
|
||||
wchild.valuedisabled = dchild.valuedisabled;
|
||||
wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
|
||||
wchild.setAddress(dchild.address);
|
||||
wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
|
||||
wchild.setHasChildren(false);
|
||||
}
|
||||
root.setChildrenUnneeded();
|
||||
} else {
|
||||
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;
|
||||
wchild.iname += dot;
|
||||
wchild.iname += dchild.name;
|
||||
// Use key entry as name (which is used for map nodes)
|
||||
if (dchild.key.isEmpty()) {
|
||||
wchild.name = dchild.name;
|
||||
} else {
|
||||
wchild.name = decodeData(dchild.key, dchild.keyEncoded);
|
||||
if (wchild.name.size() > 13) {
|
||||
wchild.name.truncate(12);
|
||||
wchild.name += QLatin1String("...");
|
||||
}
|
||||
}
|
||||
wchild.exp = dchild.exp;
|
||||
if (dchild.valueEncountered) {
|
||||
wchild.valuedisabled = dchild.valuedisabled;
|
||||
wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
|
||||
}
|
||||
wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
|
||||
wchild.setAddress(dchild.address);
|
||||
// Child overrides.
|
||||
const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount;
|
||||
switch (effectiveChildChildCount) {
|
||||
case -1:
|
||||
wchild.setChildrenNeeded();
|
||||
wchild.setHasChildrenNeeded();
|
||||
break;
|
||||
case 0:
|
||||
wchild.setHasChildren(false);
|
||||
break;
|
||||
default:
|
||||
wchild.setHasChildren(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
QDebug nospace = qDebug().nospace();
|
||||
nospace << "QtDumperResult::toWatchData" << *this << '\n';
|
||||
foreach(const WatchData &wd, rc)
|
||||
nospace << " " << wd.toString() << '\n';
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -554,11 +584,20 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
|
||||
{
|
||||
QDebug nospace = in.nospace();
|
||||
nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType
|
||||
<< " address=" << d.address
|
||||
<< " value=" << d.value
|
||||
<< " disabled=" << d.valuedisabled
|
||||
<< " encoded=" << d.valueEncoded << " internal=" << d.internal
|
||||
<< " address=" << d.address;
|
||||
if (!d.addressInfo.isEmpty())
|
||||
nospace << " addressInfo=" << d.addressInfo;
|
||||
if (d.valueEncountered) {
|
||||
nospace << " encoded=" << d.valueEncoded
|
||||
<< " value=" << d.value
|
||||
<< " disabled=" << d.valuedisabled;
|
||||
} 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
|
||||
@@ -571,8 +610,12 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
|
||||
<< " name=" << c.name;
|
||||
if (!c.key.isEmpty())
|
||||
nospace << " keyencoded=" << c.keyEncoded << " key=" << c.key;
|
||||
nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value
|
||||
<< "childcount=" << c.childCount << '\n';
|
||||
if (c.valueEncountered) {
|
||||
nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value;
|
||||
} else {
|
||||
nospace << " <no value>";
|
||||
}
|
||||
nospace << "childcount=" << c.childCount << '\n';
|
||||
}
|
||||
}
|
||||
return in;
|
||||
@@ -608,6 +651,7 @@ void QtDumperHelper::clear()
|
||||
m_sizeCache.clear();
|
||||
qFill(m_specialSizes, m_specialSizes + SpecialSizeCount, 0);
|
||||
m_expressionCache.clear();
|
||||
m_dumperVersion.clear();
|
||||
}
|
||||
|
||||
static inline void formatQtVersion(int v, QTextStream &str)
|
||||
@@ -622,7 +666,7 @@ QString QtDumperHelper::toString(bool debug) const
|
||||
QTextStream str(&rc);
|
||||
str << "version=";
|
||||
formatQtVersion(m_qtVersion, str);
|
||||
str << " namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: ";
|
||||
str << "dumperversion='" << m_dumperVersion << "' namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: ";
|
||||
const NameTypeMap::const_iterator cend = m_nameTypeMap.constEnd();
|
||||
for (NameTypeMap::const_iterator it = m_nameTypeMap.constBegin(); it != cend; ++it) {
|
||||
str <<",[" << it.key() << ',' << it.value() << ']';
|
||||
@@ -639,9 +683,9 @@ QString QtDumperHelper::toString(bool debug) const
|
||||
}
|
||||
const QString nameSpace = m_qtNamespace.isEmpty() ? QCoreApplication::translate("QtDumperHelper", "<none>") : m_qtNamespace;
|
||||
return QCoreApplication::translate("QtDumperHelper",
|
||||
"%n known types, Qt version: %1, Qt namespace: %2",
|
||||
"%n known types, Qt version: %1, Qt namespace: %2 Dumper version: %3",
|
||||
0, QCoreApplication::CodecForTr,
|
||||
m_nameTypeMap.size()).arg(qtVersionString(), nameSpace);
|
||||
m_nameTypeMap.size()).arg(qtVersionString(), nameSpace, m_dumperVersion);
|
||||
}
|
||||
|
||||
QtDumperHelper::Type QtDumperHelper::simpleType(const QString &simpleType) const
|
||||
@@ -726,10 +770,9 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
|
||||
|
||||
QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Type t)
|
||||
{
|
||||
|
||||
switch (t) {
|
||||
case QAbstractItemType:
|
||||
case QObjectSlotType:
|
||||
case QObjectSignalType:
|
||||
case QVectorType:
|
||||
case StdMapType:
|
||||
return NeedsComplexExpression;
|
||||
@@ -738,6 +781,7 @@ QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Typ
|
||||
case QMapNodeType:
|
||||
return NeedsCachedExpression;
|
||||
default:
|
||||
// QObjectSlotType, QObjectSignalType need the signal number, which is numeric
|
||||
break;
|
||||
}
|
||||
return NeedsNoExpression;
|
||||
@@ -968,9 +1012,9 @@ public:
|
||||
explicit QueryDumperParser(const char *s);
|
||||
|
||||
struct Data {
|
||||
Data() : qtVersion(0) {}
|
||||
QString qtNameSpace;
|
||||
QString qtVersion;
|
||||
QString dumperVersion;
|
||||
QStringList types;
|
||||
QList<SizeEntry> sizes;
|
||||
QMap<QString, QString> expressionCache;
|
||||
@@ -986,7 +1030,7 @@ protected:
|
||||
virtual bool handleValue(const char *k, int size);
|
||||
|
||||
private:
|
||||
enum Mode { None, ExpectingDumpers, ExpectingVersion,
|
||||
enum Mode { None, ExpectingDumpers, ExpectingQtVersion, ExpectingDumperVersion,
|
||||
ExpectingNameSpace, ExpectingSizes, ExpectingExpressionCache };
|
||||
Mode m_mode;
|
||||
Data m_data;
|
||||
@@ -1017,7 +1061,11 @@ bool QueryDumperParser::handleKeyword(const char *k, int size)
|
||||
return true;
|
||||
}
|
||||
if (!qstrncmp(k, "qtversion", size)) {
|
||||
m_mode = ExpectingVersion;
|
||||
m_mode = ExpectingQtVersion;
|
||||
return true;
|
||||
}
|
||||
if (!qstrncmp(k, "dumperversion", size)) {
|
||||
m_mode = ExpectingDumperVersion;
|
||||
return true;
|
||||
}
|
||||
if (!qstrncmp(k, "namespace", size)) {
|
||||
@@ -1038,7 +1086,7 @@ bool QueryDumperParser::handleKeyword(const char *k, int size)
|
||||
|
||||
bool QueryDumperParser::handleListStart()
|
||||
{
|
||||
return m_mode == ExpectingDumpers || m_mode == ExpectingVersion;
|
||||
return m_mode == ExpectingDumpers || m_mode == ExpectingQtVersion;
|
||||
}
|
||||
|
||||
bool QueryDumperParser::handleListEnd()
|
||||
@@ -1064,7 +1112,10 @@ bool QueryDumperParser::handleValue(const char *k, int size)
|
||||
case ExpectingNameSpace:
|
||||
m_data.qtNameSpace = QString::fromLatin1(k, size);
|
||||
break;
|
||||
case ExpectingVersion: // ["4","1","5"]
|
||||
case ExpectingDumperVersion:
|
||||
m_data.dumperVersion = QString::fromLatin1(k, size);
|
||||
break;
|
||||
case ExpectingQtVersion: // ["4","1","5"]
|
||||
if (!m_data.qtVersion.isEmpty())
|
||||
m_data.qtVersion += QLatin1Char('.');
|
||||
m_data.qtVersion += QString::fromLatin1(k, size);
|
||||
@@ -1092,6 +1143,7 @@ bool QtDumperHelper::parseQuery(const char *data, Debugger debugger)
|
||||
foreach (const QueryDumperParser::SizeEntry &se, parser.data().sizes)
|
||||
addSize(se.first, se.second);
|
||||
m_expressionCache = parser.data().expressionCache;
|
||||
m_dumperVersion = parser.data().dumperVersion;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1248,17 +1300,6 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
|
||||
case QAbstractItemType:
|
||||
inner = data.addr.mid(1);
|
||||
break;
|
||||
case QObjectType:
|
||||
case QWidgetType:
|
||||
if (debugger == GdbDebugger) {
|
||||
extraArgs[0] = QLatin1String("(char*)&((('");
|
||||
extraArgs[0] += m_qtNamespace;
|
||||
extraArgs[0] += QLatin1String("QObjectPrivate'*)&");
|
||||
extraArgs[0] += data.exp;
|
||||
extraArgs[0] += QLatin1String(")->children)-(char*)&");
|
||||
extraArgs[0] += data.exp;
|
||||
}
|
||||
break;
|
||||
case QVectorType:
|
||||
extraArgs[1] = QLatin1String("(char*)&((");
|
||||
extraArgs[1] += data.exp;
|
||||
@@ -1355,6 +1396,8 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
|
||||
qWarning("Unknown type encountered in %s.\n", Q_FUNC_INFO);
|
||||
break;
|
||||
case SupportedType:
|
||||
case QObjectType:
|
||||
case QWidgetType:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1412,6 +1455,7 @@ private:
|
||||
ExpectingType, ExpectingDisplayedType, ExpectingInternal,
|
||||
ExpectingValueDisabled, ExpectingValueEncoded,
|
||||
ExpectingCommonChildType, ExpectingChildCount,
|
||||
ExpectingChildChildOverrideCount,
|
||||
ExpectingExtra,
|
||||
IgnoreNext,
|
||||
ChildModeStart,
|
||||
@@ -1488,7 +1532,7 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
|
||||
if (!qstrncmp(keyword, "displayedtype", size))
|
||||
return ExpectingDisplayedType;
|
||||
if (!qstrncmp(keyword, "childnumchild", size))
|
||||
return IgnoreNextChildMode;
|
||||
return ExpectingChildChildOverrideCount;
|
||||
break;
|
||||
}
|
||||
return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext;
|
||||
@@ -1519,10 +1563,17 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
case ExpectingIName:
|
||||
m_result.iname = QString::fromLatin1(valueBA);
|
||||
break;
|
||||
case ExpectingAddress:
|
||||
m_result.address = 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 ExpectingValueDisabled:
|
||||
@@ -1549,6 +1600,9 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
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:
|
||||
@@ -1566,6 +1620,7 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
m_result.children.back().key = valueBA;
|
||||
break;
|
||||
case ExpectingChildValue:
|
||||
m_result.children.back().valueEncountered = true;
|
||||
m_result.children.back().value = valueBA;
|
||||
break;
|
||||
case ExpectingChildExpression:
|
||||
@@ -1590,12 +1645,13 @@ bool ValueDumperParser::handleValue(const char *k, int size)
|
||||
bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
|
||||
{
|
||||
ValueDumperParser parser(data);
|
||||
|
||||
if (!parser.run())
|
||||
return false;
|
||||
*r = parser.result();
|
||||
// Sanity
|
||||
if (r->childCount < r->children.size())
|
||||
r->childCount = r->children.size();
|
||||
if (!r->children.empty() && r->childCount != r->children.size())
|
||||
r->childCount = r->children.size();
|
||||
if (debug)
|
||||
qDebug() << '\n' << data << '\n' << *r;
|
||||
return true;
|
||||
|
@@ -99,6 +99,7 @@ struct QtDumperResult
|
||||
QString exp;
|
||||
QString type;
|
||||
QByteArray key;
|
||||
bool valueEncountered;
|
||||
QByteArray value;
|
||||
};
|
||||
|
||||
@@ -108,15 +109,18 @@ struct QtDumperResult
|
||||
|
||||
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 valuedisabled;
|
||||
int childCount;
|
||||
bool internal;
|
||||
QString childType;
|
||||
int childChildCount;
|
||||
QList <Child> children;
|
||||
};
|
||||
|
||||
@@ -242,6 +246,7 @@ private:
|
||||
|
||||
QMap<QString, QString> m_expressionCache;
|
||||
int m_qtVersion;
|
||||
QString m_dumperVersion;
|
||||
QString m_qtNamespace;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user