Debugge[New CDB]: Refine Symbol qualification for containers.

Resolve all types and always use current module for templates.
Fixes to pointer handling.
Make verbose switchable.
This commit is contained in:
Friedemann Kleint
2011-01-06 12:53:54 +01:00
parent 90a1e723c4
commit ebec516e66
7 changed files with 211 additions and 87 deletions

View File

@@ -43,8 +43,6 @@ typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbol
typedef std::vector<SymbolGroupValue> SymbolGroupValueVector; typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
typedef std::vector<int>::size_type VectorIndexType; typedef std::vector<int>::size_type VectorIndexType;
enum { debugVector = 0 };
// Read a pointer array from debuggee memory (ULONG64/32 according pointer size) // Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx) 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) // 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 // 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 std::string stripped = SymbolGroupValue::stripClassPrefixes(type);
const KnownType kt = knownType(stripped, false); const KnownType kt = knownType(stripped, 0);
// Simple types and STL/Q-types (inexplicably) are fast. // Resolve types unless they are POD or pointers to POD (that is, qualify 'Foo' and 'Foo*')
if (kt & (KT_POD_Type|KT_Qt_Type|KT_STL_Type)) const bool needResolve = kt == KT_Unknown || kt == KT_PointerType || !(kt & KT_POD_Type);
return stripped; const std::string fixed = needResolve ?
return SymbolGroupValue::resolveType(stripped, ctx); 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). // Return size from an STL vector (last/first iterators).
@@ -103,7 +110,7 @@ static inline int msvcStdVectorSize(const SymbolGroupValue &v)
return 0; return 0;
// Subtract the pointers: We need to do the pointer arithmetics ourselves // Subtract the pointers: We need to do the pointer arithmetics ourselves
// as we get char *pointers. // 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()); const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
if (size == 0) if (size == 0)
return -1; return -1;
@@ -249,10 +256,15 @@ private:
static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode *n, int count, static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode *n, int count,
const SymbolGroupValueContext &ctx) const SymbolGroupValueContext &ctx)
{ {
if (count) 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(); 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<T>: Dummy head node and then a linked list of "n", "t". // QLinkedList<T>: 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)) { if (SymbolGroupNode *child = sg->addSymbol(name, std::string(), &errorMessage)) {
rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, child)); rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, child));
} else { } else {
if (SymbolGroupValue::verbose)
DebugPrint() << "addSymbol fails in arrayChildList";
break; break;
} }
} }
if (SymbolGroupValue::verbose)
DebugPrint() << "arrayChildList '" << innerType << "' count=" << count << " returns "
<< rc.size() << " elements";
return rc; return rc;
} }
@@ -341,8 +358,8 @@ static inline AbstractSymbolGroupNodePtrVector
if (myFirst) { if (myFirst) {
if (const ULONG64 address = myFirst.pointerValue()) { if (const ULONG64 address = myFirst.pointerValue()) {
const std::string firstType = myFirst.type(); const std::string firstType = myFirst.type();
const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), ctx); const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), vec);
if (debugVector) if (SymbolGroupValue::verbose)
DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\''; DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\'';
return arrayChildList(n->symbolGroup(), address, innerType, count); return arrayChildList(n->symbolGroup(), address, innerType, count);
} }
@@ -396,9 +413,10 @@ static inline AbstractSymbolGroupNodePtrVector
const std::vector<std::string> innerTypes = deque.innerTypes(); const std::vector<std::string> innerTypes = deque.innerTypes();
if (innerTypes.empty()) if (innerTypes.empty())
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
const std::string innerType = fixInnerType(innerTypes.front(), deque);
// Get the deque size (block size) which is an unavailable static member // Get the deque size (block size) which is an unavailable static member
// (cf <deque> for the actual expression). // (cf <deque> for the actual expression).
const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerTypes.front().c_str()); const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
if (!innerTypeSize) if (!innerTypeSize)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
const int dequeSize = innerTypeSize <= 1 ? 16 : innerTypeSize <= 2 ? const int dequeSize = innerTypeSize <= 1 ? 16 : innerTypeSize <= 2 ?
@@ -410,10 +428,10 @@ static inline AbstractSymbolGroupNodePtrVector
const AbstractSymbolGroupNodePtrVector rc = SymbolGroupValue::pointerSize() == 8 ? const AbstractSymbolGroupNodePtrVector rc = SymbolGroupValue::pointerSize() == 8 ?
stdDequeChildrenHelper(deque.node()->symbolGroup(), stdDequeChildrenHelper(deque.node()->symbolGroup(),
reinterpret_cast<const ULONG64 *>(mapArray), mapSize, reinterpret_cast<const ULONG64 *>(mapArray), mapSize,
innerTypes.front(), innerTypeSize, startOffset, dequeSize, count) : innerType, innerTypeSize, startOffset, dequeSize, count) :
stdDequeChildrenHelper(deque.node()->symbolGroup(), stdDequeChildrenHelper(deque.node()->symbolGroup(),
reinterpret_cast<const ULONG32 *>(mapArray), mapSize, reinterpret_cast<const ULONG32 *>(mapArray), mapSize,
innerTypes.front(), innerTypeSize, startOffset, dequeSize, count); innerType, innerTypeSize, startOffset, dequeSize, count);
delete [] mapArray; delete [] mapArray;
return rc; return rc;
} }
@@ -641,7 +659,7 @@ static inline AbstractSymbolGroupNodePtrVector
const SymbolGroupValue vec(n, ctx); const SymbolGroupValue vec(n, ctx);
if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) { if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) {
if (const ULONG64 arrayAddress = firstElementV.address()) { 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); return arrayChildList(n->symbolGroup(), arrayAddress, fixedInnerType, count);
} }
} }
@@ -685,9 +703,9 @@ static inline AbstractSymbolGroupNodePtrVector
const std::vector<std::string> innerTypes = v.innerTypes(); const std::vector<std::string> innerTypes = v.innerTypes();
if (innerTypes.size() != 1) if (innerTypes.size() != 1)
return AbstractSymbolGroupNodePtrVector(); 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()); const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
if (debugVector) if (SymbolGroupValue::verbose)
DebugPrint() << "QList " << v.name() << " inner type " << innerType << ' ' << innerTypeSize; DebugPrint() << "QList " << v.name() << " inner type " << innerType << ' ' << innerTypeSize;
if (!innerTypeSize) if (!innerTypeSize)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
@@ -711,7 +729,7 @@ static inline AbstractSymbolGroupNodePtrVector
if (kt != KT_Unknown && !(kt & (KT_POD_Type|KT_Qt_PrimitiveType|KT_Qt_MovableType))) if (kt != KT_Unknown && !(kt & (KT_POD_Type|KT_Qt_PrimitiveType|KT_Qt_MovableType)))
isLargeOrStatic = true; isLargeOrStatic = true;
} }
if (debugVector) if (SymbolGroupValue::verbose)
DebugPrint() << "isLargeOrStatic " << isLargeOrStatic; DebugPrint() << "isLargeOrStatic " << isLargeOrStatic;
if (isLargeOrStatic) { if (isLargeOrStatic) {
// Retrieve the pointer array ourselves to avoid having to evaluate '*(class foo**)' // 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); return QtInfo::prependModuleAndNameSpace(qHashType, currentModule, qtInfo.nameSpace);
} }
enum { debugMap = 0 };
// Return up to count nodes of type "QHashNode<K,V>" of a "class QHash<K,V>". // Return up to count nodes of type "QHashNode<K,V>" of a "class QHash<K,V>".
SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v, SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
VectorIndexType count) VectorIndexType count)
@@ -787,7 +803,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
const SymbolGroupValue hashData = v["d"]; const SymbolGroupValue hashData = v["d"];
// 'e' is used as a special value to indicate empty hash buckets in the array. // 'e' is used as a special value to indicate empty hash buckets in the array.
const ULONG64 ePtr = v["e"].pointerValue(); const ULONG64 ePtr = v["e"].pointerValue();
if (debugMap) if (SymbolGroupValue::verbose)
DebugPrint() << v << " Count=" << count << ",ePtr=0x" << std::hex << ePtr; DebugPrint() << v << " Count=" << count << ",ePtr=0x" << std::hex << ePtr;
if (!hashData || !ePtr) if (!hashData || !ePtr)
return SymbolGroupValueVector(); return SymbolGroupValueVector();
@@ -825,7 +841,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
dummyNodeList.push_back(next); dummyNodeList.push_back(next);
if (dummyNodeList.size() >= count) // Stop at maximum count if (dummyNodeList.size() >= count) // Stop at maximum count
notEnough = false; notEnough = false;
if (debugMap) if (SymbolGroupValue::verbose > 1)
DebugPrint() << '#' << (dummyNodeList.size() - 1) << " l=" << l << ",next=" << next; DebugPrint() << '#' << (dummyNodeList.size() - 1) << " l=" << l << ",next=" << next;
l = next; l = next;
} else { } else {
@@ -835,7 +851,7 @@ SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
} }
// Finally convert them into real nodes 'QHashNode<K,V> (potentially expensive) // Finally convert them into real nodes 'QHashNode<K,V> (potentially expensive)
const std::string nodeType = qHashNodeType(v, "Node"); const std::string nodeType = qHashNodeType(v, "Node");
if (debugMap) if (SymbolGroupValue::verbose)
DebugPrint() << "Converting into " << nodeType; DebugPrint() << "Converting into " << nodeType;
SymbolGroupValueVector nodeList; SymbolGroupValueVector nodeList;
nodeList.reserve(count); nodeList.reserve(count);
@@ -901,11 +917,11 @@ static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, Vector
{ {
const SymbolGroupValue e = v["e"]; const SymbolGroupValue e = v["e"];
const ULONG64 ePtr = e.pointerValue(); const ULONG64 ePtr = e.pointerValue();
if (debugMap) if (SymbolGroupValue::verbose)
DebugPrint() << v.type() << " E=0x" << std::hex << ePtr; DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
if (!ePtr) if (!ePtr)
return SymbolGroupValueVector(); return SymbolGroupValueVector();
if (debugMap) if (SymbolGroupValue::verbose)
DebugPrint() << v.type() << " E=0x" << std::hex << ePtr; DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
SymbolGroupValueVector rc; SymbolGroupValueVector rc;
rc.reserve(count); rc.reserve(count);
@@ -921,7 +937,7 @@ static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, Vector
static inline AbstractSymbolGroupNodePtrVector static inline AbstractSymbolGroupNodePtrVector
qMapChildList(const SymbolGroupValue &v, VectorIndexType count) qMapChildList(const SymbolGroupValue &v, VectorIndexType count)
{ {
if (debugMap) if (SymbolGroupValue::verbose)
DebugPrint() << v.type() << "," << count; DebugPrint() << v.type() << "," << count;
if (!count) if (!count)
@@ -933,7 +949,7 @@ static inline AbstractSymbolGroupNodePtrVector
const std::string mapPayloadNodeType = qHashNodeType(v, "PayloadNode"); const std::string mapPayloadNodeType = qHashNodeType(v, "PayloadNode");
// Calculate the offset needed (see QMap::concrete() used by the iterator). // Calculate the offset needed (see QMap::concrete() used by the iterator).
const unsigned payloadNodeSize = SymbolGroupValue::sizeOf(mapPayloadNodeType.c_str()); const unsigned payloadNodeSize = SymbolGroupValue::sizeOf(mapPayloadNodeType.c_str());
if (debugMap) { if (SymbolGroupValue::verbose) {
DebugPrint() << v.type() << "," << mapNodeType << ':' DebugPrint() << v.type() << "," << mapNodeType << ':'
<< mapPayloadNodeType << ':' << payloadNodeSize << mapPayloadNodeType << ':' << payloadNodeSize
<< ", pointerSize=" << SymbolGroupValue::pointerSize(); << ", pointerSize=" << SymbolGroupValue::pointerSize();
@@ -947,16 +963,18 @@ static inline AbstractSymbolGroupNodePtrVector
const std::vector<std::string> innerTypes = v.innerTypes(); const std::vector<std::string> innerTypes = v.innerTypes();
if (innerTypes.size() != 2u) if (innerTypes.size() != 2u)
return AbstractSymbolGroupNodePtrVector(); 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"); const unsigned valueOffset = SymbolGroupValue::fieldOffset(mapNodeType.c_str(), "value");
if (debugMap) if (SymbolGroupValue::verbose)
DebugPrint() << "Payload=" << payLoad << ",valueOffset=" << valueOffset << ',' DebugPrint() << "Payload=" << payLoad << ",valueOffset=" << valueOffset << ','
<< innerTypes.front() << ',' << innerTypes.back() << ':' << valueSize; << innerTypes.front() << ',' << innerTypes.back() << ':' << valueSize;
if (!valueOffset || !valueSize) if (!valueOffset || !valueSize)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
// Get the children. // Get the children.
const SymbolGroupValueVector childNodes = qMapNodes(v, count); const SymbolGroupValueVector childNodes = qMapNodes(v, count);
if (debugMap) if (SymbolGroupValue::verbose)
DebugPrint() << "children: " << childNodes.size() << " of " << count; DebugPrint() << "children: " << childNodes.size() << " of " << count;
// Deep expansion of the forward[0] sometimes fails. In that case, // Deep expansion of the forward[0] sometimes fails. In that case,
// take what we can get. // take what we can get.
@@ -971,15 +989,14 @@ static inline AbstractSymbolGroupNodePtrVector
rc.reserve(count); rc.reserve(count);
std::string errorMessage; std::string errorMessage;
SymbolGroup *sg = v.node()->symbolGroup(); SymbolGroup *sg = v.node()->symbolGroup();
for (VectorIndexType i = 0; i < count ; i++) { for (VectorIndexType i = 0; i < count ; i++) {
const ULONG64 nodePtr = childNodes.at(i).pointerValue(); const ULONG64 nodePtr = childNodes.at(i).pointerValue();
if (!nodePtr) if (!nodePtr)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
const ULONG64 keyAddress = nodePtr - payLoad; const ULONG64 keyAddress = nodePtr - payLoad;
const std::string keyExp = pointedToSymbolName(keyAddress, innerTypes.front()); const std::string keyExp = pointedToSymbolName(keyAddress, keyType);
const std::string valueExp = pointedToSymbolName(keyAddress + valueOffset, innerTypes.at(1)); const std::string valueExp = pointedToSymbolName(keyAddress + valueOffset, valueType);
if (debugMap) { if (SymbolGroupValue::verbose) {
DebugPrint() << '#' << i << '/' << count << ' ' << std::hex << ",node=0x" << nodePtr << DebugPrint() << '#' << i << '/' << count << ' ' << std::hex << ",node=0x" << nodePtr <<
',' <<keyExp << ',' << valueExp; ',' <<keyExp << ',' << valueExp;
} }
@@ -997,6 +1014,14 @@ static inline AbstractSymbolGroupNodePtrVector
AbstractSymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int type, AbstractSymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int type,
int size, const SymbolGroupValueContext &ctx) int size, const SymbolGroupValueContext &ctx)
{ {
if (SymbolGroupValue::verbose) {
DebugPrint dp;
dp << "containerChildren " << node->name() << '/' << node->iName() << '/' << node->type()
<< " at 0x" << std::hex << node->address() << std::dec
<< " count=" << size << ",knowntype=" << type << " [";
formatKnownTypeFlags(dp, static_cast<KnownType>(type));
dp << ']';
}
if (!size) if (!size)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
if (size > 100) if (size > 100)

View File

@@ -51,6 +51,8 @@ enum KnownType
KT_IntType = KT_POD_Type + 3, // any signed short, long, int KT_IntType = KT_POD_Type + 3, // any signed short, long, int
KT_UnsignedIntType = KT_POD_Type + 4, // any unsigned int KT_UnsignedIntType = KT_POD_Type + 4, // any unsigned int
KT_FloatType = KT_POD_Type + 5, // float, double 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 // Qt Basic
KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1, KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1,
KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2, KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2,

View File

@@ -338,7 +338,6 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
break; break;
case 'v': case 'v':
SymbolGroupValue::verbose++; SymbolGroupValue::verbose++;
tokens.pop_front();
break; break;
case 'e': case 'e':
if (tokens.empty()) { if (tokens.empty()) {

View File

@@ -238,6 +238,10 @@ std::string SymbolGroup::dump(const std::string &iname,
// Real nodes: Expand and complex dumpers // Real nodes: Expand and complex dumpers
if (SymbolGroupNode *node = aNode->resolveReference()->asSymbolGroupNode()) { 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 if (node->isExpanded()) { // Mark expand request by watch model
node->clearFlags(SymbolGroupNode::ExpandedByDumper); node->clearFlags(SymbolGroupNode::ExpandedByDumper);
} else { } else {

View File

@@ -55,7 +55,7 @@ SymbolGroupValue::SymbolGroupValue(SymbolGroupNode *node,
if (m_node && !m_node->isMemoryAccessible()) { // Invalid if no value if (m_node && !m_node->isMemoryAccessible()) { // Invalid if no value
m_node = 0; m_node = 0;
if (SymbolGroupValue::verbose) 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; 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() unsigned SymbolGroupValue::pointerSize()
@@ -282,21 +287,30 @@ unsigned SymbolGroupValue::intSize()
return is; 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) unsigned SymbolGroupValue::fieldOffset(const char *type, const char *field)
{ {
ULONG rc = 0; 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 0;
}
return rc; return rc;
} }
std::string SymbolGroupValue::stripPointerType(const std::string &t) std::string SymbolGroupValue::stripPointerType(const std::string &t)
{ {
// 'Foo *' -> 'Foo', 'Bar **' -> 'Bar *'. // 'Foo *' -> 'Foo', 'Bar **' -> 'Bar *'.
if (endsWith(t, "**")) if (const unsigned stripLength = isPointerType(t))
return t.substr(0, t.size() - 1); return t.substr(0, t.size() - stripLength);
if (endsWith(t, " *"))
return t.substr(0, t.size() - 2);
return t; return t;
} }
@@ -468,38 +482,49 @@ std::list<std::string>
} }
// Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString') // 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 }; enum { BufSize = 512 };
if (type.empty() || type.find('!') != std::string::npos) if (typeIn.empty() || typeIn.find('!') != std::string::npos)
return type; 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. // Obtain the base address of the module using an obscure ioctl() call.
// See inline implementation of GetTypeSize() and docs. // See inline implementation of GetTypeSize() and docs.
SYM_DUMP_PARAM symParameters = { sizeof (SYM_DUMP_PARAM), (PUCHAR)stripped.c_str(), DBG_DUMP_NO_PRINT, 0, SYM_DUMP_PARAM symParameters = { sizeof (SYM_DUMP_PARAM), (PUCHAR)stripped.c_str(), DBG_DUMP_NO_PRINT, 0,
NULL, NULL, NULL, 0, NULL }; NULL, NULL, NULL, 0, NULL };
const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size); const ULONG typeSize = Ioctl(IG_GET_TYPE_SIZE, &symParameters, symParameters.size);
if (!typeSize || !symParameters.ModBase) // Failed? if (!typeSize || !symParameters.ModBase) // Failed?
return type; return stripped;
ULONG index = 0; ULONG index = 0;
ULONG64 base = 0; ULONG64 base = 0;
// Convert module base address to module index // Convert module base address to module index
HRESULT hr = ctx.symbols->GetModuleByOffset(symParameters.ModBase, 0, &index, &base); HRESULT hr = ctx.symbols->GetModuleByOffset(symParameters.ModBase, 0, &index, &base);
if (FAILED(hr)) if (FAILED(hr))
return type; return stripped;
// Obtain module name // Obtain module name
char buf[BufSize]; char buf[BufSize];
buf[0] = '\0'; buf[0] = '\0';
hr = ctx.symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index, base, buf, BufSize, 0); hr = ctx.symbols->GetModuleNameString(DEBUG_MODNAME_MODULE, index, base, buf, BufSize, 0);
if (FAILED(hr)) if (FAILED(hr))
return type; return stripped;
std::string rc = buf; std::string rc = buf;
rc.push_back('!'); rc.push_back('!');
rc += type; rc += stripped;
return rc; return rc;
} }
@@ -630,49 +655,52 @@ 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 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 const char stdWStringTypeC[] = "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
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; return KT_Unknown;
const bool isPointer = type.at(endPos - 1) == '*';
switch (type.at(0)) { switch (type.at(0)) {
case 'c': case 'c':
if (type == "char") if (!type.compare(0, endPos, "char"))
return KT_Char; return isPointer ? KT_POD_PointerType : KT_Char;
break; break;
case 'd': case 'd':
if (type == "double") if (!type.compare(0, endPos, "double"))
return KT_FloatType; return isPointer ? KT_POD_PointerType : KT_FloatType;
break; break;
case 'f': case 'f':
if (type == "float") if (!type.compare(0, endPos, "float"))
return KT_FloatType; return isPointer ? KT_POD_PointerType : KT_FloatType;
break; break;
case 'l': case 'l':
if (!type.compare(0, 4, "long")) if (!type.compare(0, 4, "long"))
return KT_IntType; return isPointer ? KT_POD_PointerType : KT_IntType;
break; break;
case 'i': case 'i':
if (!type.compare(0, 3, "int")) if (!type.compare(0, 3, "int"))
return KT_IntType; return isPointer ? KT_POD_PointerType : KT_IntType;
break; break;
case 's': case 's':
if (!type.compare(0, 5, "short")) if (!type.compare(0, 5, "short"))
return KT_IntType; return isPointer ? KT_POD_PointerType : KT_IntType;
break; break;
case 'u': 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; return type == "unsigned char" ? KT_UnsignedChar : KT_UnsignedIntType;
}
break; break;
} }
return KT_Unknown; return isPointer ? KT_PointerType : KT_Unknown;
} }
// Determine type starting from a position (with/without 'class '/'struct ' prefix). // 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 ? // STL ?
const std::wstring::size_type templatePos = type.find('<', pos); const std::wstring::size_type templatePos = type.find('<', pos);
static const std::wstring::size_type stlClassLen = 5; static const std::wstring::size_type stlClassLen = 5;
@@ -708,9 +736,9 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size
} }
} }
// STL strings // STL strings
if (!type.compare(pos, compareLen - pos, stdStringTypeC)) if (!type.compare(pos, endPos - pos, stdStringTypeC))
return KT_StdString; return KT_StdString;
if (!type.compare(pos, compareLen - pos, stdWStringTypeC)) if (!type.compare(pos, endPos - pos, stdWStringTypeC))
return KT_StdWString; return KT_StdWString;
return KT_Unknown; return KT_Unknown;
} // std::sth } // std::sth
@@ -763,8 +791,7 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size
} }
} }
// Remaining non-template types // Remaining non-template types
switch (compareLen - qPos) { switch (endPos - qPos) {
case 4: case 4:
if (!type.compare(qPos, 4, "QPen")) if (!type.compare(qPos, 4, "QPen"))
return KT_QPen; return KT_QPen;
@@ -997,31 +1024,69 @@ static KnownType knownClassTypeHelper(const std::string &type, std::string::size
return KT_Unknown; return KT_Unknown;
} }
KnownType knownType(const std::string &type, bool hasClassPrefix) KnownType knownType(const std::string &type, unsigned flags)
{ {
if (type.empty()) if (type.empty())
return KT_Unknown; 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) if (podType != KT_Unknown)
return podType; return podType;
if (hasClassPrefix) {
if (flags & KnownTypeHasClassPrefix) {
switch (type.at(0)) { // Check 'class X' or 'struct X' switch (type.at(0)) { // Check 'class X' or 'struct X'
case 'c': case 'c':
if (!type.compare(0, 6, "class ")) if (!type.compare(0, 6, "class "))
return knownClassTypeHelper(type, 6); return knownClassTypeHelper(type, 6, endPos);
break; break;
case 's': case 's':
if (!type.compare(0, 7, "struct ")) if (!type.compare(0, 7, "struct "))
return knownClassTypeHelper(type, 7); return knownClassTypeHelper(type, 7, endPos);
break; break;
} }
} else { } else {
// No prefix, full check // No prefix, full check
return knownClassTypeHelper(type, 0); return knownClassTypeHelper(type, 0, endPos);
} }
return KT_Unknown; return KT_Unknown;
} }
void formatKnownTypeFlags(std::ostream &os, KnownType kt)
{
switch (kt) {
case KT_Unknown:
os << "<unknown>";
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) static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str)
{ {
if (const SymbolGroupValue d = v["d"]) { if (const SymbolGroupValue d = v["d"]) {
@@ -1394,11 +1459,13 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
*containerSizeIn = -1; *containerSizeIn = -1;
// Check for class types and strip pointer types (references appear as pointers as well) // Check for class types and strip pointer types (references appear as pointers as well)
s->clear(); s->clear();
const KnownType kt = knownType(n->type()); const KnownType kt = knownType(n->type(), KnownTypeHasClassPrefix|KnownTypeAutoStripPointer);
if (knownTypeIn) if (knownTypeIn)
*knownTypeIn = kt; *knownTypeIn = kt;
if (kt == KT_Unknown || !(kt & KT_HasSimpleDumper)) { if (kt == KT_Unknown || !(kt & KT_HasSimpleDumper)) {
if (SymbolGroupValue::verbose > 1)
DebugPrint() << "dumpSimpleType N/A " << n->name() << '/' << n->type();
QTC_TRACE_OUT QTC_TRACE_OUT
return SymbolGroupNode::SimpleDumperNotApplicable; return SymbolGroupNode::SimpleDumperNotApplicable;
} }
@@ -1407,6 +1474,8 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
// Simple dump of size for containers // Simple dump of size for containers
if (kt & KT_ContainerType) { if (kt & KT_ContainerType) {
const int size = containerSize(kt, v); const int size = containerSize(kt, v);
if (SymbolGroupValue::verbose > 1)
DebugPrint() << "dumpSimpleType Container " << n->name() << '/' << n->type() << " size=" << size;
if (containerSizeIn) if (containerSizeIn)
*containerSizeIn = size; *containerSizeIn = size;
if (size >= 0) { if (size >= 0) {
@@ -1482,5 +1551,12 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
if (rc == SymbolGroupNode::SimpleDumperOk) if (rc == SymbolGroupNode::SimpleDumperOk)
*s = str.str(); *s = str.str();
QTC_TRACE_OUT 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; return rc;
} }

View File

@@ -42,6 +42,7 @@
#include <list> #include <list>
class SymbolGroupNode; class SymbolGroupNode;
class SymbolGroup;
// Structure to pass all IDebug interfaces used for SymbolGroupValue // Structure to pass all IDebug interfaces used for SymbolGroupValue
struct SymbolGroupValueContext struct SymbolGroupValueContext
@@ -97,7 +98,7 @@ public:
std::string error() const; std::string error() const;
// Some helpers for manipulating types. // 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<K,T>", "value". // Offset of structure field: "!moduleQMapNode<K,T>", "value".
static unsigned fieldOffset(const char *type, const char *field); static unsigned fieldOffset(const char *type, const char *field);
static std::string stripPointerType(const std::string &); static std::string stripPointerType(const std::string &);
@@ -105,11 +106,16 @@ public:
static std::string stripClassPrefixes(const std::string &); static std::string stripClassPrefixes(const std::string &);
static std::string addPointerType(const std::string &); static std::string addPointerType(const std::string &);
static std::string stripArrayType(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') // Resolve a type, that is, obtain its module name ('QString'->'QtCored4!QString')
// Some operations on types (like adding symbols may fail non-deterministically // Some operations on types (like adding symbols may fail non-deterministically
// or be slow when the module specification is omitted). // 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<std::string> resolveSymbol(const char *pattern, static std::list<std::string> resolveSymbol(const char *pattern,
const SymbolGroupValueContext &c, const SymbolGroupValueContext &c,
std::string *errorMessage = 0); std::string *errorMessage = 0);
@@ -157,7 +163,17 @@ struct QtInfo
* from IDebugSymbolGroup: 'class foo' or 'struct foo'. * from IDebugSymbolGroup: 'class foo' or 'struct foo'.
* 2) Class prefix==false is for inner types of templates, etc, doing * 2) Class prefix==false is for inner types of templates, etc, doing
* a more expensive check: 'foo' */ * 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, // Dump builtin simple types using SymbolGroupValue expressions,
// returning SymbolGroupNode dumper flags. // returning SymbolGroupNode dumper flags.

View File

@@ -673,6 +673,8 @@ void CdbEngine::updateWatchData(const Debugger::Internal::WatchData &dataIn,
void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
{ {
if (debuggerCore()->boolSetting(VerboseLog))
str << blankSeparator << "-v";
if (debuggerCore()->boolSetting(UseDebuggingHelpers)) if (debuggerCore()->boolSetting(UseDebuggingHelpers))
str << blankSeparator << "-c"; str << blankSeparator << "-c";
const QByteArray typeFormats = watchHandler()->typeFormatRequests(); const QByteArray typeFormats = watchHandler()->typeFormatRequests();