diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index 70a9dc60d94cf496c54c1286948af13f49a0b5bf..fb8d23702a57fb2c7c79e21b06e46c16a9fa95a0 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -623,7 +623,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpTypeI(const WatchData &wd, bool *errorMessage = msgNotHandled(wd.type); return DumpNotHandled; } - if (wd.addr.isEmpty()) { + if (wd.address == 0) { *errorMessage = QString::fromLatin1("Address is missing for '%1' (%2).") .arg(QString::fromUtf8(wd.exp)).arg(QString::fromUtf8(wd.type)); return DumpNotHandled; @@ -690,7 +690,7 @@ CdbDumperHelper::DumpExecuteResult m_helper.evaluationParameters(wd, td, QtDumperHelper::CdbDebugger, &inBuffer, &extraParameters); QString callCmd; QTextStream str(&callCmd); - str << ".call " << m_dumpObjectSymbol << "(2,0," << wd.addr << ',' << (dumpChildren ? 1 : 0); + str << ".call " << m_dumpObjectSymbol << "(2,0," << wd.hexAddress() << ',' << (dumpChildren ? 1 : 0); foreach(const QByteArray &e, extraParameters) str << ',' << QString::fromUtf8(e); str << ')'; diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index c0a9cf8873a5b2cf7f1af3e881550fc91fa31fbb..2f4bce52ca968a56791a903722e2d403311ebe65 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -198,7 +198,7 @@ static inline void fixDumperResult(const WatchData &source, it->source |= CdbSymbolGroupContext::ChildrenKnownBit; // Cannot dump items with missing addresses or missing types const bool typeFixed = fixDumperType(&wd); // Order of evaluation! - if ((wd.addr.isEmpty() && wd.isSomethingNeeded()) || typeFixed) { + if ((wd.address == 0 && wd.isSomethingNeeded()) || typeFixed) { wd.setHasChildren(false); wd.setAllUnneeded(); } else { @@ -239,7 +239,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt const QByteArray type = stripPointerType(wd.type); WatchData derefedWd; derefedWd.setType(type); - derefedWd.setAddress(hexAddrS.toLatin1()); + derefedWd.setHexAddress(hexAddrS.toAscii()); derefedWd.name = QString(QLatin1Char('*')); derefedWd.iname = wd.iname + ".*"; derefedWd.source = OwnerDumper | CdbSymbolGroupContext::ChildrenKnownBit; @@ -373,7 +373,7 @@ unsigned CdbSymbolGroupContext::watchDataAt(unsigned long index, WatchData *wd) const unsigned rc = dumpValue(index, &iname, &(wd->name), &address, &typeId, &type, &value); wd->exp = wd->iname = iname.toLatin1(); - wd->setAddress("0x" + QByteArray::number(address, 16)); + wd->setAddress(address); wd->setType(type.toUtf8(), false); if (rc & OutOfScope) { wd->setError(WatchData::msgNotInScope()); diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp index 2d39ffb3aa7f4f75c5383866027da4ca16e73a4b..b199254c9f7fcc43026a1b5ac0fa0a74678a31e5 100644 --- a/src/plugins/debugger/gdb/classicgdbengine.cpp +++ b/src/plugins/debugger/gdb/classicgdbengine.cpp @@ -183,8 +183,8 @@ void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChild //int protocol = isDisplayedIName(data.iname) ? 3 : 2; QByteArray addr; - if (data.addr.startsWith("0x")) - addr = "(void*)" + data.addr; + if (data.address) + addr = "(void*)" + data.hexAddress(); else if (data.exp.isEmpty()) // happens e.g. for QAbstractItem addr = QByteArray(1, '0'); else @@ -220,8 +220,8 @@ void GdbEngine::createGdbVariableClassic(const WatchData &data) } postCommand("-var-delete \"" + data.iname + '"', WatchUpdate); QByteArray exp = data.exp; - if (exp.isEmpty() && data.addr.startsWith("0x")) - exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.addr; + if (exp.isEmpty() && data.address) + exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress(); QVariant val = QVariant::fromValue<WatchData>(data); postCommand("-var-create \"" + data.iname + "\" * \"" + exp + '"', WatchUpdate, CB(handleVarCreate), val); @@ -474,8 +474,13 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response) data1.name = _("[%1]").arg(i); data1.type = data.type.left(data.type.size() - 4); data1.iname = data.iname + '.' + QByteArray::number(i); - data1.addr = list.at(i); - data1.exp = "((" + gdbQuoteTypes(data1.type) + "*)" + data1.addr + ')'; + const QByteArray &addressSpec = list.at(i); + if (addressSpec.startsWith("0x")) { + data.setHexAddress(addressSpec); + } else { + data.dumperFlags = addressSpec; // Item model dumpers pull tricks + } + data1.exp = "((" + gdbQuoteTypes(data1.type) + "*)" + addressSpec + ')'; data1.setHasChildren(false); data1.setValueNeeded(); QByteArray cmd = "qdumpqstring (" + data1.exp + ')'; diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 591f420bdfeeeb5688431d61d21b97eb4de24652..74171d0d0b809ef15046a41321c080962ec4282d 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -19,6 +19,7 @@ namespace Internal { WatchData::WatchData() : editformat(0), + address(0), hasChildren(false), generation(-1), valueEnabled(true), @@ -42,7 +43,7 @@ bool WatchData::isEqual(const WatchData &other) const && type == other.type && displayedType == other.displayedType && variable == other.variable - && addr == other.addr + && address == other.address && framekey == other.framekey && hasChildren == other.hasChildren && valueEnabled == other.valueEnabled @@ -145,9 +146,22 @@ void WatchData::setType(const QByteArray &str, bool guessChildrenFromType) } } -void WatchData::setAddress(const QByteArray &a) +void WatchData::setAddress(const quint64 &a) { - addr = a; + address = a; +} + +void WatchData::setHexAddress(const QByteArray &a) +{ + bool ok; + const qint64 av = a.toULongLong(&ok, 16); + if (ok) { + address = av; + } else { + qWarning("WatchData::setHexAddress(): Failed to parse address value '%s' for '%s', '%s'", + a.constData(), iname.constData(), type.constData()); + address = 0; + } } QString WatchData::toString() const @@ -162,8 +176,11 @@ QString WatchData::toString() const str << "name=\"" << name << doubleQuoteComma; if (error) str << "error,"; - if (!addr.isEmpty()) - str << "addr=\"" << addr << doubleQuoteComma; + if (address) { + str.setIntegerBase(16); + str << "addr=\"0x" << address << doubleQuoteComma; + str.setIntegerBase(10); + } if (!exp.isEmpty()) str << "exp=\"" << exp << doubleQuoteComma; @@ -179,6 +196,9 @@ QString WatchData::toString() const str << "editvalue=\"<...>\","; // str << "editvalue=\"" << editvalue << doubleQuoteComma; + if (!dumperFlags.isEmpty()) + str << "dumperFlags=\"" << dumperFlags << doubleQuoteComma; + if (isTypeNeeded()) str << "type=<needed>,"; if (isTypeKnown() && !type.isEmpty()) @@ -234,7 +254,8 @@ QString WatchData::toToolTip() const val += QCoreApplication::translate("Debugger::Internal::WatchHandler", " ... <cut off>"); } formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Value"), val); - formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Object Address"), addr); + formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Object Address"), + QString::fromAscii(hexAddress())); formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Internal ID"), iname); formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Generation"), QString::number(generation)); @@ -267,13 +288,12 @@ QString WatchData::shadowedName(const QString &name, int seen) quint64 WatchData::coreAddress() const { - if (!addr.isEmpty()) { - bool ok; - const quint64 address = addr.toULongLong(&ok, 16); - if (ok) - return address; - } - return quint64(0); + return address; +} + +QByteArray WatchData::hexAddress() const +{ + return address ? (QByteArray("0x") + QByteArray::number(address, 16)) : QByteArray(); } } // namespace Internal diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index 4d4ba2a9ca83a59e93b24f86c4065dd965dec886..c64473767ae19ea0df7175d818c540dd82d15c63 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -66,7 +66,8 @@ public: void setType(const QByteArray &, bool guessChildrenFromType = true); void setValueToolTip(const QString &); void setError(const QString &); - void setAddress(const QByteArray &); + void setAddress(const quint64 &); + void setHexAddress(const QByteArray &a); bool isSomethingNeeded() const { return state & NeededMask; } void setAllNeeded() { state = NeededMask; } @@ -102,6 +103,7 @@ public: bool isEqual(const WatchData &other) const; quint64 coreAddress() const; + QByteArray hexAddress() const; static QString msgNotInScope(); static QString shadowedName(const QString &name, int seen); @@ -119,7 +121,7 @@ public: QByteArray type; // Type for further processing QString displayedType;// Displayed type (optional) QByteArray variable; // Name of internal Gdb variable if created - QByteArray addr; // Displayed address + quint64 address; // Displayed address QString framekey; // Key for type cache QScriptValue scriptValue; // If needed... bool hasChildren; @@ -127,6 +129,7 @@ public: bool valueEnabled; // Value will be greyed out or not bool valueEditable; // Value will be editable bool error; + QByteArray dumperFlags; public: int source; // Originated from dumper or symbol evaluation? (CDB only) diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index c28c100956379790ebcdec01ee8cd134d845dae2..526916b24d3ff998f02f24c9509055ffc6291cf6 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -668,16 +668,14 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const case LocalsExpressionRole: { if (!data.exp.isEmpty()) return data.exp; - if (!data.addr.isEmpty() && !data.type.isEmpty()) { - bool ok; - const quint64 addr = data.addr.toULongLong(&ok, 16); - if (ok && addr) - return QString("*(%1*)%2").arg(QLatin1String(data.type)).arg(addr); + if (data.address && !data.type.isEmpty()) { + return QString::fromAscii("*(%1*)%2"). + arg(QLatin1String(data.type), QLatin1String(data.hexAddress())); } WatchItem *parent = item->parent; if (parent && !parent->exp.isEmpty()) - return QString("(%1).%2") - .arg(QString::fromLatin1(parent->exp)).arg(data.name); + return QString::fromAscii("(%1).%2") + .arg(QString::fromLatin1(parent->exp), data.name); return QVariant(); } @@ -1314,7 +1312,7 @@ static void swapEndian(char *d, int nchar) void WatchHandler::showEditValue(const WatchData &data) { - const QByteArray key = data.addr.isEmpty() ? data.iname : data.addr; + const QByteArray key = data.address ? data.hexAddress() : data.iname; QObject *w = m_editHandlers.value(key); if (data.editformat == 0x0) { m_editHandlers.remove(data.iname); @@ -1325,10 +1323,10 @@ void WatchHandler::showEditValue(const WatchData &data) if (!l) { delete w; l = new QLabel; - QString addr = tr("unknown address"); - if (!data.addr.isEmpty()) - addr = QString::fromLatin1(data.addr); - l->setWindowTitle(tr("%1 object at %2").arg(data.type, addr)); + const QString title = data.address ? + tr("%1 Object at %2").arg(QLatin1String(data.type), QLatin1String(data.hexAddress())) : + tr("%1 Object at Unknown Address").arg(QLatin1String(data.type)); + l->setWindowTitle(title); m_editHandlers[key] = l; } int width, height, format; diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 0c8f0f15eb4876cd8138a2dee28feaf7ba11c3ff..331e176604e071573086fabbdb30e126f5e127ee 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -46,7 +46,6 @@ namespace Internal { class WatchItem; class WatchHandler; -class WatchData; enum WatchType { diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index f4a1a6059d47e2ee7a8821a081bdd30081f1d2bc..1c027d0311adfaa776a2ee8c9ae41d9e93212f4a 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -1201,7 +1201,11 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, // in rare cases we need more or less: switch (td.type) { case QAbstractItemType: - inner = data.addr.mid(1); + if (data.dumperFlags.isEmpty()) { + qWarning("Internal error: empty dumper state '%s'.", data.iname.constData()); + } else { + inner = data.dumperFlags.mid(1); + } break; case QObjectSlotType: case QObjectSignalType: { @@ -1226,12 +1230,12 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, //qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype // << "QT VERSION" << m_qtVersion << ((4 << 16) + (5 << 8) + 0); extraArgs[2] = evaluationSizeofTypeExpression(nodetype, debugger); - extraArgs[3] = qMapNodeValueOffsetExpression(nodetype, data.addr, debugger); + extraArgs[3] = qMapNodeValueOffsetExpression(nodetype, data.hexAddress(), debugger); } break; case QMapNodeType: extraArgs[2] = evaluationSizeofTypeExpression(data.type, debugger); - extraArgs[3] = qMapNodeValueOffsetExpression(data.type, data.addr, debugger); + extraArgs[3] = qMapNodeValueOffsetExpression(data.type, data.hexAddress(), debugger); break; case StdVectorType: //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners; @@ -1280,7 +1284,9 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, // occasionally fails for complex types (std::string). // We need an address as CDB cannot do the 0-trick. // Use data address or try at least cache if missing. - const QByteArray address = data.addr.isEmpty() ? "DUMMY_ADDRESS" : data.addr; + const QByteArray address = data.address ? + data.hexAddress() : + "DUMMY_ADDRESS"; QByteArray offsetExpr = "(size_t)&(((" + pairType + " *)" + address + ")->second)" + '-' + address; extraArgs[2] = lookupCdbDummyAddressExpression(offsetExpr, address); @@ -1495,7 +1501,13 @@ static void gbdMiToWatchData(const GdbMi &root, w.editvalue = b; if (gdbMiGetByteArrayValue(&b, root, "exp")) w.exp = b; - gdbMiGetByteArrayValue(&w.addr, root, "addr"); + QByteArray addressBA; + gdbMiGetByteArrayValue(&addressBA, root, "addr"); + if (addressBA.startsWith("0x")) { // Item model dumper pulls tricks + w.setHexAddress(addressBA); + } else { + w.dumperFlags = addressBA; + } gdbMiGetBoolValue(&w.valueEnabled, root, "valueenabled"); gdbMiGetBoolValue(&w.valueEditable, root, "valueeditable"); if (gdbMiGetStringValue(&v, root, "valuetooltip", "valuetooltipencoded")) @@ -1622,9 +1634,13 @@ void setWatchDataAddress(WatchData &data, const GdbMi &mi) void setWatchDataAddressHelper(WatchData &data, const QByteArray &addr) { - data.addr = addr; - if (data.exp.isEmpty() && !data.addr.startsWith("$")) - data.exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.addr; + if (addr.startsWith("0x")) { // Item model dumpers pull tricks + data.setHexAddress(addr); + } else { + data.dumperFlags = addr; + } + if (data.exp.isEmpty() && !data.dumperFlags.startsWith('$')) + data.exp = "*(" + gdbQuoteTypes(data.type) + "*)" +data.hexAddress(); } // Find the "type" and "displayedtype" children of root and set up type.