forked from qt-creator/qt-creator
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:
@@ -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 AbstractSymbolGroupNodePtrVector();
|
||||||
return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next"));
|
const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"];
|
||||||
return AbstractSymbolGroupNodePtrVector();
|
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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user