Commit b67c1a78 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

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.
parent 0f823e9e
......@@ -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 << ')';
......
......@@ -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());
......
......@@ -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 + ')';
......
......@@ -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
......
......@@ -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)
......
......@@ -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;
......
......@@ -46,7 +46,6 @@ namespace Internal {
class WatchItem;
class WatchHandler;
class WatchData;
enum WatchType
{
......
......@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment