diff --git a/src/libs/qtcreatorcdbext/containers.cpp b/src/libs/qtcreatorcdbext/containers.cpp index 63f8d2ce545..ee9821f2348 100644 --- a/src/libs/qtcreatorcdbext/containers.cpp +++ b/src/libs/qtcreatorcdbext/containers.cpp @@ -43,8 +43,6 @@ typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbol typedef std::vector SymbolGroupValueVector; typedef std::vector::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) { @@ -80,14 +78,23 @@ static inline void dump64bitPointerArray(std::ostream &os, const void *a, int co // 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) +static inline std::string fixInnerType(std::string type, + const SymbolGroupValue &container) { 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); + const KnownType kt = knownType(stripped, 0); + // Resolve types unless they are POD or pointers to POD (that is, qualify 'Foo' and 'Foo*') + const bool needResolve = kt == KT_Unknown || kt == KT_PointerType || !(kt & KT_POD_Type); + const std::string fixed = needResolve ? + SymbolGroupValue::resolveType(stripped, container.context(), container.node()->symbolGroup()) : + stripped; + if (SymbolGroupValue::verbose) { + DebugPrint dp; + dp << "fixInnerType (resolved=" << needResolve << ") '" << type << "' ["; + formatKnownTypeFlags(dp, kt); + dp << "] -> '" << fixed <<"'\n"; + } + return fixed; } // Return size from an STL vector (last/first iterators). @@ -103,7 +110,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 = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v.context()); + const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v); const size_t size = SymbolGroupValue::sizeOf(innerType.c_str()); if (size == 0) return -1; @@ -249,10 +256,15 @@ private: static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx) { - if (count) - if (const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"]) - return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next")); - return AbstractSymbolGroupNodePtrVector(); + if (!count) + return AbstractSymbolGroupNodePtrVector(); + const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"]; + if (!head) { + if (SymbolGroupValue::verbose) + DebugPrint() << "std::list failure: " << head; + return AbstractSymbolGroupNodePtrVector(); + } + return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next")); } // QLinkedList: Dummy head node and then a linked list of "n", "t". @@ -294,9 +306,14 @@ AbstractSymbolGroupNodePtrVector arrayChildList(SymbolGroup *sg, AddressFunc add if (SymbolGroupNode *child = sg->addSymbol(name, std::string(), &errorMessage)) { rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, child)); } else { + if (SymbolGroupValue::verbose) + DebugPrint() << "addSymbol fails in arrayChildList"; break; } } + if (SymbolGroupValue::verbose) + DebugPrint() << "arrayChildList '" << innerType << "' count=" << count << " returns " + << rc.size() << " elements"; return rc; } @@ -341,8 +358,8 @@ static inline AbstractSymbolGroupNodePtrVector 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) + const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), vec); + if (SymbolGroupValue::verbose) DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\''; return arrayChildList(n->symbolGroup(), address, innerType, count); } @@ -396,9 +413,10 @@ static inline AbstractSymbolGroupNodePtrVector const std::vector innerTypes = deque.innerTypes(); if (innerTypes.empty()) return AbstractSymbolGroupNodePtrVector(); + const std::string innerType = fixInnerType(innerTypes.front(), deque); // Get the deque size (block size) which is an unavailable static member // (cf for the actual expression). - const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerTypes.front().c_str()); + const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str()); if (!innerTypeSize) return AbstractSymbolGroupNodePtrVector(); const int dequeSize = innerTypeSize <= 1 ? 16 : innerTypeSize <= 2 ? @@ -410,10 +428,10 @@ static inline AbstractSymbolGroupNodePtrVector const AbstractSymbolGroupNodePtrVector rc = SymbolGroupValue::pointerSize() == 8 ? stdDequeChildrenHelper(deque.node()->symbolGroup(), reinterpret_cast(mapArray), mapSize, - innerTypes.front(), innerTypeSize, startOffset, dequeSize, count) : + innerType, innerTypeSize, startOffset, dequeSize, count) : stdDequeChildrenHelper(deque.node()->symbolGroup(), reinterpret_cast(mapArray), mapSize, - innerTypes.front(), innerTypeSize, startOffset, dequeSize, count); + innerType, innerTypeSize, startOffset, dequeSize, count); delete [] mapArray; return rc; } @@ -641,7 +659,7 @@ static inline AbstractSymbolGroupNodePtrVector const SymbolGroupValue vec(n, ctx); if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) { if (const ULONG64 arrayAddress = firstElementV.address()) { - const std::string fixedInnerType = fixInnerType(firstElementV.type(), ctx); + const std::string fixedInnerType = fixInnerType(firstElementV.type(), vec); return arrayChildList(n->symbolGroup(), arrayAddress, fixedInnerType, count); } } @@ -685,9 +703,9 @@ static inline AbstractSymbolGroupNodePtrVector const std::vector innerTypes = v.innerTypes(); if (innerTypes.size() != 1) return AbstractSymbolGroupNodePtrVector(); - const std::string innerType = fixInnerType(innerTypes.front(), v.context()); + const std::string innerType = fixInnerType(innerTypes.front(), v); const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str()); - if (debugVector) + if (SymbolGroupValue::verbose) DebugPrint() << "QList " << v.name() << " inner type " << innerType << ' ' << innerTypeSize; if (!innerTypeSize) return AbstractSymbolGroupNodePtrVector(); @@ -711,7 +729,7 @@ static inline AbstractSymbolGroupNodePtrVector if (kt != KT_Unknown && !(kt & (KT_POD_Type|KT_Qt_PrimitiveType|KT_Qt_MovableType))) isLargeOrStatic = true; } - if (debugVector) + if (SymbolGroupValue::verbose) DebugPrint() << "isLargeOrStatic " << isLargeOrStatic; if (isLargeOrStatic) { // Retrieve the pointer array ourselves to avoid having to evaluate '*(class foo**)' @@ -776,8 +794,6 @@ static inline std::string qHashNodeType(const SymbolGroupValue &v, return QtInfo::prependModuleAndNameSpace(qHashType, currentModule, qtInfo.nameSpace); } -enum { debugMap = 0 }; - // Return up to count nodes of type "QHashNode" of a "class QHash". SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v, VectorIndexType count) @@ -787,7 +803,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v, const SymbolGroupValue hashData = v["d"]; // 'e' is used as a special value to indicate empty hash buckets in the array. const ULONG64 ePtr = v["e"].pointerValue(); - if (debugMap) + if (SymbolGroupValue::verbose) DebugPrint() << v << " Count=" << count << ",ePtr=0x" << std::hex << ePtr; if (!hashData || !ePtr) return SymbolGroupValueVector(); @@ -825,7 +841,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v, dummyNodeList.push_back(next); if (dummyNodeList.size() >= count) // Stop at maximum count notEnough = false; - if (debugMap) + if (SymbolGroupValue::verbose > 1) DebugPrint() << '#' << (dummyNodeList.size() - 1) << " l=" << l << ",next=" << next; l = next; } else { @@ -835,7 +851,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v, } // Finally convert them into real nodes 'QHashNode (potentially expensive) const std::string nodeType = qHashNodeType(v, "Node"); - if (debugMap) + if (SymbolGroupValue::verbose) DebugPrint() << "Converting into " << nodeType; SymbolGroupValueVector nodeList; nodeList.reserve(count); @@ -901,11 +917,11 @@ static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, Vector { const SymbolGroupValue e = v["e"]; const ULONG64 ePtr = e.pointerValue(); - if (debugMap) + if (SymbolGroupValue::verbose) DebugPrint() << v.type() << " E=0x" << std::hex << ePtr; if (!ePtr) return SymbolGroupValueVector(); - if (debugMap) + if (SymbolGroupValue::verbose) DebugPrint() << v.type() << " E=0x" << std::hex << ePtr; SymbolGroupValueVector rc; rc.reserve(count); @@ -921,7 +937,7 @@ static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, Vector static inline AbstractSymbolGroupNodePtrVector qMapChildList(const SymbolGroupValue &v, VectorIndexType count) { - if (debugMap) + if (SymbolGroupValue::verbose) DebugPrint() << v.type() << "," << count; if (!count) @@ -933,7 +949,7 @@ static inline AbstractSymbolGroupNodePtrVector const std::string mapPayloadNodeType = qHashNodeType(v, "PayloadNode"); // Calculate the offset needed (see QMap::concrete() used by the iterator). const unsigned payloadNodeSize = SymbolGroupValue::sizeOf(mapPayloadNodeType.c_str()); - if (debugMap) { + if (SymbolGroupValue::verbose) { DebugPrint() << v.type() << "," << mapNodeType << ':' << mapPayloadNodeType << ':' << payloadNodeSize << ", pointerSize=" << SymbolGroupValue::pointerSize(); @@ -947,16 +963,18 @@ static inline AbstractSymbolGroupNodePtrVector const std::vector innerTypes = v.innerTypes(); if (innerTypes.size() != 2u) return AbstractSymbolGroupNodePtrVector(); - const unsigned valueSize = SymbolGroupValue::sizeOf(innerTypes.at(1).c_str()); + const std::string keyType = fixInnerType(innerTypes.front(), v); + const std::string valueType = fixInnerType(innerTypes.at(1), v); + const unsigned valueSize = SymbolGroupValue::sizeOf(valueType.c_str()); const unsigned valueOffset = SymbolGroupValue::fieldOffset(mapNodeType.c_str(), "value"); - if (debugMap) + if (SymbolGroupValue::verbose) DebugPrint() << "Payload=" << payLoad << ",valueOffset=" << valueOffset << ',' << innerTypes.front() << ',' << innerTypes.back() << ':' << valueSize; if (!valueOffset || !valueSize) return AbstractSymbolGroupNodePtrVector(); // Get the children. const SymbolGroupValueVector childNodes = qMapNodes(v, count); - if (debugMap) + if (SymbolGroupValue::verbose) DebugPrint() << "children: " << childNodes.size() << " of " << count; // Deep expansion of the forward[0] sometimes fails. In that case, // take what we can get. @@ -971,15 +989,14 @@ static inline AbstractSymbolGroupNodePtrVector rc.reserve(count); std::string errorMessage; SymbolGroup *sg = v.node()->symbolGroup(); - for (VectorIndexType i = 0; i < count ; i++) { const ULONG64 nodePtr = childNodes.at(i).pointerValue(); if (!nodePtr) return AbstractSymbolGroupNodePtrVector(); const ULONG64 keyAddress = nodePtr - payLoad; - const std::string keyExp = pointedToSymbolName(keyAddress, innerTypes.front()); - const std::string valueExp = pointedToSymbolName(keyAddress + valueOffset, innerTypes.at(1)); - if (debugMap) { + const std::string keyExp = pointedToSymbolName(keyAddress, keyType); + const std::string valueExp = pointedToSymbolName(keyAddress + valueOffset, valueType); + if (SymbolGroupValue::verbose) { DebugPrint() << '#' << i << '/' << count << ' ' << std::hex << ",node=0x" << nodePtr << ',' <name() << '/' << node->iName() << '/' << node->type() + << " at 0x" << std::hex << node->address() << std::dec + << " count=" << size << ",knowntype=" << type << " ["; + formatKnownTypeFlags(dp, static_cast(type)); + dp << ']'; + } if (!size) return AbstractSymbolGroupNodePtrVector(); if (size > 100) diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h index ebabf902cac..d5ef1f4d6ad 100644 --- a/src/libs/qtcreatorcdbext/knowntype.h +++ b/src/libs/qtcreatorcdbext/knowntype.h @@ -51,6 +51,8 @@ enum KnownType 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 + KT_POD_PointerType = KT_POD_Type + 6, // pointer to some POD + KT_PointerType = KT_POD_Type + 7, // pointer to class or complex type // Qt Basic KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1, KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2, diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp index 68647605ed4..ee1eb28a289 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp @@ -338,7 +338,6 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int * break; case 'v': SymbolGroupValue::verbose++; - tokens.pop_front(); break; case 'e': if (tokens.empty()) { diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp index 855d62e64ce..c8a3c988805 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp @@ -238,6 +238,10 @@ std::string SymbolGroup::dump(const std::string &iname, // Real nodes: Expand and complex dumpers if (SymbolGroupNode *node = aNode->resolveReference()->asSymbolGroupNode()) { + if (symbolGroupDebug) + DebugPrint() << "SymbolGroup::dump(" << iname << '/' + << aNode->absoluteFullIName() <<" resolves to " << node->absoluteFullIName() + << " expanded=" << node->isExpanded(); if (node->isExpanded()) { // Mark expand request by watch model node->clearFlags(SymbolGroupNode::ExpandedByDumper); } else { diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 15f59f4e9e9..8e3b95fcd41 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -55,7 +55,7 @@ SymbolGroupValue::SymbolGroupValue(SymbolGroupNode *node, if (m_node && !m_node->isMemoryAccessible()) { // Invalid if no value m_node = 0; if (SymbolGroupValue::verbose) - DebugPrint() << name() << " memory access error"; + DebugPrint() << node->name() << '/' << node->iName() << " memory access error"; } } @@ -265,9 +265,14 @@ std::string SymbolGroupValue::error() const return m_errorMessage; } -bool SymbolGroupValue::isPointerType(const std::string &t) +// Return number of characters to strip for pointer type +unsigned SymbolGroupValue::isPointerType(const std::string &t) { - return endsWith(t, '*'); + if (endsWith(t, "**")) + return 1; + if (endsWith(t, " *")) + return 2; + return 0; } unsigned SymbolGroupValue::pointerSize() @@ -282,21 +287,30 @@ unsigned SymbolGroupValue::intSize() return is; } +unsigned SymbolGroupValue::sizeOf(const char *type) +{ + const unsigned rc = GetTypeSize(type); + if (!rc && SymbolGroupValue::verbose) + DebugPrint() << "GetTypeSize fails for '" << type << '\''; + return rc; +} + unsigned SymbolGroupValue::fieldOffset(const char *type, const char *field) { ULONG rc = 0; - if (GetFieldOffset(type, field, &rc)) + if (GetFieldOffset(type, field, &rc)) { + if (SymbolGroupValue::verbose) + DebugPrint() << "GetFieldOffset fails for '" << type << "' '" << field << '\''; return 0; + } return rc; } std::string SymbolGroupValue::stripPointerType(const std::string &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); + if (const unsigned stripLength = isPointerType(t)) + return t.substr(0, t.size() - stripLength); return t; } @@ -468,38 +482,49 @@ std::list } // Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString') -std::string SymbolGroupValue::resolveType(const std::string &type, const SymbolGroupValueContext &ctx) +std::string SymbolGroupValue::resolveType(const std::string &typeIn, + const SymbolGroupValueContext &ctx, + const SymbolGroup *current /* = 0 */) { enum { BufSize = 512 }; - if (type.empty() || type.find('!') != std::string::npos) - return type; + if (typeIn.empty() || typeIn.find('!') != std::string::npos) + return typeIn; - const std::string stripped = SymbolGroupValue::stripClassPrefixes(type); + const std::string stripped = SymbolGroupValue::stripClassPrefixes(typeIn); + // Use the module of the current symbol group for templates. + // This is because resolving some template types (std::list<> has been + // observed to result in 'QtGui4d!std::list', which subseqently fails. + if (current && stripped.find('<') != std::string::npos) { + std::string trc = current->module(); + trc.push_back('!'); + trc += stripped; + return trc; + } // 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; + return stripped; 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; + return stripped; // 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; + return stripped; std::string rc = buf; rc.push_back('!'); - rc += type; + rc += stripped; return rc; } @@ -630,49 +655,52 @@ static inline void formatMilliSeconds(std::wostream &str, int milliSecs) static const char stdStringTypeC[] = "std::basic_string,std::allocator >"; static const char stdWStringTypeC[] = "std::basic_string,std::allocator >"; -static KnownType knownPODTypeHelper(const std::string &type) +static KnownType knownPODTypeHelper(const std::string &type, std::string::size_type endPos) { - if (type.empty()) + if (type.empty() || !endPos) return KT_Unknown; + const bool isPointer = type.at(endPos - 1) == '*'; switch (type.at(0)) { case 'c': - if (type == "char") - return KT_Char; + if (!type.compare(0, endPos, "char")) + return isPointer ? KT_POD_PointerType : KT_Char; break; case 'd': - if (type == "double") - return KT_FloatType; + if (!type.compare(0, endPos, "double")) + return isPointer ? KT_POD_PointerType : KT_FloatType; break; case 'f': - if (type == "float") - return KT_FloatType; + if (!type.compare(0, endPos, "float")) + return isPointer ? KT_POD_PointerType : KT_FloatType; break; case 'l': if (!type.compare(0, 4, "long")) - return KT_IntType; + return isPointer ? KT_POD_PointerType : KT_IntType; break; case 'i': if (!type.compare(0, 3, "int")) - return KT_IntType; + return isPointer ? KT_POD_PointerType : KT_IntType; break; case 's': if (!type.compare(0, 5, "short")) - return KT_IntType; + return isPointer ? KT_POD_PointerType : KT_IntType; break; case 'u': - if (!type.compare(0, 8, "unsigned")) + if (!type.compare(0, 8, "unsigned")) { + if (isPointer) + return KT_POD_PointerType; return type == "unsigned char" ? KT_UnsignedChar : KT_UnsignedIntType; + } break; } - return KT_Unknown; + return isPointer ? KT_PointerType : KT_Unknown; } // Determine type starting from a position (with/without 'class '/'struct ' prefix). -static KnownType knownClassTypeHelper(const std::string &type, std::string::size_type pos) +static KnownType knownClassTypeHelper(const std::string &type, + std::string::size_type pos, + std::string::size_type endPos) { - // Strip pointer types. - const std::wstring::size_type compareLen = - endsWith(type, " *") ? type.size() -2 : type.size(); // STL ? const std::wstring::size_type templatePos = type.find('<', pos); static const std::wstring::size_type stlClassLen = 5; @@ -708,9 +736,9 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size } } // STL strings - if (!type.compare(pos, compareLen - pos, stdStringTypeC)) + if (!type.compare(pos, endPos - pos, stdStringTypeC)) return KT_StdString; - if (!type.compare(pos, compareLen - pos, stdWStringTypeC)) + if (!type.compare(pos, endPos - pos, stdWStringTypeC)) return KT_StdWString; return KT_Unknown; } // std::sth @@ -763,8 +791,7 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size } } // Remaining non-template types - switch (compareLen - qPos) { - + switch (endPos - qPos) { case 4: if (!type.compare(qPos, 4, "QPen")) return KT_QPen; @@ -997,31 +1024,69 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size return KT_Unknown; } -KnownType knownType(const std::string &type, bool hasClassPrefix) +KnownType knownType(const std::string &type, unsigned flags) { if (type.empty()) return KT_Unknown; - const KnownType podType = knownPODTypeHelper(type); + // Autostrip one pointer if desired + const std::string::size_type endPos = (flags & KnownTypeAutoStripPointer) ? + type.size() - SymbolGroupValue::isPointerType(type) : + type.size(); + + // PODs first + const KnownType podType = knownPODTypeHelper(type, endPos); if (podType != KT_Unknown) return podType; - if (hasClassPrefix) { + + if (flags & KnownTypeHasClassPrefix) { switch (type.at(0)) { // Check 'class X' or 'struct X' case 'c': if (!type.compare(0, 6, "class ")) - return knownClassTypeHelper(type, 6); + return knownClassTypeHelper(type, 6, endPos); break; case 's': if (!type.compare(0, 7, "struct ")) - return knownClassTypeHelper(type, 7); + return knownClassTypeHelper(type, 7, endPos); break; } } else { // No prefix, full check - return knownClassTypeHelper(type, 0); + return knownClassTypeHelper(type, 0, endPos); } return KT_Unknown; } +void formatKnownTypeFlags(std::ostream &os, KnownType kt) +{ + switch (kt) { + case KT_Unknown: + os << ""; + return; + case KT_POD_PointerType: + os << " pod_pointer"; + break; + case KT_PointerType: + os << " pointer"; + break; + default: + break; + } + if (kt & KT_POD_Type) + os << " pod"; + if (kt & KT_Qt_Type) + os << " qt"; + if (kt & KT_Qt_PrimitiveType) + os << " qt_primitive"; + if (kt & KT_Qt_MovableType) + os << " qt_movable"; + if (kt & KT_ContainerType) + os << " container"; + if (kt & KT_STL_Type) + os << " stl"; + if (kt & KT_HasSimpleDumper) + os << " simple_dumper"; +} + static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str) { if (const SymbolGroupValue d = v["d"]) { @@ -1394,11 +1459,13 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, *containerSizeIn = -1; // Check for class types and strip pointer types (references appear as pointers as well) s->clear(); - const KnownType kt = knownType(n->type()); + const KnownType kt = knownType(n->type(), KnownTypeHasClassPrefix|KnownTypeAutoStripPointer); if (knownTypeIn) *knownTypeIn = kt; if (kt == KT_Unknown || !(kt & KT_HasSimpleDumper)) { + if (SymbolGroupValue::verbose > 1) + DebugPrint() << "dumpSimpleType N/A " << n->name() << '/' << n->type(); QTC_TRACE_OUT return SymbolGroupNode::SimpleDumperNotApplicable; } @@ -1407,6 +1474,8 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, // Simple dump of size for containers if (kt & KT_ContainerType) { const int size = containerSize(kt, v); + if (SymbolGroupValue::verbose > 1) + DebugPrint() << "dumpSimpleType Container " << n->name() << '/' << n->type() << " size=" << size; if (containerSizeIn) *containerSizeIn = size; if (size >= 0) { @@ -1482,5 +1551,12 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, if (rc == SymbolGroupNode::SimpleDumperOk) *s = str.str(); QTC_TRACE_OUT + + if (SymbolGroupValue::verbose > 1) { + DebugPrint dp; + dp << "dumpSimpleType " << n->name() << '/' << n->type() << " knowntype= " << kt << " ["; + formatKnownTypeFlags(dp, kt); + dp << "] returns " << rc; + } return rc; } diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index 28c8ddb99c5..e5b1ecf061e 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -42,6 +42,7 @@ #include class SymbolGroupNode; +class SymbolGroup; // Structure to pass all IDebug interfaces used for SymbolGroupValue struct SymbolGroupValueContext @@ -97,7 +98,7 @@ public: std::string error() const; // Some helpers for manipulating types. - static inline unsigned sizeOf(const char *type) { return GetTypeSize(type); } + static inline unsigned sizeOf(const char *type); // Offset of structure field: "!moduleQMapNode", "value". static unsigned fieldOffset(const char *type, const char *field); static std::string stripPointerType(const std::string &); @@ -105,11 +106,16 @@ public: 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 &); + // pointer type, return number of characters to strip + static unsigned 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); + // If a current SymbolGroup is passed on, its module will be used for templates. + static std::string resolveType(const std::string &type, + const SymbolGroupValueContext &ctx, + const SymbolGroup *current = 0); + static std::list resolveSymbol(const char *pattern, const SymbolGroupValueContext &c, std::string *errorMessage = 0); @@ -157,7 +163,17 @@ struct QtInfo * from IDebugSymbolGroup: 'class foo' or 'struct foo'. * 2) Class prefix==false is for inner types of templates, etc, doing * a more expensive check: 'foo' */ -KnownType knownType(const std::string &type, bool hasClassPrefix = true); +enum +{ + KnownTypeHasClassPrefix = 0x1, // Strip "class Foo" -> "Foo" + KnownTypeAutoStripPointer = 0x2 // Strip "class Foo *" -> "Foo" for conveniently + // handling the pointer/value duality of symbol group entries +}; + +KnownType knownType(const std::string &type, unsigned flags); + +// Debug helper +void formatKnownTypeFlags(std::ostream &os, KnownType kt); // Dump builtin simple types using SymbolGroupValue expressions, // returning SymbolGroupNode dumper flags. diff --git a/src/plugins/debugger/cdb2/cdbengine2.cpp b/src/plugins/debugger/cdb2/cdbengine2.cpp index 7941650bb04..e295d3f065b 100644 --- a/src/plugins/debugger/cdb2/cdbengine2.cpp +++ b/src/plugins/debugger/cdb2/cdbengine2.cpp @@ -673,6 +673,8 @@ void CdbEngine::updateWatchData(const Debugger::Internal::WatchData &dataIn, void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const { + if (debuggerCore()->boolSetting(VerboseLog)) + str << blankSeparator << "-v"; if (debuggerCore()->boolSetting(UseDebuggingHelpers)) str << blankSeparator << "-c"; const QByteArray typeFormats = watchHandler()->typeFormatRequests();