diff options
author | Friedemann Kleint <[email protected]> | 2009-10-09 14:11:05 +0200 |
---|---|---|
committer | Friedemann Kleint <[email protected]> | 2009-10-09 14:11:05 +0200 |
commit | 8266c366a38279975e005355e43cdfdd2d4c1210 (patch) | |
tree | ecf3f4ee93f2133bada2d9e55cac5c2cda505138 /src/plugins/debugger/watchutils.cpp | |
parent | 9ae0575ae286ae21a58d05ce92c94f20c89fc7bb (diff) |
CDB: Make use of the improved debugger expression syntax
CDB can now handle sizeof(Class) and even expressions that
determine the offset of map node values (to some extent), may still
fail with templates). Format expressions accordingly, adapt
cached expressions.
Use gdbQuoteType depending on debugger type only.
Most important, do not evaluate each expression separately before
issuing the call, as ".call" can now do it on its own. Check for syntax
errors there and cache failing types as before.
Diffstat (limited to 'src/plugins/debugger/watchutils.cpp')
-rw-r--r-- | src/plugins/debugger/watchutils.cpp | 85 |
1 files changed, 65 insertions, 20 deletions
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 576f29811e5..c004a25652c 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -366,11 +366,11 @@ GuessChildrenResult guessChildren(const QString &type) return HasPossiblyChildren; } -QString sizeofTypeExpression(const QString &type) +QString sizeofTypeExpression(const QString &type, QtDumperHelper::Debugger debugger) { if (type.endsWith(QLatin1Char('*'))) return QLatin1String("sizeof(void*)"); - if (type.endsWith(QLatin1Char('>'))) + if (debugger != QtDumperHelper::GdbDebugger || type.endsWith(QLatin1Char('>'))) return QLatin1String("sizeof(") + type + QLatin1Char(')'); return QLatin1String("sizeof(") + gdbQuoteTypes(type) + QLatin1Char(')'); } @@ -838,7 +838,7 @@ QtDumperHelper::TypeData QtDumperHelper::typeData(const QString &typeName) const // Format an expression to have the debugger query the // size. Use size cache if possible QString QtDumperHelper::evaluationSizeofTypeExpression(const QString &typeName, - Debugger /* debugger */) const + Debugger debugger) const { // Look up special size types const SpecialSizeType st = specialSizeType(typeName); @@ -851,7 +851,7 @@ QString QtDumperHelper::evaluationSizeofTypeExpression(const QString &typeName, if (sit != m_sizeCache.constEnd()) return QString::number(sit.value()); // Finally have the debugger evaluate - return sizeofTypeExpression(typeName); + return sizeofTypeExpression(typeName, debugger); } QtDumperHelper::SpecialSizeType QtDumperHelper::specialSizeType(const QString &typeName) const @@ -962,24 +962,17 @@ 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] = QLatin1String("(size_t)&(('"); - extraArgs[3] += nodetype; - extraArgs[3] += QLatin1String("'*)0)->value"); + extraArgs[3] = qMapNodeValueOffsetExpression(nodetype, data.addr, debugger); } break; case QMapNodeType: extraArgs[2] = evaluationSizeofTypeExpression(data.type, debugger); - extraArgs[3] = QLatin1String("(size_t)&(('"); - extraArgs[3] += data.type; - extraArgs[3] += QLatin1String("'*)0)->value"); + extraArgs[3] = qMapNodeValueOffsetExpression(data.type, data.addr, debugger); break; case StdVectorType: //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners; if (inners.at(0) == QLatin1String("bool")) { outertype = QLatin1String("std::vector::bool"); - } else { - //extraArgs[extraArgCount++] = evaluationSizeofTypeExpression(data.type, debugger); - //extraArgs[extraArgCount++] = "(size_t)&(('" + data.type + "'*)0)->value"; } break; case StdDequeType: @@ -995,27 +988,40 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, extraArgs[2] = zero; break; case StdMapType: { - // We don't want the comparator and the allocator confuse gdb. - // But we need the offset of the second item in the value pair. + // We need the offset of the second item in the value pair. // We read the type of the pair from the allocator argument because - // that gets the constness "right" (in the sense that gdb can + // that gets the constness "right" (in the sense that gdb/cdb can // read it back: "std::allocator<std::pair<Key,Value> >" // -> "std::pair<Key,Value>". Different debuggers have varying // amounts of terminating blanks... + extraArgs[2].clear(); + extraArgs[3] = zero; QString pairType = inners.at(3); int bracketPos = pairType.indexOf(QLatin1Char('<')); if (bracketPos != -1) pairType.remove(0, bracketPos + 1); + // We don't want the comparator and the allocator confuse gdb. const QChar closingBracket = QLatin1Char('>'); bracketPos = pairType.lastIndexOf(closingBracket); if (bracketPos != -1) bracketPos = pairType.lastIndexOf(closingBracket, bracketPos - pairType.size() - 1); if (bracketPos != -1) pairType.truncate(bracketPos + 1); - extraArgs[2] = QLatin1String("(size_t)&(('"); - extraArgs[2] += pairType; - extraArgs[2] += QLatin1String("'*)0)->second"); - extraArgs[3] = zero; + if (debugger == GdbDebugger) { + extraArgs[2] = QLatin1String("(size_t)&(('"); + extraArgs[2] += pairType; + extraArgs[2] += QLatin1String("'*)0)->second"); + } else { + // Cdb: The std::pair is usually in scope. Still, this expression + // 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 QString address = data.addr.isEmpty() ? QString::fromLatin1("DUMMY_ADDRESS") : data.addr; + QString offsetExpr; + QTextStream str(&offsetExpr); + str << "(size_t)&(((" << pairType << " *)" << address << ")->second)" << '-' << address; + extraArgs[2] = lookupCdbDummyAddressExpression(offsetExpr, address); + } } break; case StdStringType: @@ -1068,6 +1074,45 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, qDebug() << '\n' << Q_FUNC_INFO << '\n' << data.toString() << "\n-->" << outertype << td.type << extraArgs; } +// Return debugger expression to get the offset of a map node. +QString QtDumperHelper::qMapNodeValueOffsetExpression(const QString &type, + const QString &addressIn, + Debugger debugger) const +{ + switch (debugger) { + case GdbDebugger: + return QLatin1String("(size_t)&(('") + type + QLatin1String("'*)0)->value"); + case CdbDebugger: { + // Cdb: This will only work if a QMapNode is in scope. + // We need an address as CDB cannot do the 0-trick. + // Use data address or try at least cache if missing. + const QString address = addressIn.isEmpty() ? QString::fromLatin1("DUMMY_ADDRESS") : addressIn; + QString offsetExpression; + QTextStream(&offsetExpression) << "(size_t)&(((" << type + << " *)" << address << ")->value)-" << address; + return lookupCdbDummyAddressExpression(offsetExpression, address); + } + } + return QString(); +} + +/* Cdb cannot do tricks like ( "&(std::pair<int,int>*)(0)->second)", + * that is, use a null pointer to determine the offset of a member. + * It tries to dereference the address at some point and fails with + * "memory access error". As a trick, use the address of the watch item + * to do this. However, in the expression cache, 0 is still used, so, + * for cache lookups, use '0' as address. */ +QString QtDumperHelper::lookupCdbDummyAddressExpression(const QString &expr, + const QString &address) const +{ + QString nullExpr = expr; + nullExpr.replace(address, QString(QLatin1Char('0'))); + const QString rc = m_expressionCache.value(nullExpr, expr); + if (debug) + qDebug() << "lookupCdbDummyAddressExpression" << expr << rc; + return rc; +} + // GdbMi parsing helpers for parsing dumper value results static bool gdbMiGetIntValue(int *target, |