1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "containers.h"
35 #include "symbolgroupvalue.h"
36 #include "symbolgroup.h"
37 #include "stringutils.h"
42 typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbolGroupNodePtrVector;
43 typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
44 typedef std::vector<int>::size_type VectorIndexType;
46 // Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
47 static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx)
49 const unsigned pointerSize = SymbolGroupValue::pointerSize();
50 const ULONG allocSize = pointerSize * count;
52 void *data = new unsigned char[allocSize];
53 const HRESULT hr = ctx.dataspaces->ReadVirtual(address, data, allocSize, &bytesRead);
54 if (FAILED(hr) || bytesRead != allocSize) {
62 inline void dumpHexArray(std::ostream &os, const UInt *a, int count)
64 os << std::showbase << std::hex;
65 std::copy(a, a + count, std::ostream_iterator<UInt>(os, ", "));
66 os << std::noshowbase << std::dec;
69 static inline void dump32bitPointerArray(std::ostream &os, const void *a, int count)
71 dumpHexArray(os, reinterpret_cast<const ULONG32 *>(a), count);
74 static inline void dump64bitPointerArray(std::ostream &os, const void *a, int count)
76 dumpHexArray(os, reinterpret_cast<const ULONG64 *>(a), count);
79 // Fix the inner type of containers (that is, make it work smoothly with AddSymbol)
80 // by prefixing it with the module except for well-known types like STL/Qt types
81 static inline std::string fixInnerType(std::string type,
82 const SymbolGroupValue &container)
84 const std::string stripped
85 = SymbolGroupValue::stripConst(SymbolGroupValue::stripClassPrefixes(type));
86 const KnownType kt = knownType(stripped, 0);
87 // Resolve types unless they are POD or pointers to POD (that is, qualify 'Foo' and 'Foo*')
88 const bool needResolve = kt == KT_Unknown || kt == KT_PointerType || !(kt & KT_POD_Type);
89 const std::string fixed = needResolve ?
90 SymbolGroupValue::resolveType(stripped, container.context(), container.module()) :
92 if (SymbolGroupValue::verbose) {
94 dp << "fixInnerType (resolved=" << needResolve << ") '" << type << "' [";
95 formatKnownTypeFlags(dp, kt);
96 dp << "] -> '" << fixed <<"'\n";
101 // Return size from an STL vector (last/first iterators).
102 static inline int msvcStdVectorSize(const SymbolGroupValue &v)
104 if (const SymbolGroupValue myFirstPtrV = v["_Myfirst"]) {
105 if (const SymbolGroupValue myLastPtrV = v["_Mylast"]) {
106 const ULONG64 firstPtr = myFirstPtrV.pointerValue();
107 const ULONG64 lastPtr = myLastPtrV.pointerValue();
108 if (!firstPtr || lastPtr < firstPtr)
110 if (lastPtr == firstPtr)
112 // Subtract the pointers: We need to do the pointer arithmetics ourselves
113 // as we get char *pointers.
114 const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v);
115 const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
118 return static_cast<int>((lastPtr - firstPtr) / size);
124 // Return size of container or -1
125 int containerSize(KnownType kt, SymbolGroupNode *n, const SymbolGroupValueContext &ctx)
128 if ((kt & KT_ContainerType) == 0)
130 const int ct = containerSize(kt, SymbolGroupValue(n, ctx));
135 /*! Determine size of containers \ingroup qtcreatorcdbext */
136 int containerSize(KnownType kt, const SymbolGroupValue &v)
140 if (const SymbolGroupValue base = v[unsigned(0)])
141 return containerSize(KT_QList, base);
144 if (const SymbolGroupValue dV = v["d"]) {
145 if (const SymbolGroupValue beginV = dV["begin"]) {
146 const int begin = beginV.intValue();
147 const int end = dV["end"].intValue();
148 if (begin >= 0 && end >= begin)
157 if (const SymbolGroupValue sizeV = v["d"]["size"])
158 return sizeV.intValue();
161 if (const SymbolGroupValue qHash = v[unsigned(0)])
162 return containerSize(KT_QHash, qHash);
165 if (const SymbolGroupValue qList= v[unsigned(0)])
166 return containerSize(KT_QList, qList);
169 if (const SymbolGroupValue qVector = v[unsigned(0)])
170 return containerSize(KT_QVector, qVector);
173 if (const SymbolGroupValue base = v[unsigned(0)])
174 return containerSize(KT_QHash, base);
177 if (const SymbolGroupValue base = v[unsigned(0)])
178 return containerSize(KT_QMap, base);
181 if (const SymbolGroupValue base = v[unsigned(0)]) {
182 const int msvc10Size = msvcStdVectorSize(base);
186 const int msvc8Size = msvcStdVectorSize(v);
192 if (const SymbolGroupValue sizeV = v["_Mysize"]) // VS 8
193 return sizeV.intValue();
194 if (const SymbolGroupValue sizeV = v[unsigned(0)][unsigned(0)]["_Mysize"]) // VS10
195 return sizeV.intValue();
198 const SymbolGroupValue msvc10sizeV = v[unsigned(0)]["_Mysize"]; // VS10
200 return msvc10sizeV.intValue();
201 const SymbolGroupValue msvc8sizeV = v["_Mysize"]; // VS8
203 return msvc8sizeV.intValue();
207 if (const SymbolGroupValue deque = v[unsigned(0)])
208 return containerSize(KT_StdDeque, deque);
213 if (const SymbolGroupValue baseV = v[unsigned(0)]) {
214 if (const SymbolGroupValue sizeV = baseV["_Mysize"]) // VS 8
215 return sizeV.intValue();
216 if (const SymbolGroupValue sizeV = baseV[unsigned(0)][unsigned(0)]["_Mysize"]) // VS 10
217 return sizeV.intValue();
224 /* Generate a list of children by invoking the functions to obtain the value
225 * and the next link */
226 template <class ValueFunction, class NextFunction>
227 AbstractSymbolGroupNodePtrVector linkedListChildList(SymbolGroupValue headNode,
229 ValueFunction valueFunc,
230 NextFunction nextFunc)
232 AbstractSymbolGroupNodePtrVector rc;
234 for (int i =0; i < count && headNode; i++) {
235 if (const SymbolGroupValue value = valueFunc(headNode)) {
236 rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, value.node()));
237 headNode = nextFunc(headNode);
245 // Helper function for linkedListChildList that returns a member by name
246 class MemberByName : public std::unary_function<const SymbolGroupValue &, SymbolGroupValue>
249 explicit MemberByName(const char *name) : m_name(name) {}
250 SymbolGroupValue operator()(const SymbolGroupValue &v) { return v[m_name]; }
256 // std::list<T>: Dummy head node and then a linked list of "_Next", "_Myval".
257 static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode *n, int count,
258 const SymbolGroupValueContext &ctx)
261 return AbstractSymbolGroupNodePtrVector();
262 const SymbolGroupValue head = SymbolGroupValue(n, ctx)[unsigned(0)][unsigned(0)]["_Myhead"]["_Next"];
264 if (SymbolGroupValue::verbose)
265 DebugPrint() << "std::list failure: " << head;
266 return AbstractSymbolGroupNodePtrVector();
268 return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next"));
271 // QLinkedList<T>: Dummy head node and then a linked list of "n", "t".
272 static inline AbstractSymbolGroupNodePtrVector qLinkedListChildList(SymbolGroupNode *n, int count,
273 const SymbolGroupValueContext &ctx)
276 if (const SymbolGroupValue head = SymbolGroupValue(n, ctx)["e"]["n"])
277 return linkedListChildList(head, count, MemberByName("t"), MemberByName("n"));
278 return AbstractSymbolGroupNodePtrVector();
281 /* Helper for array-type containers:
282 * Add a series of "*(innertype *)0x (address + n * size)" fake child symbols.
283 * for a function generating a sequence of addresses. */
285 template <class AddressFunc>
286 AbstractSymbolGroupNodePtrVector arrayChildList(SymbolGroup *sg, AddressFunc addressFunc,
287 const std::string &module,
288 const std::string &innerType,
291 AbstractSymbolGroupNodePtrVector rc;
294 std::string errorMessage;
296 for (int i = 0; i < count; i++) {
297 const std::string name = SymbolGroupValue::pointedToSymbolName(addressFunc(), innerType);
298 if (SymbolGroupNode *child = sg->addSymbol(module, name, std::string(), &errorMessage)) {
299 rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, child));
301 if (SymbolGroupValue::verbose)
302 DebugPrint() << "addSymbol fails in arrayChildList";
306 if (SymbolGroupValue::verbose)
307 DebugPrint() << "arrayChildList '" << innerType << "' count=" << count << " returns "
308 << rc.size() << " elements";
312 // Helper function for arrayChildList() taking a reference to an address and simply generating
313 // a sequence of address, address + delta, address + 2 * delta...
314 class AddressSequence
317 explicit inline AddressSequence(ULONG64 &address, ULONG delta) : m_address(address), m_delta(delta) {}
318 inline ULONG64 operator()()
320 const ULONG64 rc = m_address;
321 m_address += m_delta;
330 static inline AbstractSymbolGroupNodePtrVector
331 arrayChildList(SymbolGroup *sg, ULONG64 address, const std::string &module,
332 const std::string &innerType, int count)
334 if (const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str()))
335 return arrayChildList(sg, AddressSequence(address, innerTypeSize),
336 module, innerType, count);
337 return AbstractSymbolGroupNodePtrVector();
341 static inline AbstractSymbolGroupNodePtrVector
342 stdVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
345 // std::vector<T>: _Myfirst is a pointer of T*. Get address
346 // element to obtain address.
347 const SymbolGroupValue vec(n, ctx);
348 SymbolGroupValue myFirst = vec[unsigned(0)]["_Myfirst"]; // MSVC2010
350 myFirst = vec["_Myfirst"]; // MSVC2008
352 if (const ULONG64 address = myFirst.pointerValue()) {
353 const std::string firstType = myFirst.type();
354 const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), vec);
355 if (SymbolGroupValue::verbose)
356 DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\'';
357 return arrayChildList(n->symbolGroup(), address, n->module(), innerType, count);
361 return AbstractSymbolGroupNodePtrVector();
364 // Helper for std::deque<>: From the array of deque blocks, read out the values.
365 template<class AddressType>
366 AbstractSymbolGroupNodePtrVector
367 stdDequeChildrenHelper(SymbolGroup *sg,
368 const AddressType *blockArray, ULONG64 blockArraySize,
369 const std::string &module,
370 const std::string &innerType, ULONG64 innerTypeSize,
371 ULONG64 startOffset, ULONG64 dequeSize, int count)
373 AbstractSymbolGroupNodePtrVector rc;
375 std::string errorMessage;
376 // Determine block number and offset in the block array T[][dequeSize]
377 // and create symbol by address.
378 for (int i = 0; i < count; i++) {
379 // see <deque>-header: std::deque<T>::iterator::operator*
380 const ULONG64 offset = startOffset + i;
381 ULONG64 block = offset / dequeSize;
382 if (block >= blockArraySize)
383 block -= blockArraySize;
384 const ULONG64 blockOffset = offset % dequeSize;
385 const ULONG64 address = blockArray[block] + innerTypeSize * blockOffset;
386 if (SymbolGroupNode *n = sg->addSymbol(module, SymbolGroupValue::pointedToSymbolName(address, innerType), std::string(), &errorMessage)) {
387 rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, n));
389 return AbstractSymbolGroupNodePtrVector();
396 static inline AbstractSymbolGroupNodePtrVector
397 stdDequeDirectChildList(const SymbolGroupValue &deque, int count)
400 return AbstractSymbolGroupNodePtrVector();
401 // From MSVC10 on, there is an additional base class
402 const ULONG64 arrayAddress = deque["_Map"].pointerValue();
403 const int startOffset = deque["_Myoff"].intValue();
404 const int mapSize = deque["_Mapsize"].intValue();
405 if (!arrayAddress || startOffset < 0 || mapSize <= 0)
406 return AbstractSymbolGroupNodePtrVector();
407 const std::vector<std::string> innerTypes = deque.innerTypes();
408 if (innerTypes.empty())
409 return AbstractSymbolGroupNodePtrVector();
410 const std::string innerType = fixInnerType(innerTypes.front(), deque);
411 // Get the deque size (block size) which is an unavailable static member
412 // (cf <deque> for the actual expression).
413 const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
415 return AbstractSymbolGroupNodePtrVector();
416 const int dequeSize = innerTypeSize <= 1 ? 16 : innerTypeSize <= 2 ?
417 8 : innerTypeSize <= 4 ? 4 : innerTypeSize <= 8 ? 2 : 1;
418 // Read out map array (pointing to the blocks)
419 void *mapArray = readPointerArray(arrayAddress, mapSize, deque.context());
421 return AbstractSymbolGroupNodePtrVector();
422 const AbstractSymbolGroupNodePtrVector rc = SymbolGroupValue::pointerSize() == 8 ?
423 stdDequeChildrenHelper(deque.node()->symbolGroup(),
424 reinterpret_cast<const ULONG64 *>(mapArray), mapSize,
425 deque.module(), innerType, innerTypeSize, startOffset, dequeSize, count) :
426 stdDequeChildrenHelper(deque.node()->symbolGroup(),
427 reinterpret_cast<const ULONG32 *>(mapArray), mapSize,
428 deque.module(), innerType, innerTypeSize, startOffset, dequeSize, count);
434 static inline AbstractSymbolGroupNodePtrVector
435 stdDequeChildList(const SymbolGroupValue &v, int count)
437 // MSVC10 has a base class. If that fails, try direct (MSVC2008)
438 const AbstractSymbolGroupNodePtrVector msvc10rc = stdDequeDirectChildList(v[unsigned(0)], count);
439 return msvc10rc.empty() ? stdDequeDirectChildList(v, count) : msvc10rc;
442 /* Helper class for std::map<>,std::set<> based on std::__Tree:
443 * We locally rebuild the structure in using instances of below class 'StdMapNode'
444 * with 'left' and 'right' pointers and the values. Reason being that while it is
445 * possible to write the iteration in terms of class SymbolGroupValue, it involves
446 * going back up the tree over the flat node->parent pointers. Doing that in the debugger
447 * sometimes ends up in nirvana, apparently due to it not being able to properly expand it.
448 * StdMapNode has a buildMap() to build a hierarchy from a __Tree value,
449 * begin() to return the first node and next() to iterate. The latter are modeled
450 * after the _Tree::iterator base classes. (_Tree::begin, _Tree::iterator::operator++() */
455 StdMapNode(const StdMapNode &);
456 StdMapNode &operator=(const StdMapNode &);
459 explicit StdMapNode(StdMapNode *p, const SymbolGroupValue &node, const SymbolGroupValue &value);
460 ~StdMapNode() { delete m_left; delete m_right; }
462 // Iterator helpers: Return first and move to next
463 const StdMapNode *begin() const { return StdMapNode::leftMost(this); }
464 static const StdMapNode *next(const StdMapNode *s);
466 const SymbolGroupValue &value() const { return m_value; }
468 // Build the hierarchy
469 static StdMapNode *buildMap(const SymbolGroupValue &n);
472 void debug(std::ostream &os, unsigned depth = 0) const;
475 static StdMapNode *buildMapRecursion(const SymbolGroupValue &n, ULONG64 headAddress, StdMapNode *parent);
476 static const StdMapNode *leftMost(const StdMapNode *n);
478 StdMapNode *const m_parent;
481 const SymbolGroupValue m_node;
482 const SymbolGroupValue m_value;
485 StdMapNode::StdMapNode(StdMapNode *p, const SymbolGroupValue &n, const SymbolGroupValue &v) :
486 m_parent(p), m_left(0), m_right(0), m_node(n), m_value(v)
490 const StdMapNode *StdMapNode::leftMost(const StdMapNode *n)
492 for ( ; n->m_left ; n = n->m_left ) ;
496 const StdMapNode *StdMapNode::next(const StdMapNode *s)
498 if (s->m_right) // If we have a right node, return its left-most
499 return StdMapNode::leftMost(s->m_right);
500 do { // Climb looking for 'right' subtree, that is, we are left of it
501 StdMapNode *parent = s->m_parent;
502 if (!parent || parent->m_right != s)
509 StdMapNode *StdMapNode::buildMapRecursion(const SymbolGroupValue &n, ULONG64 headAddress, StdMapNode *parent)
511 const SymbolGroupValue value = n["_Myval"];
514 StdMapNode *node = new StdMapNode(parent, n, value);
515 // Get left and right nodes. A node pointing to head terminates the recursion
516 if (const SymbolGroupValue left = n["_Left"])
517 if (const ULONG64 leftAddr = left.pointerValue())
518 if (leftAddr != headAddress)
519 node->m_left = buildMapRecursion(left, headAddress, node);
520 if (const SymbolGroupValue right = n["_Right"])
521 if (const ULONG64 rightAddr = right.pointerValue())
522 if (rightAddr != headAddress)
523 node->m_right = buildMapRecursion(right, headAddress, node);
527 StdMapNode *StdMapNode::buildMap(const SymbolGroupValue &n)
529 // Goto root of tree (see _Tree::_Root())
530 if (const SymbolGroupValue head = n["_Myhead"])
531 if (const ULONG64 headAddress = head.pointerValue())
532 return buildMapRecursion(head["_Parent"], headAddress, 0);
536 static inline void indentStream(std::ostream &os, unsigned indent)
538 for (unsigned i = 0; i < indent; i++)
542 // Debugging helper for a SymbolGroupValue containing a __Tree::node of
543 // a map (assuming a std::pair inside).
544 static inline void debugMSVC2010MapNode(const SymbolGroupValue &n, std::ostream &os, unsigned indent = 0)
546 indentStream(os, indent);
547 os << "Node at " << std::hex << std::showbase << n.address()
548 << std::dec << std::noshowbase
549 << " Value='" << wStringToString(n.value()) << "', Parent=" << wStringToString(n["_Parent"].value())
550 << ", Left=" << wStringToString(n["_Left"].value())
551 << ", Right=" << wStringToString(n["_Right"].value())
552 << ", nil='" << wStringToString(n["_Isnil"].value());
553 if (const SymbolGroupValue pairBase = n["_Myval"][unsigned(0)]) {
554 os << "', key='" << wStringToString(pairBase["first"].value())
555 << "', value='" << wStringToString(pairBase["second"].value())
558 os << "', key='" << wStringToString(n["_Myval"].value()) << '\'';
563 void StdMapNode::debug(std::ostream &os, unsigned depth) const
565 indentStream(os, 2 * depth);
566 os << "StdNode=" << this << " Left=" << m_left << " Right=" << m_right << '\n';
567 debugMSVC2010MapNode(m_node, os, 2 * depth);
569 m_left->debug(os, depth + 1);
571 m_right->debug(os, depth + 1);
574 // Helper for std::map<>,std::set<> based on std::__Tree:
575 // Return the list of children (pair for maps, direct children for set)
576 static inline SymbolGroupValueVector
577 stdTreeChildList(const SymbolGroupValue &tree, int count, bool *isMSVC2010In = 0)
580 return SymbolGroupValueVector();
581 // MSVC2010: "class _Tree : public _Tree_val: public _Tree_nod".
582 // MSVC2008: Direct class
583 const int size = tree[unsigned(0)][unsigned(0)]["_Mysize"].intValue();
584 const bool isMSVC2010 = size >= 0 && size <= count; // Count may be limited
586 *isMSVC2010In = isMSVC2010;
587 const SymbolGroupValue treeNode = isMSVC2010 ? tree[unsigned(0)][unsigned(0)] : tree;
589 return SymbolGroupValueVector();
590 // Build the tree and iterate it.
591 const StdMapNode *nodeTree = StdMapNode::buildMap(treeNode);
593 return SymbolGroupValueVector();
594 SymbolGroupValueVector rc;
597 for (const StdMapNode *n = nodeTree->begin() ; n && i < count; n = StdMapNode::next(n), i++)
598 rc.push_back(n->value());
600 if (rc.size() != count)
601 return SymbolGroupValueVector();
605 // std::set<>: Children directly contained in list
606 static inline AbstractSymbolGroupNodePtrVector
607 stdSetChildList(const SymbolGroupValue &set, int count)
609 const SymbolGroupValueVector children = stdTreeChildList(set[unsigned(0)], count);
610 if (int(children.size()) != count)
611 return AbstractSymbolGroupNodePtrVector();
612 AbstractSymbolGroupNodePtrVector rc;
614 for (int i = 0; i < count; i++)
615 rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, children.at(i).node()));
619 // std::map<K,V>: A list of std::pair<K,V> (derived from std::pair_base<K,V>)
620 static inline AbstractSymbolGroupNodePtrVector
621 stdMapChildList(const SymbolGroupValue &map, int count)
623 bool isMSVC2010 = true;
624 const SymbolGroupValueVector children = stdTreeChildList(map[unsigned(0)], count, &isMSVC2010);
625 if (int(children.size()) != count)
626 return AbstractSymbolGroupNodePtrVector();
627 AbstractSymbolGroupNodePtrVector rc;
629 for (int i = 0; i < count; i++) {
630 // MSVC2010 introduces a std::pair_base.
631 const SymbolGroupValue pairBase = isMSVC2010?
632 children.at(i)[unsigned(0)] : children.at(i);
633 const SymbolGroupValue key = pairBase["first"];
634 const SymbolGroupValue value = pairBase["second"];
636 rc.push_back(MapNodeSymbolGroupNode::create(i, pairBase.address(),
638 key.node(), value.node()));
640 return AbstractSymbolGroupNodePtrVector();
647 static inline AbstractSymbolGroupNodePtrVector
648 qVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
651 // QVector<T>: p/array is declared as array of T. Dereference first
652 // element to obtain address.
653 const SymbolGroupValue vec(n, ctx);
654 if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) {
655 if (const ULONG64 arrayAddress = firstElementV.address()) {
656 const std::string fixedInnerType = fixInnerType(firstElementV.type(), vec);
657 return arrayChildList(n->symbolGroup(), arrayAddress, n->module(), fixedInnerType, count);
661 return AbstractSymbolGroupNodePtrVector();
664 // Helper function for arrayChildList() for use with QLists of large types that are an
665 // array of pointers to allocated elements: Generate a pointer sequence by reading out the array.
666 template <class AddressType>
667 class AddressArraySequence
670 explicit inline AddressArraySequence(const AddressType *array) : m_array(array) {}
671 inline ULONG64 operator()() { return *m_array++; }
674 const AddressType *m_array;
678 static inline AbstractSymbolGroupNodePtrVector
679 qListChildList(const SymbolGroupValue &v, int count)
681 // QList<T>: d/array is declared as array of void *[]. Dereference first
682 // element to obtain address.
684 return AbstractSymbolGroupNodePtrVector();
685 const SymbolGroupValue dV = v["d"];
687 return AbstractSymbolGroupNodePtrVector();
688 const int begin = dV["begin"].intValue();
690 return AbstractSymbolGroupNodePtrVector();
691 const SymbolGroupValue firstElementV = dV["array"][unsigned(0)];
693 return AbstractSymbolGroupNodePtrVector();
694 ULONG64 arrayAddress = firstElementV.address();
696 return AbstractSymbolGroupNodePtrVector();
697 const std::vector<std::string> innerTypes = v.innerTypes();
698 if (innerTypes.size() != 1)
699 return AbstractSymbolGroupNodePtrVector();
700 const std::string innerType = fixInnerType(innerTypes.front(), v);
701 const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
702 if (SymbolGroupValue::verbose)
703 DebugPrint() << "QList " << v.name() << " inner type " << innerType << ' ' << innerTypeSize;
705 return AbstractSymbolGroupNodePtrVector();
707 * 1) An array of 'void *[]' where T values are coerced into the elements for
708 * POD/pointer types and small, movable or primitive Qt types. That is, smaller
709 * elements are also aligned at 'void *' boundaries.
710 * 2) An array of 'T *[]' (pointer to allocated instances) for anything else
711 * (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic)
712 * isStatic depends on QTypeInfo specializations and hardcoded flags for types. */
713 const unsigned pointerSize = SymbolGroupValue::pointerSize();
714 arrayAddress += begin * pointerSize;
715 if (SymbolGroupValue::isPointerType(innerType)) // Quick check: Any pointer is T[]
716 return arrayChildList(v.node()->symbolGroup(),
717 AddressSequence(arrayAddress, pointerSize),
718 v.module(), innerType, count);
719 // Check condition for large||static.
720 bool isLargeOrStatic = innerTypeSize > pointerSize;
721 if (!isLargeOrStatic && !SymbolGroupValue::isPointerType(innerType)) {
722 const KnownType kt = knownType(innerType, false); // inner type, no 'class ' prefix.
723 if (kt != KT_Unknown && !(kt & (KT_POD_Type|KT_Qt_PrimitiveType|KT_Qt_MovableType)))
724 isLargeOrStatic = true;
726 if (SymbolGroupValue::verbose)
727 DebugPrint() << "isLargeOrStatic " << isLargeOrStatic;
728 if (isLargeOrStatic) {
729 // Retrieve the pointer array ourselves to avoid having to evaluate '*(class foo**)'
730 if (void *data = readPointerArray(arrayAddress, count, v.context())) {
731 // Generate sequence of addresses from pointer array
732 const AbstractSymbolGroupNodePtrVector rc = pointerSize == 8 ?
733 arrayChildList(v.node()->symbolGroup(),
734 AddressArraySequence<ULONG64>(reinterpret_cast<const ULONG64 *>(data)),
735 v.module(), innerType, count) :
736 arrayChildList(v.node()->symbolGroup(), AddressArraySequence<ULONG32>(reinterpret_cast<const ULONG32 *>(data)),
737 v.module(), innerType, count);
741 return AbstractSymbolGroupNodePtrVector();
743 return arrayChildList(v.node()->symbolGroup(),
744 AddressSequence(arrayAddress, pointerSize),
745 v.module(), innerType, count);
748 // Return the list of buckets of a 'QHash<>' as 'QHashData::Node *' values from
749 // the list of addresses passed in
750 template<class AddressType>
751 SymbolGroupValueVector hashBuckets(SymbolGroup *sg, const std::string &hashNodeType,
752 const AddressType *pointerArray,
755 const std::string &module,
756 const SymbolGroupValueContext &ctx)
758 SymbolGroupValueVector rc;
759 rc.reserve(numBuckets);
760 const AddressType *end = pointerArray + numBuckets;
761 std::string errorMessage;
762 // Skip 'e' special values as they are used as placeholder for reserve(d)
763 // empty array elements.
764 for (const AddressType *p = pointerArray; p < end; p++) {
766 const std::string name = SymbolGroupValue::pointedToSymbolName(*p, hashNodeType);
767 if (SymbolGroupNode *child = sg->addSymbol(module, name, std::string(), &errorMessage)) {
768 rc.push_back(SymbolGroupValue(child, ctx));
770 return std::vector<SymbolGroupValue>();
778 // Return the node type of a QHash/QMap:
779 // "class QHash<K,V>[ *]" -> [struct] "QtCored4!QHashNode<K,V>";
780 static inline std::string qHashNodeType(const SymbolGroupValue &v,
781 const char *nodeType)
783 std::string qHashType = SymbolGroupValue::stripPointerType(v.type());
784 const std::string::size_type pos = qHashType.find('<');
785 if (pos != std::string::npos)
786 qHashType.insert(pos, nodeType);
787 // A map node must be qualified with the current module and
788 // the Qt namespace (particularly QMapNode, QHashNodes work also for
789 // the unqualified case).
790 const QtInfo &qtInfo = QtInfo::get(v.context());
791 const std::string currentModule = v.module();
792 return QtInfo::prependModuleAndNameSpace(qHashType, currentModule, qtInfo.nameSpace);
795 // Return up to count nodes of type "QHashNode<K,V>" of a "class QHash<K,V>".
796 SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
797 VectorIndexType count)
800 return SymbolGroupValueVector();
801 const SymbolGroupValue hashData = v["d"];
802 // 'e' is used as a special value to indicate empty hash buckets in the array.
803 const ULONG64 ePtr = v["e"].pointerValue();
804 if (SymbolGroupValue::verbose)
805 DebugPrint() << v << " Count=" << count << ",ePtr=0x" << std::hex << ePtr;
806 if (!hashData || !ePtr)
807 return SymbolGroupValueVector();
808 // Retrieve the array of buckets of 'd'
809 const int numBuckets = hashData["numBuckets"].intValue();
810 const ULONG64 bucketArray = hashData["buckets"].pointerValue();
811 if (numBuckets <= 0 || !bucketArray)
812 return SymbolGroupValueVector();
813 void *bucketPointers = readPointerArray(bucketArray, numBuckets, v.context());
815 return SymbolGroupValueVector();
816 // Get list of buckets (starting elements of 'QHashData::Node')
817 const std::string dummyNodeType = QtInfo::get(v.context()).prependQtCoreModule("QHashData::Node");
818 const SymbolGroupValueVector buckets = SymbolGroupValue::pointerSize() == 8 ?
819 hashBuckets(v.node()->symbolGroup(), dummyNodeType,
820 reinterpret_cast<const ULONG64 *>(bucketPointers), numBuckets,
821 ePtr, v.module(), v.context()) :
822 hashBuckets(v.node()->symbolGroup(), dummyNodeType,
823 reinterpret_cast<const ULONG32 *>(bucketPointers), numBuckets,
824 ULONG32(ePtr), v.module(), v.context());
825 delete [] bucketPointers ;
826 // Generate the list 'QHashData::Node *' by iterating over the linked list of
827 // nodes starting at each bucket. Using the 'QHashData::Node *' instead of
828 // the 'QHashNode<K,T>' is much faster. Each list has a trailing, unused
829 // dummy element. The initial element as such is skipped due to the pointer/value
830 // duality (since its 'next' element is identical to it when using typecast<> later on).
831 SymbolGroupValueVector dummyNodeList;
832 dummyNodeList.reserve(count);
833 bool notEnough = true;
834 const SymbolGroupValueVector::const_iterator ncend = buckets.end();
835 for (SymbolGroupValueVector::const_iterator it = buckets.begin(); notEnough && it != ncend; ++it) {
836 for (SymbolGroupValue l = *it; notEnough && l ; ) {
837 const SymbolGroupValue next = l["next"];
838 if (next && next.pointerValue()) { // Stop at trailing dummy element
839 dummyNodeList.push_back(next);
840 if (dummyNodeList.size() >= count) // Stop at maximum count
842 if (SymbolGroupValue::verbose > 1)
843 DebugPrint() << '#' << (dummyNodeList.size() - 1) << " l=" << l << ",next=" << next;
850 // Finally convert them into real nodes 'QHashNode<K,V> (potentially expensive)
851 const std::string nodeType = qHashNodeType(v, "Node");
852 if (SymbolGroupValue::verbose)
853 DebugPrint() << "Converting into " << nodeType;
854 SymbolGroupValueVector nodeList;
855 nodeList.reserve(count);
856 const SymbolGroupValueVector::const_iterator dcend = dummyNodeList.end();
857 for (SymbolGroupValueVector::const_iterator it = dummyNodeList.begin(); it != dcend; ++it) {
858 if (const SymbolGroupValue n = (*it).typeCast(nodeType.c_str())) {
859 nodeList.push_back(n);
861 return SymbolGroupValueVector();
867 // QSet<>: Contains a 'QHash<key, QHashDummyValue>' as member 'q_hash'.
868 // Just dump the keys as an array.
869 static inline AbstractSymbolGroupNodePtrVector
870 qSetChildList(const SymbolGroupValue &v, int count)
872 const SymbolGroupValue qHash = v["q_hash"];
873 AbstractSymbolGroupNodePtrVector rc;
874 if (!count || !qHash)
876 const SymbolGroupValueVector nodes = qHashNodes(qHash, count);
877 if (nodes.size() != VectorIndexType(count))
880 for (int i = 0; i < count; i++) {
881 if (const SymbolGroupValue key = nodes.at(i)["key"]) {
882 rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, key.node()));
884 return AbstractSymbolGroupNodePtrVector();
890 // QHash<>: Add with fake map nodes.
891 static inline AbstractSymbolGroupNodePtrVector
892 qHashChildList(const SymbolGroupValue &v, int count)
894 AbstractSymbolGroupNodePtrVector rc;
897 const SymbolGroupValueVector nodes = qHashNodes(v, count);
898 if (nodes.size() != count)
901 for (int i = 0; i < count; i++) {
902 const SymbolGroupValue &mapNode = nodes.at(i);
903 const SymbolGroupValue key = mapNode["key"];
904 const SymbolGroupValue value = mapNode["value"];
906 return AbstractSymbolGroupNodePtrVector();
907 rc.push_back(MapNodeSymbolGroupNode::create(i, mapNode.address(),
908 mapNode.type(), key.node(), value.node()));
913 // QMap<>: Return the list of QMapData::Node
914 static inline SymbolGroupValueVector qMapNodes(const SymbolGroupValue &v, VectorIndexType count)
916 const SymbolGroupValue e = v["e"];
917 const ULONG64 ePtr = e.pointerValue();
918 if (SymbolGroupValue::verbose)
919 DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
921 return SymbolGroupValueVector();
922 if (SymbolGroupValue::verbose)
923 DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
924 SymbolGroupValueVector rc;
926 SymbolGroupValue n = e["forward"][unsigned(0)];
927 for (VectorIndexType i = 0; i < count && n && n.pointerValue() != ePtr; i++) {
929 n = n["forward"][unsigned(0)];
934 // QMap<>: Add with fake map nodes.
935 static inline AbstractSymbolGroupNodePtrVector
936 qMapChildList(const SymbolGroupValue &v, VectorIndexType count)
938 if (SymbolGroupValue::verbose)
939 DebugPrint() << v.type() << "," << count;
942 return AbstractSymbolGroupNodePtrVector();
943 // Get node type: 'class namespace::QMap<K,T>'
944 // ->'QtCored4!namespace::QMapNode<K,T>'
945 // Note: Any types QMapNode<> will not be found without modules!
946 const std::string mapNodeType = qHashNodeType(v, "Node");
947 const std::string mapPayloadNodeType = qHashNodeType(v, "PayloadNode");
948 // Calculate the offset needed (see QMap::concrete() used by the iterator).
949 const unsigned payloadNodeSize = SymbolGroupValue::sizeOf(mapPayloadNodeType.c_str());
950 if (SymbolGroupValue::verbose) {
951 DebugPrint() << v.type() << "," << mapNodeType << ':'
952 << mapPayloadNodeType << ':' << payloadNodeSize
953 << ", pointerSize=" << SymbolGroupValue::pointerSize();
955 if (!payloadNodeSize)
956 return AbstractSymbolGroupNodePtrVector();
957 const ULONG64 payLoad = payloadNodeSize - SymbolGroupValue::pointerSize();
958 // Get the value offset. Manually determine the alignment to be able
959 // to retrieve key/value without having to deal with QMapNode<> (see below).
960 // Subtract the 2 trailing pointers of the node.
961 const std::vector<std::string> innerTypes = v.innerTypes();
962 if (innerTypes.size() != 2u)
963 return AbstractSymbolGroupNodePtrVector();
964 const std::string keyType = fixInnerType(innerTypes.front(), v);
965 const std::string valueType = fixInnerType(innerTypes.at(1), v);
966 const unsigned valueSize = SymbolGroupValue::sizeOf(valueType.c_str());
967 const unsigned valueOffset = SymbolGroupValue::fieldOffset(mapNodeType.c_str(), "value");
968 if (SymbolGroupValue::verbose)
969 DebugPrint() << "Payload=" << payLoad << ",valueOffset=" << valueOffset << ','
970 << innerTypes.front() << ',' << innerTypes.back() << ':' << valueSize;
971 if (!valueOffset || !valueSize)
972 return AbstractSymbolGroupNodePtrVector();
974 const SymbolGroupValueVector childNodes = qMapNodes(v, count);
975 if (SymbolGroupValue::verbose)
976 DebugPrint() << "children: " << childNodes.size() << " of " << count;
977 // Deep expansion of the forward[0] sometimes fails. In that case,
978 // take what we can get.
979 if (childNodes.size() != count)
980 count = childNodes.size();
981 // The correct way of doing this would be to construct additional symbols
982 // '*(QMapNode<K,V> *)(node_address)'. However, when doing this as of
983 // 'CDB 6.12.0002.633' (21.12.2010) IDebugSymbolGroup::AddSymbol()
984 // just fails, returning DEBUG_ANY_ID without actually doing something. So,
985 // we circumvent the map nodes and directly create key and values at their addresses.
986 AbstractSymbolGroupNodePtrVector rc;
988 std::string errorMessage;
989 SymbolGroup *sg = v.node()->symbolGroup();
990 for (VectorIndexType i = 0; i < count ; i++) {
991 const ULONG64 nodePtr = childNodes.at(i).pointerValue();
993 return AbstractSymbolGroupNodePtrVector();
994 const ULONG64 keyAddress = nodePtr - payLoad;
995 const std::string keyExp = SymbolGroupValue::pointedToSymbolName(keyAddress, keyType);
996 const std::string valueExp = SymbolGroupValue::pointedToSymbolName(keyAddress + valueOffset, valueType);
997 if (SymbolGroupValue::verbose) {
998 DebugPrint() << '#' << i << '/' << count << ' ' << std::hex << ",node=0x" << nodePtr <<
999 ',' <<keyExp << ',' << valueExp;
1002 SymbolGroupNode *keyNode = sg->addSymbol(v.module(), keyExp, std::string(), &errorMessage);
1003 SymbolGroupNode *valueNode = sg->addSymbol(v.module(), valueExp, std::string(), &errorMessage);
1004 if (!keyNode || !valueNode)
1005 return AbstractSymbolGroupNodePtrVector();
1006 rc.push_back(MapNodeSymbolGroupNode::create(int(i), keyAddress,
1007 mapNodeType, keyNode, valueNode));
1012 /*! Determine children of containers \ingroup qtcreatorcdbext */
1013 AbstractSymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int type,
1014 int size, const SymbolGroupValueContext &ctx)
1016 if (SymbolGroupValue::verbose) {
1018 dp << "containerChildren " << node->name() << '/' << node->iName() << '/' << node->type()
1019 << " at 0x" << std::hex << node->address() << std::dec
1020 << " count=" << size << ",knowntype=" << type << " [";
1021 formatKnownTypeFlags(dp, static_cast<KnownType>(type));
1025 return AbstractSymbolGroupNodePtrVector();
1030 return qVectorChildList(node, size, ctx);
1032 return stdVectorChildList(node, size, ctx);
1033 case KT_QLinkedList:
1034 return qLinkedListChildList(node, size, ctx);
1036 return qListChildList(SymbolGroupValue(node, ctx), size);
1038 if (const SymbolGroupValue qList = SymbolGroupValue(node, ctx)[unsigned(0)])
1039 return qListChildList(qList, size);
1042 if (const SymbolGroupValue qVector = SymbolGroupValue(node, ctx)[unsigned(0)])
1043 return qVectorChildList(qVector.node(), size, ctx);
1046 return qHashChildList(SymbolGroupValue(node, ctx), size);
1048 if (const SymbolGroupValue hash = SymbolGroupValue(node, ctx)[unsigned(0)])
1049 return qHashChildList(hash, size);
1052 return qSetChildList(SymbolGroupValue(node, ctx), size);
1054 return qMapChildList(SymbolGroupValue(node, ctx), size);
1056 if (const SymbolGroupValue qmap = SymbolGroupValue(node, ctx)[unsigned(0)])
1057 return qMapChildList(qmap, size);
1059 case KT_QStringList:
1060 if (const SymbolGroupValue qList = SymbolGroupValue(node, ctx)[unsigned(0)])
1061 return qListChildList(qList, size);
1064 return stdListChildList(node, size , ctx);
1066 return stdDequeChildList(SymbolGroupValue(node, ctx), size);
1068 if (const SymbolGroupValue deque = SymbolGroupValue(node, ctx)[unsigned(0)])
1069 return stdDequeChildList(deque, size);
1072 return stdSetChildList(SymbolGroupValue(node, ctx), size);
1074 case KT_StdMultiMap:
1075 return stdMapChildList(SymbolGroupValue(node, ctx), size);
1077 return AbstractSymbolGroupNodePtrVector();