From 67d391019b1b0f411f304d401e3471faafbc5b75 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 12 Apr 2011 15:56:03 +0200 Subject: [PATCH] Debugger: Have Python dumper print type size information. For memory views. In the dumper, create a cache of TypeInfo structs to contain type information and print the new entries in each call of bb(). Collect the information in the gdb engine. Replace WatchData::origAddress by WatchData::ReferencingAddress to be able to correctly handle automatically dereferenced pointers of the gdb engine. Whereas 'address' of a automatically dereferenced used to be that of the pointer, it is now that of the dereferenced item matching the size reported, enabling memory views. Referencing address is now the address of the pointer. Reviewed-by: hjk --- share/qtcreator/gdbmacros/dumper.py | 21 ++++++++++- src/plugins/debugger/gdb/classicgdbengine.cpp | 4 +-- src/plugins/debugger/gdb/gdbengine.h | 8 +++++ src/plugins/debugger/gdb/pythongdbengine.cpp | 16 +++++++++ src/plugins/debugger/watchdata.cpp | 16 ++++----- src/plugins/debugger/watchdata.h | 4 +-- src/plugins/debugger/watchhandler.cpp | 6 ++-- src/plugins/debugger/watchutils.cpp | 35 ++++++++++--------- src/plugins/debugger/watchutils.h | 2 +- 9 files changed, 79 insertions(+), 33 deletions(-) diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py index b2029125cbc..0565159b6de 100644 --- a/share/qtcreator/gdbmacros/dumper.py +++ b/share/qtcreator/gdbmacros/dumper.py @@ -103,6 +103,13 @@ def hasInferiorThreadList(): typeCache = {} +class TypeInfo: + def __init__(self, type): + self.size = type.sizeof + self.reported = False + +typeInfoCache = {} + def lookupType(typestring): type = typeCache.get(typestring) #warn("LOOKUP 1: %s -> %s" % (typestring, type)) @@ -331,8 +338,13 @@ class SubItem: #warn("TYPE VALUE: %s" % self.d.currentValue) type = stripClassTag(str(self.d.currentType)) #warn("TYPE: '%s' DEFAULT: '%s'" % (type, self.d.currentChildType)) + if len(type) > 0 and type != self.d.currentChildType: self.d.put('type="%s",' % type) # str(type.unqualified()) ? + if not type in typeInfoCache: + typeObj = lookupType(type) + if not typeObj is None: + typeInfoCache[type] = TypeInfo(typeObj) if not self.d.currentValueEncoding is None: self.d.put('valueencoded="%d",' % self.d.currentValueEncoding) if not self.d.currentValue is None: @@ -1082,7 +1094,14 @@ class FrameCommand(gdb.Command): FrameCommand() def bb(args): - return 'data=[' + Dumper(args).output + ']' + output = 'data=[' + Dumper(args).output + '],typeinfo=[' + for typeName, typeInfo in typeInfoCache.iteritems(): + if not typeInfo.reported: + output += '{name="' + base64.b64encode(typeName) + output += '",size="' + str(typeInfo.size) + '"},' + typeInfo.reported = True + output += ']'; + return output ####################################################################### diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp index 4004d7b5c52..a20221217f2 100644 --- a/src/plugins/debugger/gdb/classicgdbengine.cpp +++ b/src/plugins/debugger/gdb/classicgdbengine.cpp @@ -1367,7 +1367,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item, data.variable = name; setWatchDataType(data, item.findChild("type")); setWatchDataValue(data, item); - setWatchDataAddress(data, item.findChild("addr")); + setWatchDataAddress(data, item.findChild("addr"), GdbMi()); data.setHasChildren(false); insertData(data); } else if (parent.iname.endsWith('.')) { @@ -1391,7 +1391,7 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item, data.sortId = sortId; setWatchDataType(data, item.findChild("type")); setWatchDataValue(data, item); - setWatchDataAddress(data, item.findChild("addr")); + setWatchDataAddress(data, item.findChild("addr"), GdbMi()); setWatchDataChildCount(data, item.findChild("numchild")); if (!watchHandler()->isExpandedIName(data.iname)) data.setChildrenUnneeded(); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 3480b163a2e..ff372289f5f 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -660,6 +660,14 @@ private: ////////// View & Data Stuff ////////// void handleStackListArgumentsClassic(const GdbResponse &response); QSet m_processedNames; + struct TypeInfo + { + TypeInfo(uint s = 0) : size(s) {} + + uint size; + }; + + QHash m_typeInfoCache; // // Dumper Management diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp index 72b535d8a17..af971fad121 100644 --- a/src/plugins/debugger/gdb/pythongdbengine.cpp +++ b/src/plugins/debugger/gdb/pythongdbengine.cpp @@ -158,6 +158,22 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response) } parseWatchData(watchHandler()->expandedINames(), dummy, child, &list); } + const GdbMi typeInfo = all.findChild("typeinfo"); + if (typeInfo.type() == GdbMi::List) { + foreach (const GdbMi &s, typeInfo.children()) { + const GdbMi name = s.findChild("name"); + const GdbMi size = s.findChild("size"); + if (name.isValid() && size.isValid()) + m_typeInfoCache.insert(QByteArray::fromBase64(name.data()), + TypeInfo(size.data().toUInt())); + } + } + for (int i = 0; i != list.size(); ++i) { + const TypeInfo ti = m_typeInfoCache.value(list.at(i).type); + if (ti.size) + list[i].size = ti.size; + } + watchHandler()->insertBulkData(list); //PENDING_DEBUG("AFTER handleStackFrame()"); diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 81b7e0d49e6..d27f40ef3c3 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -125,7 +125,7 @@ WatchData::WatchData() : state(InitialState), editformat(0), address(0), - origAddress(0), + referencingAddress(0), size(0), bitpos(0), bitsize(0), @@ -305,9 +305,9 @@ QString WatchData::toString() const str << "addr=\"0x" << address << doubleQuoteComma; str.setIntegerBase(10); } - if (origAddress) { + if (referencingAddress) { str.setIntegerBase(16); - str << "origaddr=\"0x" << origAddress << doubleQuoteComma; + str << "referencingaddr=\"0x" << referencingAddress << doubleQuoteComma; str.setIntegerBase(10); } if (!exp.isEmpty()) @@ -373,9 +373,9 @@ QString WatchData::toToolTip() const formatToolTipRow(str, tr("Value"), val); formatToolTipRow(str, tr("Object Address"), QString::fromAscii(hexAddress())); - if (origAddress) - formatToolTipRow(str, tr("Original Address"), - QString::fromAscii(hexOrigAddress())); + if (referencingAddress) + formatToolTipRow(str, tr("Referencing Address"), + QString::fromAscii(hexReferencingAddress())); if (size) formatToolTipRow(str, tr("Size"), QString::number(size)); @@ -419,9 +419,9 @@ QByteArray WatchData::hexAddress() const return address ? (QByteArray("0x") + QByteArray::number(address, 16)) : QByteArray(); } -QByteArray WatchData::hexOrigAddress() const +QByteArray WatchData::hexReferencingAddress() const { - return origAddress ? (QByteArray("0x") + QByteArray::number(origAddress, 16)) : QByteArray(); + return referencingAddress ? (QByteArray("0x") + QByteArray::number(referencingAddress, 16)) : QByteArray(); } } // namespace Internal diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index d8e835fffb5..3fba8f40de2 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -113,7 +113,7 @@ public: quint64 coreAddress() const; QByteArray hexAddress() const; - QByteArray hexOrigAddress() const; + QByteArray hexReferencingAddress() const; public: quint64 id; // Token for the engine for internal mapping @@ -129,7 +129,7 @@ public: QByteArray type; // Type for further processing QString displayedType;// Displayed type (optional) quint64 address; // Displayed address - quint64 origAddress; // Original address for dereferenced pointers + quint64 referencingAddress; // Address of the pointer referencing this item (gdb auto-deref) uint size; // Size uint bitpos; // Position within bit fields uint bitsize; // Size in case of bit fields diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index fd7bd5afbb6..fa41c2e4701 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -641,9 +641,9 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const case 1: result = removeInitialNamespace(truncateValue( formattedValue(data, itemFormat(data))), ns); - if (data.origAddress) { + if (data.referencingAddress) { result += QLatin1String(" @"); - result += QString::fromLatin1(data.hexOrigAddress()); + result += QString::fromLatin1(data.hexAddress()); } break; case 2: @@ -696,7 +696,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const return m_handler->m_expandedINames.contains(data.iname); case LocalsTypeFormatListRole: { - if (data.origAddress || data.type.endsWith('*')) + if (data.referencingAddress || data.type.endsWith('*')) return QStringList() << tr("Raw pointer") << tr("Latin1 string") diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 5c74fa2c5bb..fe9b889d4b9 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -732,26 +732,31 @@ static void setWatchDataExpression(WatchData &data, const GdbMi &mi) data.exp = mi.data(); } -static void setWatchDataAddressHelper(WatchData &data, const QByteArray &addr) +static void setWatchDataAddress(WatchData &data, quint64 address , quint64 origAddress = 0) { - if (addr.startsWith("0x")) { // Item model dumpers pull tricks - data.setHexAddress(addr); + if (origAddress) { // Gdb dumpers reports the dereferenced address as origAddress + data.address = origAddress; + data.referencingAddress = address; } else { - data.dumperFlags = addr; + data.address = address; } if (data.exp.isEmpty() && !data.dumperFlags.startsWith('$')) data.exp = "*(" + gdbQuoteTypes(data.type) + "*)" +data.hexAddress(); } -void setWatchDataAddress(WatchData &data, const GdbMi &mi) +void setWatchDataAddress(WatchData &data, const GdbMi &addressMi, const GdbMi &origAddressMi) { - if (mi.isValid()) - setWatchDataAddressHelper(data, mi.data()); -} - -static void setWatchDataOrigAddress(WatchData &data, const GdbMi &mi) -{ - data.origAddress = mi.data().toULongLong(0, 16); + if (!addressMi.isValid()) + return; + const QByteArray addressBA = addressMi.data(); + if (!addressBA.startsWith("0x")) { // Item model dumpers pull tricks. + data.dumperFlags = addressBA; + return; + } + const quint64 address = addressBA.toULongLong(0, 16); + const quint64 origAddress = origAddressMi.isValid() ? + origAddressMi.data().toULongLong(0, 16) : quint64(0); + setWatchDataAddress(data, address, origAddress); } static void setWatchDataSize(WatchData &data, const GdbMi &mi) @@ -811,8 +816,7 @@ void parseWatchData(const QSet &expandedINames, data.bitsize = mi.data().toInt(); setWatchDataValue(data, item); - setWatchDataAddress(data, item.findChild("addr")); - setWatchDataOrigAddress(data, item.findChild("origaddr")); + setWatchDataAddress(data, item.findChild("addr"), item.findChild("origaddr")); setWatchDataSize(data, item.findChild("size")); setWatchDataExpression(data, item.findChild("exp")); setWatchDataValueEnabled(data, item.findChild("valueenabled")); @@ -851,8 +855,7 @@ void parseWatchData(const QSet &expandedINames, if (!data1.name.isEmpty() && data1.name.at(0).isDigit()) data1.name = _c('[') + data1.name + _c(']'); if (addressStep) { - const QByteArray addr = "0x" + QByteArray::number(addressBase, 16); - setWatchDataAddressHelper(data1, addr); + setWatchDataAddress(data1, addressBase); addressBase += addressStep; } QByteArray key = child.findChild("key").data(); diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 4e59fcc5e40..0182bbbd4c2 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -119,7 +119,7 @@ void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi, int encoding); void setWatchDataChildCount(WatchData &data, const GdbMi &mi); void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi); -void setWatchDataAddress(WatchData &data, const GdbMi &mi); +void setWatchDataAddress(WatchData &data, const GdbMi &addressMi, const GdbMi &origAddressMi); void setWatchDataType(WatchData &data, const GdbMi &mi); void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi);