Debugger: Sanitize Datatypes, part 3: Address of watch items.

Use a quint64 as address. Split apart special handling of
QAbstractItemModels of old shared-library based dumpers
(passing '$'+ special expression as address) into separate
dumperFlags QByteArray.
This commit is contained in:
Friedemann Kleint
2010-09-22 11:19:35 +02:00
parent 0f823e9e9e
commit b67c1a7889
8 changed files with 88 additions and 47 deletions

View File

@@ -623,7 +623,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpTypeI(const WatchData &wd, bool
*errorMessage = msgNotHandled(wd.type); *errorMessage = msgNotHandled(wd.type);
return DumpNotHandled; return DumpNotHandled;
} }
if (wd.addr.isEmpty()) { if (wd.address == 0) {
*errorMessage = QString::fromLatin1("Address is missing for '%1' (%2).") *errorMessage = QString::fromLatin1("Address is missing for '%1' (%2).")
.arg(QString::fromUtf8(wd.exp)).arg(QString::fromUtf8(wd.type)); .arg(QString::fromUtf8(wd.exp)).arg(QString::fromUtf8(wd.type));
return DumpNotHandled; return DumpNotHandled;
@@ -690,7 +690,7 @@ CdbDumperHelper::DumpExecuteResult
m_helper.evaluationParameters(wd, td, QtDumperHelper::CdbDebugger, &inBuffer, &extraParameters); m_helper.evaluationParameters(wd, td, QtDumperHelper::CdbDebugger, &inBuffer, &extraParameters);
QString callCmd; QString callCmd;
QTextStream str(&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) foreach(const QByteArray &e, extraParameters)
str << ',' << QString::fromUtf8(e); str << ',' << QString::fromUtf8(e);
str << ')'; str << ')';

View File

@@ -198,7 +198,7 @@ static inline void fixDumperResult(const WatchData &source,
it->source |= CdbSymbolGroupContext::ChildrenKnownBit; it->source |= CdbSymbolGroupContext::ChildrenKnownBit;
// Cannot dump items with missing addresses or missing types // Cannot dump items with missing addresses or missing types
const bool typeFixed = fixDumperType(&wd); // Order of evaluation! 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.setHasChildren(false);
wd.setAllUnneeded(); wd.setAllUnneeded();
} else { } else {
@@ -239,7 +239,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt
const QByteArray type = stripPointerType(wd.type); const QByteArray type = stripPointerType(wd.type);
WatchData derefedWd; WatchData derefedWd;
derefedWd.setType(type); derefedWd.setType(type);
derefedWd.setAddress(hexAddrS.toLatin1()); derefedWd.setHexAddress(hexAddrS.toAscii());
derefedWd.name = QString(QLatin1Char('*')); derefedWd.name = QString(QLatin1Char('*'));
derefedWd.iname = wd.iname + ".*"; derefedWd.iname = wd.iname + ".*";
derefedWd.source = OwnerDumper | CdbSymbolGroupContext::ChildrenKnownBit; 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, const unsigned rc = dumpValue(index, &iname, &(wd->name), &address,
&typeId, &type, &value); &typeId, &type, &value);
wd->exp = wd->iname = iname.toLatin1(); wd->exp = wd->iname = iname.toLatin1();
wd->setAddress("0x" + QByteArray::number(address, 16)); wd->setAddress(address);
wd->setType(type.toUtf8(), false); wd->setType(type.toUtf8(), false);
if (rc & OutOfScope) { if (rc & OutOfScope) {
wd->setError(WatchData::msgNotInScope()); wd->setError(WatchData::msgNotInScope());

View File

@@ -183,8 +183,8 @@ void GdbEngine::runDebuggingHelperClassic(const WatchData &data0, bool dumpChild
//int protocol = isDisplayedIName(data.iname) ? 3 : 2; //int protocol = isDisplayedIName(data.iname) ? 3 : 2;
QByteArray addr; QByteArray addr;
if (data.addr.startsWith("0x")) if (data.address)
addr = "(void*)" + data.addr; addr = "(void*)" + data.hexAddress();
else if (data.exp.isEmpty()) // happens e.g. for QAbstractItem else if (data.exp.isEmpty()) // happens e.g. for QAbstractItem
addr = QByteArray(1, '0'); addr = QByteArray(1, '0');
else else
@@ -220,8 +220,8 @@ void GdbEngine::createGdbVariableClassic(const WatchData &data)
} }
postCommand("-var-delete \"" + data.iname + '"', WatchUpdate); postCommand("-var-delete \"" + data.iname + '"', WatchUpdate);
QByteArray exp = data.exp; QByteArray exp = data.exp;
if (exp.isEmpty() && data.addr.startsWith("0x")) if (exp.isEmpty() && data.address)
exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.addr; exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress();
QVariant val = QVariant::fromValue<WatchData>(data); QVariant val = QVariant::fromValue<WatchData>(data);
postCommand("-var-create \"" + data.iname + "\" * \"" + exp + '"', postCommand("-var-create \"" + data.iname + "\" * \"" + exp + '"',
WatchUpdate, CB(handleVarCreate), val); WatchUpdate, CB(handleVarCreate), val);
@@ -474,8 +474,13 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response)
data1.name = _("[%1]").arg(i); data1.name = _("[%1]").arg(i);
data1.type = data.type.left(data.type.size() - 4); data1.type = data.type.left(data.type.size() - 4);
data1.iname = data.iname + '.' + QByteArray::number(i); data1.iname = data.iname + '.' + QByteArray::number(i);
data1.addr = list.at(i); const QByteArray &addressSpec = list.at(i);
data1.exp = "((" + gdbQuoteTypes(data1.type) + "*)" + data1.addr + ')'; 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.setHasChildren(false);
data1.setValueNeeded(); data1.setValueNeeded();
QByteArray cmd = "qdumpqstring (" + data1.exp + ')'; QByteArray cmd = "qdumpqstring (" + data1.exp + ')';

View File

@@ -19,6 +19,7 @@ namespace Internal {
WatchData::WatchData() : WatchData::WatchData() :
editformat(0), editformat(0),
address(0),
hasChildren(false), hasChildren(false),
generation(-1), generation(-1),
valueEnabled(true), valueEnabled(true),
@@ -42,7 +43,7 @@ bool WatchData::isEqual(const WatchData &other) const
&& type == other.type && type == other.type
&& displayedType == other.displayedType && displayedType == other.displayedType
&& variable == other.variable && variable == other.variable
&& addr == other.addr && address == other.address
&& framekey == other.framekey && framekey == other.framekey
&& hasChildren == other.hasChildren && hasChildren == other.hasChildren
&& valueEnabled == other.valueEnabled && 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 QString WatchData::toString() const
@@ -162,8 +176,11 @@ QString WatchData::toString() const
str << "name=\"" << name << doubleQuoteComma; str << "name=\"" << name << doubleQuoteComma;
if (error) if (error)
str << "error,"; str << "error,";
if (!addr.isEmpty()) if (address) {
str << "addr=\"" << addr << doubleQuoteComma; str.setIntegerBase(16);
str << "addr=\"0x" << address << doubleQuoteComma;
str.setIntegerBase(10);
}
if (!exp.isEmpty()) if (!exp.isEmpty())
str << "exp=\"" << exp << doubleQuoteComma; str << "exp=\"" << exp << doubleQuoteComma;
@@ -179,6 +196,9 @@ QString WatchData::toString() const
str << "editvalue=\"<...>\","; str << "editvalue=\"<...>\",";
// str << "editvalue=\"" << editvalue << doubleQuoteComma; // str << "editvalue=\"" << editvalue << doubleQuoteComma;
if (!dumperFlags.isEmpty())
str << "dumperFlags=\"" << dumperFlags << doubleQuoteComma;
if (isTypeNeeded()) if (isTypeNeeded())
str << "type=<needed>,"; str << "type=<needed>,";
if (isTypeKnown() && !type.isEmpty()) if (isTypeKnown() && !type.isEmpty())
@@ -234,7 +254,8 @@ QString WatchData::toToolTip() const
val += QCoreApplication::translate("Debugger::Internal::WatchHandler", " ... <cut off>"); val += QCoreApplication::translate("Debugger::Internal::WatchHandler", " ... <cut off>");
} }
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Value"), val); 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", "Internal ID"), iname);
formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Generation"), formatToolTipRow(str, QCoreApplication::translate("Debugger::Internal::WatchHandler", "Generation"),
QString::number(generation)); QString::number(generation));
@@ -267,13 +288,12 @@ QString WatchData::shadowedName(const QString &name, int seen)
quint64 WatchData::coreAddress() const quint64 WatchData::coreAddress() const
{ {
if (!addr.isEmpty()) {
bool ok;
const quint64 address = addr.toULongLong(&ok, 16);
if (ok)
return address; return address;
} }
return quint64(0);
QByteArray WatchData::hexAddress() const
{
return address ? (QByteArray("0x") + QByteArray::number(address, 16)) : QByteArray();
} }
} // namespace Internal } // namespace Internal

View File

@@ -66,7 +66,8 @@ public:
void setType(const QByteArray &, bool guessChildrenFromType = true); void setType(const QByteArray &, bool guessChildrenFromType = true);
void setValueToolTip(const QString &); void setValueToolTip(const QString &);
void setError(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; } bool isSomethingNeeded() const { return state & NeededMask; }
void setAllNeeded() { state = NeededMask; } void setAllNeeded() { state = NeededMask; }
@@ -102,6 +103,7 @@ public:
bool isEqual(const WatchData &other) const; bool isEqual(const WatchData &other) const;
quint64 coreAddress() const; quint64 coreAddress() const;
QByteArray hexAddress() const;
static QString msgNotInScope(); static QString msgNotInScope();
static QString shadowedName(const QString &name, int seen); static QString shadowedName(const QString &name, int seen);
@@ -119,7 +121,7 @@ public:
QByteArray type; // Type for further processing QByteArray type; // Type for further processing
QString displayedType;// Displayed type (optional) QString displayedType;// Displayed type (optional)
QByteArray variable; // Name of internal Gdb variable if created QByteArray variable; // Name of internal Gdb variable if created
QByteArray addr; // Displayed address quint64 address; // Displayed address
QString framekey; // Key for type cache QString framekey; // Key for type cache
QScriptValue scriptValue; // If needed... QScriptValue scriptValue; // If needed...
bool hasChildren; bool hasChildren;
@@ -127,6 +129,7 @@ public:
bool valueEnabled; // Value will be greyed out or not bool valueEnabled; // Value will be greyed out or not
bool valueEditable; // Value will be editable bool valueEditable; // Value will be editable
bool error; bool error;
QByteArray dumperFlags;
public: public:
int source; // Originated from dumper or symbol evaluation? (CDB only) int source; // Originated from dumper or symbol evaluation? (CDB only)

View File

@@ -668,16 +668,14 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
case LocalsExpressionRole: { case LocalsExpressionRole: {
if (!data.exp.isEmpty()) if (!data.exp.isEmpty())
return data.exp; return data.exp;
if (!data.addr.isEmpty() && !data.type.isEmpty()) { if (data.address && !data.type.isEmpty()) {
bool ok; return QString::fromAscii("*(%1*)%2").
const quint64 addr = data.addr.toULongLong(&ok, 16); arg(QLatin1String(data.type), QLatin1String(data.hexAddress()));
if (ok && addr)
return QString("*(%1*)%2").arg(QLatin1String(data.type)).arg(addr);
} }
WatchItem *parent = item->parent; WatchItem *parent = item->parent;
if (parent && !parent->exp.isEmpty()) if (parent && !parent->exp.isEmpty())
return QString("(%1).%2") return QString::fromAscii("(%1).%2")
.arg(QString::fromLatin1(parent->exp)).arg(data.name); .arg(QString::fromLatin1(parent->exp), data.name);
return QVariant(); return QVariant();
} }
@@ -1314,7 +1312,7 @@ static void swapEndian(char *d, int nchar)
void WatchHandler::showEditValue(const WatchData &data) 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); QObject *w = m_editHandlers.value(key);
if (data.editformat == 0x0) { if (data.editformat == 0x0) {
m_editHandlers.remove(data.iname); m_editHandlers.remove(data.iname);
@@ -1325,10 +1323,10 @@ void WatchHandler::showEditValue(const WatchData &data)
if (!l) { if (!l) {
delete w; delete w;
l = new QLabel; l = new QLabel;
QString addr = tr("unknown address"); const QString title = data.address ?
if (!data.addr.isEmpty()) tr("%1 Object at %2").arg(QLatin1String(data.type), QLatin1String(data.hexAddress())) :
addr = QString::fromLatin1(data.addr); tr("%1 Object at Unknown Address").arg(QLatin1String(data.type));
l->setWindowTitle(tr("%1 object at %2").arg(data.type, addr)); l->setWindowTitle(title);
m_editHandlers[key] = l; m_editHandlers[key] = l;
} }
int width, height, format; int width, height, format;

View File

@@ -46,7 +46,6 @@ namespace Internal {
class WatchItem; class WatchItem;
class WatchHandler; class WatchHandler;
class WatchData;
enum WatchType enum WatchType
{ {

View File

@@ -1201,7 +1201,11 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
// in rare cases we need more or less: // in rare cases we need more or less:
switch (td.type) { switch (td.type) {
case QAbstractItemType: 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; break;
case QObjectSlotType: case QObjectSlotType:
case QObjectSignalType: { case QObjectSignalType: {
@@ -1226,12 +1230,12 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
//qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype //qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype
// << "QT VERSION" << m_qtVersion << ((4 << 16) + (5 << 8) + 0); // << "QT VERSION" << m_qtVersion << ((4 << 16) + (5 << 8) + 0);
extraArgs[2] = evaluationSizeofTypeExpression(nodetype, debugger); extraArgs[2] = evaluationSizeofTypeExpression(nodetype, debugger);
extraArgs[3] = qMapNodeValueOffsetExpression(nodetype, data.addr, debugger); extraArgs[3] = qMapNodeValueOffsetExpression(nodetype, data.hexAddress(), debugger);
} }
break; break;
case QMapNodeType: case QMapNodeType:
extraArgs[2] = evaluationSizeofTypeExpression(data.type, debugger); extraArgs[2] = evaluationSizeofTypeExpression(data.type, debugger);
extraArgs[3] = qMapNodeValueOffsetExpression(data.type, data.addr, debugger); extraArgs[3] = qMapNodeValueOffsetExpression(data.type, data.hexAddress(), debugger);
break; break;
case StdVectorType: case StdVectorType:
//qDebug() << "EXTRACT TEMPLATE: " << outertype << inners; //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
@@ -1280,7 +1284,9 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
// occasionally fails for complex types (std::string). // occasionally fails for complex types (std::string).
// We need an address as CDB cannot do the 0-trick. // We need an address as CDB cannot do the 0-trick.
// Use data address or try at least cache if missing. // 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 QByteArray offsetExpr = "(size_t)&(((" + pairType + " *)" + address
+ ")->second)" + '-' + address; + ")->second)" + '-' + address;
extraArgs[2] = lookupCdbDummyAddressExpression(offsetExpr, address); extraArgs[2] = lookupCdbDummyAddressExpression(offsetExpr, address);
@@ -1495,7 +1501,13 @@ static void gbdMiToWatchData(const GdbMi &root,
w.editvalue = b; w.editvalue = b;
if (gdbMiGetByteArrayValue(&b, root, "exp")) if (gdbMiGetByteArrayValue(&b, root, "exp"))
w.exp = b; 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.valueEnabled, root, "valueenabled");
gdbMiGetBoolValue(&w.valueEditable, root, "valueeditable"); gdbMiGetBoolValue(&w.valueEditable, root, "valueeditable");
if (gdbMiGetStringValue(&v, root, "valuetooltip", "valuetooltipencoded")) if (gdbMiGetStringValue(&v, root, "valuetooltip", "valuetooltipencoded"))
@@ -1622,9 +1634,13 @@ void setWatchDataAddress(WatchData &data, const GdbMi &mi)
void setWatchDataAddressHelper(WatchData &data, const QByteArray &addr) void setWatchDataAddressHelper(WatchData &data, const QByteArray &addr)
{ {
data.addr = addr; if (addr.startsWith("0x")) { // Item model dumpers pull tricks
if (data.exp.isEmpty() && !data.addr.startsWith("$")) data.setHexAddress(addr);
data.exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.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. // Find the "type" and "displayedtype" children of root and set up type.