CDB: Fix STL debugger helpers for MSVC2012 beta.

In MSVC2012, more bases classes for std::string
and containers were introduced whereas std::pair_base
was removed compared to MSVC2010.

Add a findMember() function to be able to skip base
classes when looking for a certain member to finally
fix this issue.
Introduce SymbolGroupValue::parent()/childCount()
and simplify the helpers using it.

Change-Id: I7a6aad5c07739ca9cbf350489acd6d03bd1865e8
Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
Friedemann Kleint
2012-08-02 13:32:37 +02:00
committed by hjk
parent c45ae0e288
commit b5abaa27df
4 changed files with 113 additions and 102 deletions

View File

@@ -98,8 +98,9 @@ static inline std::string fixInnerType(std::string type,
// Return size from an STL vector (last/first iterators). // Return size from an STL vector (last/first iterators).
static inline int msvcStdVectorSize(const SymbolGroupValue &v) static inline int msvcStdVectorSize(const SymbolGroupValue &v)
{ {
if (const SymbolGroupValue myFirstPtrV = v["_Myfirst"]) { // MSVC2012 has 2 base classes, MSVC2010 1, MSVC2008 none
if (const SymbolGroupValue myLastPtrV = v["_Mylast"]) { if (const SymbolGroupValue myFirstPtrV = SymbolGroupValue::findMember(v, "_Myfirst")) {
if (const SymbolGroupValue myLastPtrV = myFirstPtrV.parent()["_Mylast"]) {
const ULONG64 firstPtr = myFirstPtrV.pointerValue(); const ULONG64 firstPtr = myFirstPtrV.pointerValue();
const ULONG64 lastPtr = myLastPtrV.pointerValue(); const ULONG64 lastPtr = myLastPtrV.pointerValue();
if (!firstPtr || lastPtr < firstPtr) if (!firstPtr || lastPtr < firstPtr)
@@ -182,46 +183,20 @@ int containerSize(KnownType kt, const SymbolGroupValue &v)
if (const SymbolGroupValue base = v[unsigned(0)]) if (const SymbolGroupValue base = v[unsigned(0)])
return containerSize(KT_QMap, base); return containerSize(KT_QMap, base);
break; break;
case KT_StdVector: { case KT_StdVector:
if (const SymbolGroupValue base = v[unsigned(0)]) { return msvcStdVectorSize(v);
const int msvc10Size = msvcStdVectorSize(base); case KT_StdDeque: // MSVC2012 has many base classes, MSVC2010 1, MSVC2008 none
if (msvc10Size >= 0) case KT_StdSet:
return msvc10Size; case KT_StdMap:
} case KT_StdMultiMap:
const int msvc8Size = msvcStdVectorSize(v);
if (msvc8Size >= 0)
return msvc8Size;
}
break;
case KT_StdList: case KT_StdList:
if (const SymbolGroupValue sizeV = v["_Mysize"]) // VS 8 if (const SymbolGroupValue size = SymbolGroupValue::findMember(v, "_Mysize"))
return sizeV.intValue(); return size.intValue();
if (const SymbolGroupValue sizeV = v[unsigned(0)][unsigned(0)]["_Mysize"]) // VS10
return sizeV.intValue();
break;
case KT_StdDeque: {
const SymbolGroupValue msvc10sizeV = v[unsigned(0)]["_Mysize"]; // VS10
if (msvc10sizeV)
return msvc10sizeV.intValue();
const SymbolGroupValue msvc8sizeV = v["_Mysize"]; // VS8
if (msvc8sizeV)
return msvc8sizeV.intValue();
}
break; break;
case KT_StdStack: case KT_StdStack:
if (const SymbolGroupValue deque = v[unsigned(0)]) if (const SymbolGroupValue deque = v[unsigned(0)])
return containerSize(KT_StdDeque, deque); return containerSize(KT_StdDeque, deque);
break; break;
case KT_StdSet:
case KT_StdMap:
case KT_StdMultiMap:
if (const SymbolGroupValue baseV = v[unsigned(0)]) {
if (const SymbolGroupValue sizeV = baseV["_Mysize"]) // VS 8
return sizeV.intValue();
if (const SymbolGroupValue sizeV = baseV[unsigned(0)][unsigned(0)]["_Mysize"]) // VS 10
return sizeV.intValue();
}
break;
} }
return -1; return -1;
} }
@@ -258,20 +233,19 @@ private:
const char *m_name; const char *m_name;
}; };
// std::list<T>: Dummy head node and then a linked list of "_Next", "_Myval". // std::list<T>: Skip dummy head node and then a linked list of "_Next", "_Myval".
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)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"]; const SymbolGroupValue head = SymbolGroupValue::findMember(SymbolGroupValue(n, ctx), "_Myhead")["_Next"];
if (!head) { if (head)
return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next"));
if (SymbolGroupValue::verbose) if (SymbolGroupValue::verbose)
DebugPrint() << "std::list failure: " << head; DebugPrint() << "std::list failure: " << head;
return AbstractSymbolGroupNodePtrVector(); 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".
static inline AbstractSymbolGroupNodePtrVector qLinkedListChildList(SymbolGroupNode *n, int count, static inline AbstractSymbolGroupNodePtrVector qLinkedListChildList(SymbolGroupNode *n, int count,
@@ -346,25 +320,24 @@ static inline AbstractSymbolGroupNodePtrVector
static inline AbstractSymbolGroupNodePtrVector static inline AbstractSymbolGroupNodePtrVector
stdVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx) stdVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
{ {
if (count) { if (!count)
return AbstractSymbolGroupNodePtrVector();
// MSVC2012 has 2 base classes, MSVC2010 1, MSVC2008 none
const SymbolGroupValue vec = SymbolGroupValue(n, ctx);
SymbolGroupValue myFirst = SymbolGroupValue::findMember(vec, "_Myfirst");
if (!myFirst)
return AbstractSymbolGroupNodePtrVector();
// std::vector<T>: _Myfirst is a pointer of T*. Get address // std::vector<T>: _Myfirst is a pointer of T*. Get address
// element to obtain address. // element to obtain address.
const SymbolGroupValue vec(n, ctx); const ULONG64 address = myFirst.pointerValue();
SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010 if (!address)
if (!myFirst) return AbstractSymbolGroupNodePtrVector();
myFirst = vec["_Myfirst"]; // MSVC2008
if (myFirst) {
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), vec); const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), vec);
if (SymbolGroupValue::verbose) if (SymbolGroupValue::verbose)
DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\''; DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\'';
return arrayChildList(n->symbolGroup(), address, n->module(), innerType, count); return arrayChildList(n->symbolGroup(), address, n->module(), innerType, count);
} }
}
}
return AbstractSymbolGroupNodePtrVector();
}
// Helper for std::deque<>: From the array of deque blocks, read out the values. // Helper for std::deque<>: From the array of deque blocks, read out the values.
template<class AddressType> template<class AddressType>
@@ -399,17 +372,21 @@ AbstractSymbolGroupNodePtrVector
// std::deque<> // std::deque<>
static inline AbstractSymbolGroupNodePtrVector static inline AbstractSymbolGroupNodePtrVector
stdDequeDirectChildList(const SymbolGroupValue &deque, int count) stdDequeChildList(const SymbolGroupValue &dequeIn, int count)
{ {
if (!count) if (!count)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
// From MSVC10 on, there is an additional base class // From MSVC10 on, there is an additional base class, MSVC2012 more.
const ULONG64 arrayAddress = deque["_Map"].pointerValue(); const SymbolGroupValue map = SymbolGroupValue::findMember(dequeIn, "_Map");
if (!map)
return AbstractSymbolGroupNodePtrVector();
const SymbolGroupValue deque = map.parent();
const ULONG64 arrayAddress = map.pointerValue();
const int startOffset = deque["_Myoff"].intValue(); const int startOffset = deque["_Myoff"].intValue();
const int mapSize = deque["_Mapsize"].intValue(); const int mapSize = deque["_Mapsize"].intValue();
if (!arrayAddress || startOffset < 0 || mapSize <= 0) if (!arrayAddress || startOffset < 0 || mapSize <= 0)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
const std::vector<std::string> innerTypes = deque.innerTypes(); const std::vector<std::string> innerTypes = dequeIn.innerTypes();
if (innerTypes.empty()) if (innerTypes.empty())
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
const std::string innerType = fixInnerType(innerTypes.front(), deque); const std::string innerType = fixInnerType(innerTypes.front(), deque);
@@ -435,15 +412,6 @@ static inline AbstractSymbolGroupNodePtrVector
return rc; return rc;
} }
// std::deque<>
static inline AbstractSymbolGroupNodePtrVector
stdDequeChildList(const SymbolGroupValue &v, int count)
{
// MSVC10 has a base class. If that fails, try direct (MSVC2008)
const AbstractSymbolGroupNodePtrVector msvc10rc = stdDequeDirectChildList(v[unsigned(0)], count);
return msvc10rc.empty() ? stdDequeDirectChildList(v, count) : msvc10rc;
}
/* Helper class for std::map<>,std::set<> based on std::__Tree: /* Helper class for std::map<>,std::set<> based on std::__Tree:
* We locally rebuild the structure in using instances of below class 'StdMapNode' * We locally rebuild the structure in using instances of below class 'StdMapNode'
* with 'left' and 'right' pointers and the values. Reason being that while it is * with 'left' and 'right' pointers and the values. Reason being that while it is
@@ -579,21 +547,20 @@ void StdMapNode::debug(std::ostream &os, unsigned depth) const
// Helper for std::map<>,std::set<> based on std::__Tree: // Helper for std::map<>,std::set<> based on std::__Tree:
// Return the list of children (pair for maps, direct children for set) // Return the list of children (pair for maps, direct children for set)
static inline SymbolGroupValueVector static inline SymbolGroupValueVector
stdTreeChildList(const SymbolGroupValue &tree, int count, bool *isMSVC2010In = 0) stdTreeChildList(const SymbolGroupValue &treeIn, int count)
{ {
if (!count) if (!count)
return SymbolGroupValueVector(); return SymbolGroupValueVector();
// MSVC2012: many base classes.
// MSVC2010: "class _Tree : public _Tree_val: public _Tree_nod". // MSVC2010: "class _Tree : public _Tree_val: public _Tree_nod".
// MSVC2008: Direct class // MSVC2008: Direct class
const int size = tree[unsigned(0)][unsigned(0)]["_Mysize"].intValue(); const SymbolGroupValue sizeV = SymbolGroupValue::findMember(treeIn, "_Mysize");
const bool isMSVC2010 = size >= 0 && size <= count; // Count may be limited const SymbolGroupValue tree = sizeV.parent();
if (isMSVC2010In) const int size = sizeV.intValue();
*isMSVC2010In = isMSVC2010; if (!tree|| size <= 0)
const SymbolGroupValue treeNode = isMSVC2010 ? tree[unsigned(0)][unsigned(0)] : tree;
if (!treeNode)
return SymbolGroupValueVector(); return SymbolGroupValueVector();
// Build the tree and iterate it. // Build the tree and iterate it.
const StdMapNode *nodeTree = StdMapNode::buildMap(treeNode); const StdMapNode *nodeTree = StdMapNode::buildMap(tree);
if (!nodeTree) if (!nodeTree)
return SymbolGroupValueVector(); return SymbolGroupValueVector();
SymbolGroupValueVector rc; SymbolGroupValueVector rc;
@@ -611,7 +578,7 @@ static inline SymbolGroupValueVector
static inline AbstractSymbolGroupNodePtrVector static inline AbstractSymbolGroupNodePtrVector
stdSetChildList(const SymbolGroupValue &set, int count) stdSetChildList(const SymbolGroupValue &set, int count)
{ {
const SymbolGroupValueVector children = stdTreeChildList(set[unsigned(0)], count); const SymbolGroupValueVector children = stdTreeChildList(set, count);
if (int(children.size()) != count) if (int(children.size()) != count)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
AbstractSymbolGroupNodePtrVector rc; AbstractSymbolGroupNodePtrVector rc;
@@ -625,17 +592,16 @@ static inline AbstractSymbolGroupNodePtrVector
static inline AbstractSymbolGroupNodePtrVector static inline AbstractSymbolGroupNodePtrVector
stdMapChildList(const SymbolGroupValue &map, int count) stdMapChildList(const SymbolGroupValue &map, int count)
{ {
bool isMSVC2010 = true; const SymbolGroupValueVector children = stdTreeChildList(map[unsigned(0)], count);
const SymbolGroupValueVector children = stdTreeChildList(map[unsigned(0)], count, &isMSVC2010);
if (int(children.size()) != count) if (int(children.size()) != count)
return AbstractSymbolGroupNodePtrVector(); return AbstractSymbolGroupNodePtrVector();
AbstractSymbolGroupNodePtrVector rc; AbstractSymbolGroupNodePtrVector rc;
rc.reserve(count); rc.reserve(count);
const std::string firstName = "first";
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
// MSVC2010 introduces a std::pair_base. // MSVC2010 (only) has a std::pair_base class.
const SymbolGroupValue pairBase = isMSVC2010? const SymbolGroupValue key = SymbolGroupValue::findMember(children.at(i), firstName);
children.at(i)[unsigned(0)] : children.at(i); const SymbolGroupValue pairBase = key.parent();
const SymbolGroupValue key = pairBase["first"];
const SymbolGroupValue value = pairBase["second"]; const SymbolGroupValue value = pairBase["second"];
if (key && value) { if (key && value) {
rc.push_back(MapNodeSymbolGroupNode::create(i, pairBase.address(), rc.push_back(MapNodeSymbolGroupNode::create(i, pairBase.address(),

View File

@@ -386,7 +386,7 @@ DumpParameters::checkRecode(const std::string &type,
DumpParameterRecodeResult result; DumpParameterRecodeResult result;
if (SymbolGroupValue::verbose > 2) { if (SymbolGroupValue::verbose > 2) {
DebugPrint debugPrint; DebugPrint debugPrint;
debugPrint << '>' << __FUNCTION__ << ' ' << iname << '/' << iname; debugPrint << '>' << __FUNCTION__ << ' ' << iname << '/' << type;
if (dp) if (dp)
debugPrint << " option format: " << dp->format(type, iname); debugPrint << " option format: " << dp->format(type, iname);
} }
@@ -472,6 +472,9 @@ DumpParameters::checkRecode(const std::string &type,
ULONG obtained = 0; ULONG obtained = 0;
if (FAILED(ctx.dataspaces->ReadVirtual(address, result.buffer, ULONG(result.size), &obtained))) { if (FAILED(ctx.dataspaces->ReadVirtual(address, result.buffer, ULONG(result.size), &obtained))) {
delete [] result.buffer; delete [] result.buffer;
DebugPrint() << __FUNCTION__ << " ReadVirtual() failed to read "
<< result.size << " bytes from 0x" << std::hex
<< address << std::dec << " for " << iname << '.';
result = DumpParameterRecodeResult(); result = DumpParameterRecodeResult();
} }
if (SymbolGroupValue::verbose > 2) if (SymbolGroupValue::verbose > 2)

View File

@@ -126,6 +126,22 @@ SymbolGroupValue SymbolGroupValue::operator[](unsigned index) const
return SymbolGroupValue(m_errorMessage); return SymbolGroupValue(m_errorMessage);
} }
unsigned SymbolGroupValue::childCount() const
{
if (ensureExpanded())
return unsigned(m_node->children().size());
return 0;
}
SymbolGroupValue SymbolGroupValue::parent() const
{
if (isValid())
if (AbstractSymbolGroupNode *aParent = m_node->parent())
if (SymbolGroupNode *parent = aParent->asSymbolGroupNode())
return SymbolGroupValue(parent, m_context);
return SymbolGroupValue("parent() invoked on invalid value.");
}
bool SymbolGroupValue::ensureExpanded() const bool SymbolGroupValue::ensureExpanded() const
{ {
if (!isValid() || !m_node->canExpand()) if (!isValid() || !m_node->canExpand())
@@ -205,7 +221,7 @@ int SymbolGroupValue::intValue(int defaultValue) const
return rc; return rc;
} }
if (SymbolGroupValue::verbose) if (SymbolGroupValue::verbose)
DebugPrint() << name() << "::intValue() fails"; DebugPrint() << name() << '/' << type() << '/'<< m_errorMessage << ": intValue() fails";
return defaultValue; return defaultValue;
} }
@@ -217,7 +233,7 @@ ULONG64 SymbolGroupValue::pointerValue(ULONG64 defaultValue) const
return rc; return rc;
} }
if (SymbolGroupValue::verbose) if (SymbolGroupValue::verbose)
DebugPrint() << name() << "::pointerValue() fails"; DebugPrint() << name() << '/'<< type() << '/' << m_errorMessage << ": pointerValue() fails";
return defaultValue; return defaultValue;
} }
@@ -383,6 +399,30 @@ SymbolGroupValue SymbolGroupValue::typeCastedValue(ULONG64 address, const char *
return SymbolGroupValue(); return SymbolGroupValue();
} }
SymbolGroupValue SymbolGroupValue::findMember(const SymbolGroupValue &start,
const std::string &symbolName)
{
const unsigned count = start.childCount();
for (unsigned i = 0; i < count ; ++i) { // check members
const SymbolGroupValue child = start[i];
if (child.name() == symbolName)
return child;
}
// Recurse down base classes at the beginning that have class names
// as value.
for (unsigned i = 0; i < count; ++i) {
const SymbolGroupValue child = start[i];
const std::wstring value = child.value();
if (value.compare(0, 6, L"class ") && value.compare(0, 7, L"struct ")) {
break;
} else {
if (SymbolGroupValue r = findMember(child, symbolName))
return r;
}
}
return SymbolGroupValue();
}
std::wstring SymbolGroupValue::wcharPointerData(unsigned charCount, unsigned maxCharCount) const std::wstring SymbolGroupValue::wcharPointerData(unsigned charCount, unsigned maxCharCount) const
{ {
const bool truncated = charCount > maxCharCount; const bool truncated = charCount > maxCharCount;
@@ -2047,14 +2087,10 @@ static inline bool dumpQWindow(const SymbolGroupValue &v, std::wostream &str, vo
// Dump a std::string. // Dump a std::string.
static bool dumpStd_W_String(const SymbolGroupValue &v, int type, std::wostream &str) static bool dumpStd_W_String(const SymbolGroupValue &v, int type, std::wostream &str)
{ {
SymbolGroupValue bx = v[unsigned(0)]["_Bx"]; // Find 'bx'. MSVC 2012 has 2 base classes, MSVC 2010 1,
int reserved = 0; // and MSVC2008 none
if (bx) { // MSVC 2010 const SymbolGroupValue bx = SymbolGroupValue::findMember(v, "_Bx");
reserved = v[unsigned(0)]["_Myres"].intValue(); const int reserved = bx.parent()["_Myres"].intValue();
} else { // MSVC2008
bx = v["_Bx"];
reserved = v["_Myres"].intValue();
}
if (!bx || reserved < 0) if (!bx || reserved < 0)
return false; return false;
// 'Buf' array for small strings, else pointer 'Ptr'. // 'Buf' array for small strings, else pointer 'Ptr'.

View File

@@ -68,11 +68,17 @@ public:
// Access children by name or index (0-based) // Access children by name or index (0-based)
SymbolGroupValue operator[](const char *name) const; SymbolGroupValue operator[](const char *name) const;
SymbolGroupValue operator[](unsigned) const; SymbolGroupValue operator[](unsigned) const;
unsigned childCount() const;
SymbolGroupValue parent() const;
// take address and cast to desired (pointer) type // take address and cast to desired (pointer) type
SymbolGroupValue typeCast(const char *type) const; SymbolGroupValue typeCast(const char *type) const;
// take pointer value and cast to desired (pointer) type // take pointer value and cast to desired (pointer) type
SymbolGroupValue pointerTypeCast(const char *type) const; SymbolGroupValue pointerTypeCast(const char *type) const;
// Find a member variable traversing the list of base classes. This useful
// for skipping template base classes of STL containers whose number varies
// by MSVC version.
static SymbolGroupValue findMember(const SymbolGroupValue &start,
const std::string &symbolName);
std::string name() const; std::string name() const;
std::string type() const; std::string type() const;
std::vector<std::string> innerTypes() const { return innerTypesOf(type()); } std::vector<std::string> innerTypes() const { return innerTypesOf(type()); }