diff --git a/src/libs/qtcreatorcdbext/containers.cpp b/src/libs/qtcreatorcdbext/containers.cpp index a59bdf52c47e0a2fdaa75fce01b8732e63664189..9e28cf0aa4566ed628a25fa810762450870fbbbf 100644 --- a/src/libs/qtcreatorcdbext/containers.cpp +++ b/src/libs/qtcreatorcdbext/containers.cpp @@ -43,6 +43,8 @@ typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbol typedef std::vector<SymbolGroupValue> SymbolGroupValueVector; typedef std::vector<int>::size_type VectorIndexType; +enum { debugVector = 0 }; + // Read a pointer array from debuggee memory (ULONG64/32 according pointer size) static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx) { @@ -76,6 +78,18 @@ static inline void dump64bitPointerArray(std::ostream &os, const void *a, int co dumpHexArray(os, reinterpret_cast<const ULONG64 *>(a), count); } +// Fix the inner type of containers (that is, make it work smoothly with AddSymbol) +// by prefixing it with the module except for well-known types like STL/Qt types +static inline std::string fixInnerType(std::string type, const SymbolGroupValueContext &ctx) +{ + const std::string stripped = SymbolGroupValue::stripClassPrefixes(type); + const KnownType kt = knownType(stripped, false); + // Simple types and STL/Q-types (inexplicably) are fast. + if (kt & (KT_POD_Type|KT_Qt_Type|KT_STL_Type)) + return stripped; + return SymbolGroupValue::resolveType(stripped, ctx); +} + // Return size from an STL vector (last/first iterators). static inline int msvcStdVectorSize(const SymbolGroupValue &v) { @@ -89,7 +103,7 @@ static inline int msvcStdVectorSize(const SymbolGroupValue &v) return 0; // Subtract the pointers: We need to do the pointer arithmetics ourselves // as we get char *pointers. - const std::string innerType = SymbolGroupValue::stripPointerType(myFirstPtrV.type()); + const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v.context()); const size_t size = SymbolGroupValue::sizeOf(innerType.c_str()); if (size == 0) return -1; @@ -324,10 +338,15 @@ static inline AbstractSymbolGroupNodePtrVector SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010 if (!myFirst) myFirst = vec["_Myfirst"]; // MSVC2008 - if (myFirst) - if (const ULONG64 address = myFirst.pointerValue()) - return arrayChildList(n->symbolGroup(), address, - SymbolGroupValue::stripPointerType(myFirst.type()), count); + if (myFirst) { + if (const ULONG64 address = myFirst.pointerValue()) { + const std::string firstType = myFirst.type(); + const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), ctx); + if (debugVector) + DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\''; + return arrayChildList(n->symbolGroup(), address, innerType, count); + } + } } return AbstractSymbolGroupNodePtrVector(); } @@ -620,9 +639,12 @@ static inline AbstractSymbolGroupNodePtrVector // QVector<T>: p/array is declared as array of T. Dereference first // element to obtain address. const SymbolGroupValue vec(n, ctx); - if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) - if (const ULONG64 arrayAddress = firstElementV.address()) - return arrayChildList(n->symbolGroup(), arrayAddress, firstElementV.type(), count); + if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) { + if (const ULONG64 arrayAddress = firstElementV.address()) { + const std::string fixedInnerType = fixInnerType(firstElementV.type(), ctx); + return arrayChildList(n->symbolGroup(), arrayAddress, fixedInnerType, count); + } + } } return AbstractSymbolGroupNodePtrVector(); } @@ -663,7 +685,7 @@ static inline AbstractSymbolGroupNodePtrVector const std::vector<std::string> innerTypes = v.innerTypes(); if (innerTypes.size() != 1) return AbstractSymbolGroupNodePtrVector(); - const std::string &innerType = innerTypes.front(); + const std::string innerType = fixInnerType(innerTypes.front(), v.context()); const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str()); if (!innerTypeSize) return AbstractSymbolGroupNodePtrVector(); diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h index f88ad6074810b6f4c7891514dc3d308a84e6f9dc..ebabf902cacaa132574c49338f6fff6ab2a072ba 100644 --- a/src/libs/qtcreatorcdbext/knowntype.h +++ b/src/libs/qtcreatorcdbext/knowntype.h @@ -38,12 +38,19 @@ enum KnownType { KT_Unknown =0, - KT_Qt_Type = 0x10000, - KT_Qt_PrimitiveType = 0x20000, - KT_Qt_MovableType = 0x40000, - KT_STL_Type = 0x80000, - KT_ContainerType = 0x100000, - KT_HasSimpleDumper = 0x200000, + KT_POD_Type = 0x10000, + KT_Qt_Type = 0x20000, + KT_Qt_PrimitiveType = 0x40000, + KT_Qt_MovableType = 0x80000, + KT_STL_Type = 0x100000, + KT_ContainerType = 0x200000, + KT_HasSimpleDumper = 0x400000, + // PODs + KT_Char = KT_POD_Type + 1, + KT_UnsignedChar = KT_POD_Type + 2, + KT_IntType = KT_POD_Type + 3, // any signed short, long, int + KT_UnsignedIntType = KT_POD_Type + 4, // any unsigned int + KT_FloatType = KT_POD_Type + 5, // float, double // Qt Basic KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1, KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2, @@ -156,7 +163,7 @@ enum KnownType KT_StdDeque = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 4, KT_StdSet = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 5, KT_StdMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 6, - KT_StdMultiMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 7, + KT_StdMultiMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 7 }; #endif // KNOWNTYPE_H diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 1ce1899cbc682f5116a3c95a8cac2c8840a3b65c..73e6f5c94e7eda28969dcafe20ec6b84cf98a451 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -252,7 +252,7 @@ std::string SymbolGroupValue::error() const bool SymbolGroupValue::isPointerType(const std::string &t) { - return endsWith(t, " *"); + return endsWith(t, '*'); } unsigned SymbolGroupValue::pointerSize() @@ -277,7 +277,25 @@ unsigned SymbolGroupValue::fieldOffset(const char *type, const char *field) std::string SymbolGroupValue::stripPointerType(const std::string &t) { - return isPointerType(t) ? t.substr(0, t.size() - 2) : t; + // 'Foo *' -> 'Foo', 'Bar **' -> 'Bar *'. + if (endsWith(t, "**")) + return t.substr(0, t.size() - 1); + if (endsWith(t, " *")) + return t.substr(0, t.size() - 2); + return t; +} + +// Strip "class Foo", "struct Bar"-> "Foo", "Bar " +std::string SymbolGroupValue::stripClassPrefixes(const std::string &type) +{ + std::string rc = type; + if (rc.compare(0, 6, "class ") == 0) { + rc.erase(0, 6); + } else { + if (rc.compare(0, 7, "struct ") == 0) + rc.erase(0, 7); + } + return rc; } std::string SymbolGroupValue::addPointerType(const std::string &t) @@ -371,13 +389,7 @@ std::string QtInfo::prependModuleAndNameSpace(const std::string &type, const std::string &aNameSpace) { // Strip the prefixes "class ", "struct ". - std::string rc = type; - if (rc.compare(0, 6, "class ") == 0) { - rc.erase(0, 6); - } else { - if (rc.compare(0, 7, "struct ") == 0) - rc.erase(0, 7); - } + std::string rc = SymbolGroupValue::stripClassPrefixes(type); // Is the namespace 'nsp::' missing? if (!aNameSpace.empty()) { const bool nameSpaceMissing = rc.size() <= aNameSpace.size() @@ -440,6 +452,42 @@ std::list<std::string> return rc; } +// Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString') +std::string SymbolGroupValue::resolveType(const std::string &type, const SymbolGroupValueContext &ctx) +{ + enum { BufSize = 512 }; + + if (type.empty() || type.find('!') != std::string::npos) + return type; + + const std::string stripped = SymbolGroupValue::stripClassPrefixes(type); + + // Obtain the base address of the module using an obscure ioctl() call. + // See inline implementation of GetTypeSize() and docs. + SYM_DUMP_PARAM symParameters = { sizeof (SYM_DUMP_PARAM), (PUCHAR)stripped.c_str(), DBG_DUMP_NO_PRINT, 0, + NULL, NULL, NULL, 0, NULL }; + const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size); + if (!typeSize || !symParameters.ModBase) // Failed? + return type; + ULONG index = 0; + ULONG64 base = 0; + // Convert module base address to module index + HRESULT hr = ctx.symbols->GetModuleByOffset(symParameters.ModBase, 0, &index, &base); + if (FAILED(hr)) + return type; + // Obtain module name + char buf[BufSize]; + buf[0] = '\0'; + hr = ctx.symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index, base, buf, BufSize, 0); + if (FAILED(hr)) + return type; + + std::string rc = buf; + rc.push_back('!'); + rc += type; + return rc; +} + // get the inner types: "QMap<int, double>" -> "int", "double" std::vector<std::string> SymbolGroupValue::innerTypesOf(const std::string &t) { @@ -567,8 +615,45 @@ static inline void formatMilliSeconds(std::wostream &str, int milliSecs) static const char stdStringTypeC[] = "std::basic_string<char,std::char_traits<char>,std::allocator<char> >"; static const char stdWStringTypeC[] = "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >"; +static KnownType knownPODTypeHelper(const std::string &type) +{ + if (type.empty()) + return KT_Unknown; + switch (type.at(0)) { + case 'c': + if (type == "char") + return KT_Char; + break; + case 'd': + if (type == "double") + return KT_FloatType; + break; + case 'f': + if (type == "float") + return KT_FloatType; + break; + case 'l': + if (!type.compare(0, 4, "long")) + return KT_IntType; + break; + case 'i': + if (!type.compare(0, 3, "int")) + return KT_IntType; + break; + case 's': + if (!type.compare(0, 5, "short")) + return KT_IntType; + break; + case 'u': + if (!type.compare(0, 8, "unsigned")) + return type == "unsigned char" ? KT_UnsignedChar : KT_UnsignedIntType; + break; + } + return KT_Unknown; +} + // Determine type starting from a position (with/without 'class '/'struct ' prefix). -static KnownType knownTypeHelper(const std::string &type, std::string::size_type pos) +static KnownType knownClassTypeHelper(const std::string &type, std::string::size_type pos) { // Strip pointer types. const std::wstring::size_type compareLen = @@ -901,20 +986,23 @@ KnownType knownType(const std::string &type, bool hasClassPrefix) { if (type.empty()) return KT_Unknown; + const KnownType podType = knownPODTypeHelper(type); + if (podType != KT_Unknown) + return podType; if (hasClassPrefix) { switch (type.at(0)) { // Check 'class X' or 'struct X' case 'c': if (!type.compare(0, 6, "class ")) - return knownTypeHelper(type, 6); + return knownClassTypeHelper(type, 6); break; case 's': if (!type.compare(0, 7, "struct ")) - return knownTypeHelper(type, 7); + return knownClassTypeHelper(type, 7); break; } } else { // No prefix, full check - return knownTypeHelper(type, 0); + return knownClassTypeHelper(type, 0); } return KT_Unknown; } diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index 4c3cd00ab808679e6d69a57fd3badc4cedcef883..9a0ea67536f5affab4886a87c541e7fa6ccdb80c 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -101,9 +101,15 @@ public: // Offset of structure field: "!moduleQMapNode<K,T>", "value". static unsigned fieldOffset(const char *type, const char *field); static std::string stripPointerType(const std::string &); + // Strip "class ", "struct " + static std::string stripClassPrefixes(const std::string &); static std::string addPointerType(const std::string &); static std::string stripArrayType(const std::string &); static bool isPointerType(const std::string &); + // Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString') + // Some operations on types (like adding symbols may fail non-deterministically + // or be slow when the module specification is omitted). + static std::string resolveType(const std::string &type, const SymbolGroupValueContext &ctx); static std::list<std::string> resolveSymbol(const char *pattern, const SymbolGroupValueContext &c, std::string *errorMessage = 0);