forked from qt-creator/qt-creator
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:
@@ -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);
|
||||
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user