forked from qt-creator/qt-creator
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
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
@@ -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();
|
||||
|
@@ -660,6 +660,14 @@ private: ////////// View & Data Stuff //////////
|
||||
void handleStackListArgumentsClassic(const GdbResponse &response);
|
||||
|
||||
QSet<QByteArray> m_processedNames;
|
||||
struct TypeInfo
|
||||
{
|
||||
TypeInfo(uint s = 0) : size(s) {}
|
||||
|
||||
uint size;
|
||||
};
|
||||
|
||||
QHash<QByteArray, TypeInfo> m_typeInfoCache;
|
||||
|
||||
//
|
||||
// Dumper Management
|
||||
|
@@ -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()");
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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")
|
||||
|
@@ -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());
|
||||
if (!addressMi.isValid())
|
||||
return;
|
||||
const QByteArray addressBA = addressMi.data();
|
||||
if (!addressBA.startsWith("0x")) { // Item model dumpers pull tricks.
|
||||
data.dumperFlags = addressBA;
|
||||
return;
|
||||
}
|
||||
|
||||
static void setWatchDataOrigAddress(WatchData &data, const GdbMi &mi)
|
||||
{
|
||||
data.origAddress = mi.data().toULongLong(0, 16);
|
||||
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<QByteArray> &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<QByteArray> &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();
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user