containers.cpp 48.3 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29 30 31 32 33 34

#include "containers.h"
#include "symbolgroupvalue.h"
#include "symbolgroup.h"
#include "stringutils.h"

35
#include <functional>
36
#include <iterator>
37

38
typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbolGroupNodePtrVector;
39 40
typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
typedef std::vector<int>::size_type VectorIndexType;
41

42 43
// Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx)
44
{
45 46 47 48 49 50 51 52 53 54
    const unsigned pointerSize = SymbolGroupValue::pointerSize();
    const ULONG allocSize = pointerSize * count;
    ULONG bytesRead = 0;
    void *data = new unsigned char[allocSize];
    const HRESULT hr = ctx.dataspaces->ReadVirtual(address, data, allocSize, &bytesRead);
    if (FAILED(hr) || bytesRead != allocSize) {
        delete [] data;
        return 0;
    }
    return data;
55 56
}

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
template <class UInt>
inline void dumpHexArray(std::ostream &os, const UInt *a, int count)
{
    os << std::showbase << std::hex;
    std::copy(a, a + count, std::ostream_iterator<UInt>(os, ", "));
    os << std::noshowbase << std::dec;
}

static inline void dump32bitPointerArray(std::ostream &os, const void *a, int count)
{
    dumpHexArray(os, reinterpret_cast<const ULONG32 *>(a), count);
}

static inline void dump64bitPointerArray(std::ostream &os, const void *a, int count)
{
    dumpHexArray(os, reinterpret_cast<const ULONG64 *>(a), count);
}

75 76
// 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
77 78
static inline std::string fixInnerType(std::string type,
                                       const SymbolGroupValue &container)
79
{
80
    std::string stripped
81
        = SymbolGroupValue::stripConst(SymbolGroupValue::stripClassPrefixes(type));
82 83 84 85 86 87 88

    // Unfortunately the cdb can not handle the vc exclusiv 64 bit integer
    // "__int64" but works fine with "int64", so we have to strip down "__"
    const size_t __int64pos = stripped.find("__int64");
    if (__int64pos != std::string::npos)
        stripped.erase(__int64pos, 2);

89 90 91 92
    const KnownType kt = knownType(stripped, 0);
    // Resolve types unless they are POD or pointers to POD (that is, qualify 'Foo' and 'Foo*')
    const bool needResolve = kt == KT_Unknown || kt ==  KT_PointerType || !(kt & KT_POD_Type);
    const std::string fixed = needResolve ?
93
                SymbolGroupValue::resolveType(stripped, container.context(), container.module()) :
94 95 96 97 98 99 100 101
                stripped;
    if (SymbolGroupValue::verbose) {
        DebugPrint dp;
        dp << "fixInnerType (resolved=" << needResolve << ") '" << type << "' [";
        formatKnownTypeFlags(dp, kt);
        dp << "] -> '" << fixed <<"'\n";
    }
    return fixed;
102 103
}

104 105 106
// Return size from an STL vector (last/first iterators).
static inline int msvcStdVectorSize(const SymbolGroupValue &v)
{
107 108 109
    // MSVC2012 has 2 base classes, MSVC2010 1, MSVC2008 none
    if (const SymbolGroupValue myFirstPtrV = SymbolGroupValue::findMember(v, "_Myfirst")) {
        if (const SymbolGroupValue myLastPtrV = myFirstPtrV.parent()["_Mylast"]) {
110 111 112 113 114 115 116 117
            const ULONG64 firstPtr = myFirstPtrV.pointerValue();
            const ULONG64 lastPtr = myLastPtrV.pointerValue();
            if (!firstPtr || lastPtr < firstPtr)
                return -1;
            if (lastPtr == firstPtr)
                return 0;
            // Subtract the pointers: We need to do the pointer arithmetics ourselves
            // as we get char *pointers.
118
            const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(myFirstPtrV.type()), v);
119 120 121 122 123 124 125 126 127
            const size_t size = SymbolGroupValue::sizeOf(innerType.c_str());
            if (size == 0)
                return -1;
            return static_cast<int>((lastPtr - firstPtr) / size);
        }
    }
    return -1;
}

128 129 130 131 132 133 134 135 136 137 138
// Return size of container or -1
int containerSize(KnownType kt, SymbolGroupNode *n, const SymbolGroupValueContext &ctx)
{
    QTC_TRACE_IN
    if ((kt & KT_ContainerType) == 0)
        return -1;
    const int ct = containerSize(kt, SymbolGroupValue(n, ctx));
    QTC_TRACE_OUT
    return ct;
}

139
/*! Determine size of containers \ingroup qtcreatorcdbext */
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
int containerSize(KnownType kt, const SymbolGroupValue &v)
{
    switch (kt) {
    case KT_QStringList:
        if (const SymbolGroupValue base = v[unsigned(0)])
            return containerSize(KT_QList, base);
        break;
    case KT_QList:
        if (const SymbolGroupValue dV = v["d"]) {
            if (const SymbolGroupValue beginV = dV["begin"]) {
                const int begin = beginV.intValue();
                const int end = dV["end"].intValue();
                if (begin >= 0 && end >= begin)
                    return end - begin;
            }
        }
        break;
    case KT_QLinkedList:
    case KT_QHash:
        if (const SymbolGroupValue sizeV = v["d"]["size"])
            return sizeV.intValue();
        break;
162 163 164 165 166 167 168 169 170 171
    case KT_QMap:
    case KT_QVector: {
        // Inheritance from QVectorTypedData, QMapData<> in Qt 5.
        const SymbolGroupValue sizeV =
            QtInfo::get(v.context()).version >= 5 ?
            v["d"][unsigned(0)]["size"] : v["d"]["size"];
        if (sizeV)
            return sizeV.intValue();
    }
        break;
172 173 174 175
    case KT_QMultiHash:
        if (const SymbolGroupValue qHash = v[unsigned(0)])
            return containerSize(KT_QHash, qHash);
        break;
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
    case KT_QQueue:
        if (const SymbolGroupValue qList= v[unsigned(0)])
            return containerSize(KT_QList, qList);
        break;
    case KT_QStack:
        if (const SymbolGroupValue qVector = v[unsigned(0)])
            return containerSize(KT_QVector, qVector);
        break;
    case KT_QSet:
        if (const SymbolGroupValue base = v[unsigned(0)])
            return containerSize(KT_QHash, base);
        break;
    case KT_QMultiMap:
        if (const SymbolGroupValue base = v[unsigned(0)])
            return containerSize(KT_QMap, base);
        break;
192 193 194 195 196 197
    case KT_StdVector:
        return msvcStdVectorSize(v);
    case KT_StdDeque: // MSVC2012 has many base classes, MSVC2010 1, MSVC2008 none
    case KT_StdSet:
    case KT_StdMap:
    case KT_StdMultiMap:
198
    case KT_StdList:
199 200
        if (const SymbolGroupValue size = SymbolGroupValue::findMember(v, "_Mysize"))
            return size.intValue();
201 202 203 204 205 206 207 208 209 210 211 212
        break;
    case KT_StdStack:
        if (const SymbolGroupValue deque =  v[unsigned(0)])
            return containerSize(KT_StdDeque, deque);
        break;
    }
    return -1;
}

/* Generate a list of children by invoking the functions to obtain the value
 * and the next link */
template <class ValueFunction, class NextFunction>
213 214 215 216
AbstractSymbolGroupNodePtrVector linkedListChildList(SymbolGroupValue headNode,
                                                     int count,
                                                     ValueFunction valueFunc,
                                                     NextFunction nextFunc)
217
{
218
    AbstractSymbolGroupNodePtrVector rc;
219 220 221
    rc.reserve(count);
    for (int i =0; i < count && headNode; i++) {
        if (const SymbolGroupValue value = valueFunc(headNode)) {
222
            rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, value.node()));
223 224 225 226 227 228 229 230 231
            headNode = nextFunc(headNode);
        } else {
            break;
        }
    }
    return rc;
}

// Helper function for linkedListChildList that returns a member by name
232 233
class MemberByName : public std::unary_function<const SymbolGroupValue &, SymbolGroupValue>
{
234 235 236 237 238 239 240 241
public:
    explicit MemberByName(const char *name) : m_name(name) {}
    SymbolGroupValue operator()(const SymbolGroupValue &v) { return v[m_name]; }

private:
    const char *m_name;
};

242
// std::list<T>: Skip dummy head node and then a linked list of "_Next", "_Myval".
243
static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode *n, int count,
244 245
                                                        const SymbolGroupValueContext &ctx)
{
246 247
    if (!count)
        return AbstractSymbolGroupNodePtrVector();
248 249 250 251 252 253
    const SymbolGroupValue head = SymbolGroupValue::findMember(SymbolGroupValue(n, ctx), "_Myhead")["_Next"];
    if (head)
        return linkedListChildList(head, count, MemberByName("_Myval"), MemberByName("_Next"));
    if (SymbolGroupValue::verbose)
        DebugPrint() << "std::list failure: " << head;
    return AbstractSymbolGroupNodePtrVector();
254 255 256
}

// QLinkedList<T>: Dummy head node and then a linked list of "n", "t".
257
static inline AbstractSymbolGroupNodePtrVector qLinkedListChildList(SymbolGroupNode *n, int count,
258 259 260 261 262
                                                        const SymbolGroupValueContext &ctx)
{
    if (count)
        if (const SymbolGroupValue head = SymbolGroupValue(n, ctx)["e"]["n"])
            return linkedListChildList(head, count, MemberByName("t"), MemberByName("n"));
263
    return AbstractSymbolGroupNodePtrVector();
264 265
}

266
/* Helper for array-type containers:
267 268
 * Add a series of "*(innertype *)0x (address + n * size)" fake child symbols.
 * for a function generating a sequence of addresses. */
269

270
template <class AddressFunc>
271
AbstractSymbolGroupNodePtrVector arrayChildList(SymbolGroup *sg, AddressFunc addressFunc,
272 273 274
                                                const std::string &module,
                                                const std::string &innerType,
                                                int count)
275
{
276
    AbstractSymbolGroupNodePtrVector rc;
277
    if (!count)
278 279 280
        return rc;
    std::string errorMessage;
    rc.reserve(count);
281
    for (int i = 0; i < count; i++) {
282
        const std::string name = SymbolGroupValue::pointedToSymbolName(addressFunc(), innerType);
283
        if (SymbolGroupNode *child = sg->addSymbol(module, name, std::string(), &errorMessage)) {
284
            rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, child));
285
        } else {
286 287
            if (SymbolGroupValue::verbose)
                DebugPrint() << "addSymbol fails in arrayChildList";
288 289 290
            break;
        }
    }
291 292 293
    if (SymbolGroupValue::verbose)
        DebugPrint() << "arrayChildList '" << innerType << "' count=" << count << " returns "
                     << rc.size() << " elements";
294 295 296
    return rc;
}

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
// Helper function for arrayChildList() taking a reference to an address and simply generating
// a sequence of address, address + delta, address + 2 * delta...
class AddressSequence
{
public:
    explicit inline AddressSequence(ULONG64 &address, ULONG delta) : m_address(address), m_delta(delta) {}
    inline ULONG64 operator()()
    {
        const ULONG64 rc = m_address;
        m_address += m_delta;
        return rc;
    }

private:
    ULONG64 &m_address;
    const ULONG m_delta;
};

315 316 317
static inline AbstractSymbolGroupNodePtrVector
    arrayChildList(SymbolGroup *sg, ULONG64 address, const std::string &module,
                   const std::string &innerType, int count)
318 319
{
    if (const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str()))
320
        return arrayChildList(sg, AddressSequence(address, innerTypeSize),
321
                              module, innerType, count);
322
    return AbstractSymbolGroupNodePtrVector();
323 324
}

325
// std::vector<T>
326
static inline AbstractSymbolGroupNodePtrVector
327 328
    stdVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
{
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
    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
    // element to obtain address.
    const ULONG64 address = myFirst.pointerValue();
    if (!address)
        return AbstractSymbolGroupNodePtrVector();
    const std::string firstType = myFirst.type();
    const std::string innerType = fixInnerType(SymbolGroupValue::stripPointerType(firstType), vec);
    if (SymbolGroupValue::verbose)
        DebugPrint() << n->name() << " inner type: '" << innerType << "' from '" << firstType << '\'';
    return arrayChildList(n->symbolGroup(), address, n->module(), innerType, count);
346 347
}

348 349 350 351 352
// Helper for std::deque<>: From the array of deque blocks, read out the values.
template<class AddressType>
AbstractSymbolGroupNodePtrVector
    stdDequeChildrenHelper(SymbolGroup *sg,
                           const AddressType *blockArray, ULONG64 blockArraySize,
353
                           const std::string &module,
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
                           const std::string &innerType, ULONG64 innerTypeSize,
                           ULONG64 startOffset, ULONG64 dequeSize, int count)
{
    AbstractSymbolGroupNodePtrVector rc;
    rc.reserve(count);
    std::string errorMessage;
    // Determine block number and offset in the block array T[][dequeSize]
    // and create symbol by address.
    for (int i = 0; i < count; i++) {
        // see <deque>-header: std::deque<T>::iterator::operator*
        const ULONG64 offset = startOffset + i;
        ULONG64 block = offset / dequeSize;
        if (block >= blockArraySize)
            block -= blockArraySize;
        const ULONG64 blockOffset = offset % dequeSize;
        const ULONG64 address = blockArray[block] + innerTypeSize * blockOffset;
370
        if (SymbolGroupNode *n = sg->addSymbol(module, SymbolGroupValue::pointedToSymbolName(address, innerType), std::string(), &errorMessage))
371
            rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, n));
372
        else
373 374 375 376 377 378 379
            return AbstractSymbolGroupNodePtrVector();
    }
    return rc;
}

// std::deque<>
static inline AbstractSymbolGroupNodePtrVector
380
    stdDequeChildList(const SymbolGroupValue &dequeIn, int count)
381 382 383
{
    if (!count)
        return AbstractSymbolGroupNodePtrVector();
384 385 386 387 388 389
    // From MSVC10 on, there is an additional base class, MSVC2012 more.
    const SymbolGroupValue map = SymbolGroupValue::findMember(dequeIn, "_Map");
    if (!map)
        return AbstractSymbolGroupNodePtrVector();
    const SymbolGroupValue deque = map.parent();
    const ULONG64 arrayAddress = map.pointerValue();
390 391
    const int startOffset = deque["_Myoff"].intValue();
    const int mapSize  = deque["_Mapsize"].intValue();
392 393
    if (!arrayAddress || startOffset < 0 || mapSize <= 0)
        return AbstractSymbolGroupNodePtrVector();
394
    const std::vector<std::string> innerTypes = dequeIn.innerTypes();
395 396
    if (innerTypes.empty())
        return AbstractSymbolGroupNodePtrVector();
397
    const std::string innerType = fixInnerType(innerTypes.front(), deque);
398 399
    // Get the deque size (block size) which is an unavailable static member
    // (cf <deque> for the actual expression).
400
    const unsigned innerTypeSize = SymbolGroupValue::sizeOf(innerType.c_str());
401 402 403 404 405
    if (!innerTypeSize)
        return AbstractSymbolGroupNodePtrVector();
    const int dequeSize = innerTypeSize <= 1 ? 16 : innerTypeSize <= 2 ?
                               8 : innerTypeSize <= 4 ? 4 : innerTypeSize <= 8 ? 2 : 1;
    // Read out map array (pointing to the blocks)
406
    void *mapArray = readPointerArray(arrayAddress, mapSize, deque.context());
407 408 409
    if (!mapArray)
        return AbstractSymbolGroupNodePtrVector();
    const AbstractSymbolGroupNodePtrVector rc = SymbolGroupValue::pointerSize() == 8 ?
410
        stdDequeChildrenHelper(deque.node()->symbolGroup(),
411
                               reinterpret_cast<const ULONG64 *>(mapArray), mapSize,
412
                               deque.module(), innerType, innerTypeSize, startOffset, dequeSize, count) :
413
        stdDequeChildrenHelper(deque.node()->symbolGroup(),
414
                               reinterpret_cast<const ULONG32 *>(mapArray), mapSize,
415
                               deque.module(), innerType, innerTypeSize, startOffset, dequeSize, count);
416 417 418 419
    delete [] mapArray;
    return rc;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
420 421 422
/* Helper class for red-black trees (std::map<>,std::set<> based on std::__Tree:
 * or Qt 5 maps).
 * We locally rebuild the structure in using instances of below class 'RedBlackTreeNode'
423 424 425 426
 * with 'left' and 'right' pointers and the values. Reason being that while it is
 * possible to write the iteration in terms of class SymbolGroupValue, it involves
 * going back up the tree over the flat node->parent pointers. Doing that in the debugger
 * sometimes ends up in nirvana, apparently due to it not being able to properly expand it.
Friedemann Kleint's avatar
Friedemann Kleint committed
427 428 429 430 431 432
 * RedBlackTreeNode has a buildMapRecursion() to build a hierarchy from a STL __Tree or
 * Qt 5 map header value, taking a helper providing node creation and left/right symbol names.
 * Use begin() to return the first node and next() to iterate. The latter are modeled
 * after the _Tree::iterator base classes. (_Tree::begin, _Tree::iterator::operator++()
 * STL tree nodes have a "value" member which is the pair of map data.
 * In Qt 5, the node is a QMapNodeBase which needs to be casted to a QMapNode<K, V>. */
433

Friedemann Kleint's avatar
Friedemann Kleint committed
434
class RedBlackTreeNode
435 436
{
private:
Friedemann Kleint's avatar
Friedemann Kleint committed
437 438
    RedBlackTreeNode(const RedBlackTreeNode &);
    RedBlackTreeNode &operator=(const RedBlackTreeNode &);
439 440

public:
Friedemann Kleint's avatar
Friedemann Kleint committed
441 442 443 444
    explicit RedBlackTreeNode(RedBlackTreeNode *p, const SymbolGroupValue &nodeValue);
    ~RedBlackTreeNode() { delete m_left; delete m_right; }

    const SymbolGroupValue &nodeValue() const { return m_node; }
445 446

    // Iterator helpers: Return first and move to next
Friedemann Kleint's avatar
Friedemann Kleint committed
447 448
    const RedBlackTreeNode *begin() const { return RedBlackTreeNode::leftMost(this); }
    static const RedBlackTreeNode *next(const RedBlackTreeNode *s);
449

Friedemann Kleint's avatar
Friedemann Kleint committed
450 451 452
    // Debug helpers
    template <class DebugFunction>
    void debug(std::ostream &os, DebugFunction df, unsigned depth = 0) const;
453

Friedemann Kleint's avatar
Friedemann Kleint committed
454 455 456
    static RedBlackTreeNode *buildMapRecursion(const SymbolGroupValue &n, ULONG64 headAddress,
                                               RedBlackTreeNode *parent,
                                               const char *leftSymbol, const char *rightSymbol);
457

Friedemann Kleint's avatar
Friedemann Kleint committed
458
    static const RedBlackTreeNode *leftMost(const RedBlackTreeNode *n);
459 460

private:
Friedemann Kleint's avatar
Friedemann Kleint committed
461 462 463
    RedBlackTreeNode *const m_parent;
    RedBlackTreeNode *m_left;
    RedBlackTreeNode *m_right;
464 465 466
    const SymbolGroupValue m_node;
};

Friedemann Kleint's avatar
Friedemann Kleint committed
467 468
RedBlackTreeNode::RedBlackTreeNode(RedBlackTreeNode *p, const SymbolGroupValue &node)
    : m_parent(p), m_left(0), m_right(0), m_node(node)
469 470 471
{
}

Friedemann Kleint's avatar
Friedemann Kleint committed
472
const RedBlackTreeNode *RedBlackTreeNode::leftMost(const RedBlackTreeNode *n)
473 474 475 476 477
{
    for ( ; n->m_left ; n = n->m_left ) ;
    return n;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
478
const RedBlackTreeNode *RedBlackTreeNode::next(const RedBlackTreeNode *s)
479 480
{
    if (s->m_right) // If we have a right node, return its left-most
Friedemann Kleint's avatar
Friedemann Kleint committed
481
        return RedBlackTreeNode::leftMost(s->m_right);
482
    do { // Climb looking for 'right' subtree, that is, we are left of it
Friedemann Kleint's avatar
Friedemann Kleint committed
483
        RedBlackTreeNode *parent = s->m_parent;
484 485 486 487 488 489 490
        if (!parent || parent->m_right != s)
            return parent;
        s = parent;
    } while (true);
    return 0;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
491 492 493 494 495
/* Build the tree using the helper which is asked to create the node
 * and provide the names of the "left" and "right" nodes. */
RedBlackTreeNode *RedBlackTreeNode::buildMapRecursion(const SymbolGroupValue &n, ULONG64 headAddress,
                                                      RedBlackTreeNode *parent,
                                                      const char *leftSymbol, const char *rightSymbol)
496
{
Friedemann Kleint's avatar
Friedemann Kleint committed
497 498 499
    RedBlackTreeNode *node = new RedBlackTreeNode(parent, n);
    // Get left and right nodes. A node pointing to 0 (Qt) or 'head' (STL) terminates the recursion
    if (const SymbolGroupValue left = n[leftSymbol])
500
        if (const ULONG64 leftAddr = left.pointerValue())
Friedemann Kleint's avatar
Friedemann Kleint committed
501 502 503
            if (leftAddr && leftAddr != headAddress)
                node->m_left = buildMapRecursion(left, headAddress, node, leftSymbol, rightSymbol);
    if (const SymbolGroupValue right = n[rightSymbol])
504
        if (const ULONG64 rightAddr = right.pointerValue())
Friedemann Kleint's avatar
Friedemann Kleint committed
505 506
            if (rightAddr && rightAddr != headAddress)
                node->m_right = buildMapRecursion(right, headAddress, node, leftSymbol, rightSymbol);
507 508 509
    return node;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
510 511
template <class DebugFunction>
void RedBlackTreeNode::debug(std::ostream &os, DebugFunction df, unsigned depth) const
512
{
Friedemann Kleint's avatar
Friedemann Kleint committed
513 514 515 516 517
    df(m_node, os, 2 * depth);
    if (m_left)
        m_left->debug(os, df, depth + 1);
    if (m_right)
        m_right->debug(os, df, depth + 1);
518 519 520 521
}

static inline void indentStream(std::ostream &os, unsigned indent)
{
Friedemann Kleint's avatar
Friedemann Kleint committed
522
    for (unsigned i = 0; i < indent; ++i)
523 524 525 526 527
        os << ' ';
}

// Debugging helper for a SymbolGroupValue containing a __Tree::node of
// a map (assuming a std::pair inside).
Friedemann Kleint's avatar
Friedemann Kleint committed
528
static void debugMSVC2010MapNode(const SymbolGroupValue &n, std::ostream &os, unsigned indent = 0)
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
{
    indentStream(os, indent);
    os << "Node at " << std::hex << std::showbase << n.address()
       << std::dec << std::noshowbase
       << " Value='" << wStringToString(n.value()) << "', Parent=" << wStringToString(n["_Parent"].value())
       << ", Left=" << wStringToString(n["_Left"].value())
       << ", Right=" << wStringToString(n["_Right"].value())
       << ", nil='" <<  wStringToString(n["_Isnil"].value());
    if (const SymbolGroupValue pairBase = n["_Myval"][unsigned(0)]) {
        os << "', key='"  << wStringToString(pairBase["first"].value())
           << "', value='"   << wStringToString(pairBase["second"].value())
           << '\'';
    } else {
        os << "', key='"  << wStringToString(n["_Myval"].value()) << '\'';
    }
    os << '\n';
}

// Helper for std::map<>,std::set<> based on std::__Tree:
// Return the list of children (pair for maps, direct children for set)
static inline SymbolGroupValueVector
550
    stdTreeChildList(const SymbolGroupValue &treeIn, int count)
551
{
552 553
    if (!count)
        return SymbolGroupValueVector();
554
    // MSVC2012: many base classes.
555 556
    // MSVC2010: "class _Tree : public _Tree_val: public _Tree_nod".
    // MSVC2008: Direct class
557 558 559 560
    const SymbolGroupValue sizeV = SymbolGroupValue::findMember(treeIn, "_Mysize");
    const SymbolGroupValue tree = sizeV.parent();
    const int size = sizeV.intValue();
    if (!tree|| size <= 0)
561 562
        return SymbolGroupValueVector();
    // Build the tree and iterate it.
Friedemann Kleint's avatar
Friedemann Kleint committed
563 564 565 566 567
    // Goto root of tree (see _Tree::_Root())
    RedBlackTreeNode *nodeTree = 0;
    if (const SymbolGroupValue head = tree["_Myhead"])
        if (const ULONG64 headAddress = head.pointerValue())
            nodeTree = RedBlackTreeNode::buildMapRecursion(head["_Parent"], headAddress, 0, "_Left", "_Right");
568 569
    if (!nodeTree)
        return SymbolGroupValueVector();
Friedemann Kleint's avatar
Friedemann Kleint committed
570 571
    if (SymbolGroupValue::verbose > 1)
        nodeTree->debug(DebugPrint(), debugMSVC2010MapNode);
572 573 574
    SymbolGroupValueVector rc;
    rc.reserve(count);
    int i = 0;
Friedemann Kleint's avatar
Friedemann Kleint committed
575 576 577 578 579 580 581 582
    for (const RedBlackTreeNode *n = nodeTree->begin() ; n && i < count; n = RedBlackTreeNode::next(n), i++) {
        const SymbolGroupValue value = n->nodeValue()["_Myval"];
        if (!value) {
            delete nodeTree;
            return SymbolGroupValueVector();
        }
        rc.push_back(value);
    }
583 584 585 586 587 588 589 590 591 592
    delete nodeTree;
    if (rc.size() != count)
        return SymbolGroupValueVector();
    return rc;
}

// std::set<>: Children directly contained in list
static inline AbstractSymbolGroupNodePtrVector
    stdSetChildList(const SymbolGroupValue &set, int count)
{
593
    const SymbolGroupValueVector children = stdTreeChildList(set, count);
594 595 596 597 598 599 600 601 602 603 604 605 606
    if (int(children.size()) != count)
        return AbstractSymbolGroupNodePtrVector();
    AbstractSymbolGroupNodePtrVector rc;
    rc.reserve(count);
    for (int i = 0; i < count; i++)
        rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, children.at(i).node()));
    return rc;
}

// std::map<K,V>: A list of std::pair<K,V> (derived from std::pair_base<K,V>)
static inline AbstractSymbolGroupNodePtrVector
    stdMapChildList(const SymbolGroupValue &map, int count)
{
607
    const SymbolGroupValueVector children = stdTreeChildList(map[unsigned(0)], count);
608 609 610 611
    if (int(children.size()) != count)
        return AbstractSymbolGroupNodePtrVector();
    AbstractSymbolGroupNodePtrVector rc;
    rc.reserve(count);
612
    const std::string firstName = "first";
613
    for (int i = 0; i < count; i++) {
614 615 616
        // MSVC2010 (only) has a std::pair_base class.
        const SymbolGroupValue key = SymbolGroupValue::findMember(children.at(i), firstName);
        const SymbolGroupValue pairBase = key.parent();
617 618 619 620 621 622 623 624 625 626 627 628
        const SymbolGroupValue value = pairBase["second"];
        if (key && value) {
            rc.push_back(MapNodeSymbolGroupNode::create(i, pairBase.address(),
                                                        pairBase.type(),
                                                        key.node(), value.node()));
        } else {
            return AbstractSymbolGroupNodePtrVector();
        }
    }
    return rc;
}

629
// QVector<T>
630
static inline AbstractSymbolGroupNodePtrVector
631 632
    qVectorChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx)
{
633 634 635 636 637 638
    if (!count)
        return AbstractSymbolGroupNodePtrVector();
    const SymbolGroupValue vec(n, ctx);
    const int qtVersion = QtInfo::get(vec.context()).version;
    if (qtVersion < 5) {
        // Qt 4: QVector<T>: p/array is declared as array of T. Dereference first
639
        // element to obtain address.
640 641
        if (const SymbolGroupValue firstElementV = vec["p"]["array"][unsigned(0)]) {
            if (const ULONG64 arrayAddress = firstElementV.address()) {
642
                const std::string fixedInnerType = fixInnerType(firstElementV.type(), vec);
643
                return arrayChildList(n->symbolGroup(), arrayAddress, n->module(), fixedInnerType, count);
644 645
            }
        }
646 647 648 649 650 651 652 653 654 655 656 657 658 659
        return AbstractSymbolGroupNodePtrVector();
    }
    // Qt 5: Data are located in a pool behind 'd' (similar to QString,
    // QByteArray).
    const SymbolGroupValue dV = vec["d"][unsigned(0)];
    const SymbolGroupValue offsetV = dV["offset"];
    if (!dV || !offsetV)
        return AbstractSymbolGroupNodePtrVector();
    const ULONG64 arrayAddress = dV.address() + offsetV.intValue();
    std::vector<std::string> innerTypes = SymbolGroupValue::innerTypesOf(vec.type());
    if (arrayAddress && !innerTypes.empty()) {
        return arrayChildList(n->symbolGroup(), arrayAddress, n->module(),
                              fixInnerType(innerTypes.front(), vec),
                              count);
660
    }
661
    return AbstractSymbolGroupNodePtrVector();
662 663
}

664 665 666 667 668 669 670 671 672 673 674 675 676 677
// Helper function for arrayChildList() for use with QLists of large types that are an
// array of pointers to allocated elements: Generate a pointer sequence by reading out the array.
template <class AddressType>
class AddressArraySequence
{
public:
    explicit inline AddressArraySequence(const AddressType *array) : m_array(array) {}
    inline ULONG64 operator()() { return *m_array++; }

private:
    const AddressType *m_array;
};

// QList<>.
678
static inline AbstractSymbolGroupNodePtrVector
679
    qListChildList(const SymbolGroupValue &v, int count)
680 681 682
{
    // QList<T>: d/array is declared as array of void *[]. Dereference first
    // element to obtain address.
683
    if (!count)
684
        return AbstractSymbolGroupNodePtrVector();
685 686
    const SymbolGroupValue dV = v["d"];
    if (!dV)
687
        return AbstractSymbolGroupNodePtrVector();
688 689
    const int begin = dV["begin"].intValue();
    if (begin < 0)
690
        return AbstractSymbolGroupNodePtrVector();
691 692
    const SymbolGroupValue firstElementV = dV["array"][unsigned(0)];
    if (!firstElementV)
693
        return AbstractSymbolGroupNodePtrVector();
694
     ULONG64 arrayAddress = firstElementV.address();
695
     if (!arrayAddress)
696
         return AbstractSymbolGroupNodePtrVector();
697 698
     const std::vector<std::string> innerTypes = v.innerTypes();
     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;
704
     if (!innerTypeSize)
705
         return AbstractSymbolGroupNodePtrVector();
706 707 708 709 710 711 712 713 714
     /* QList<> is:
      * 1) An array of 'void *[]' where T values are coerced into the elements for
      *    POD/pointer types and small, movable or primitive Qt types. That is, smaller
      *    elements are also aligned at 'void *' boundaries.
      * 2) An array of 'T *[]' (pointer to allocated instances) for anything else
      *    (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic)
      *    isStatic depends on QTypeInfo specializations and hardcoded flags for types. */
     const unsigned pointerSize = SymbolGroupValue::pointerSize();
     arrayAddress += begin * pointerSize;
715 716
     if (SymbolGroupValue::isPointerType(innerType)) // Quick check: Any pointer is T[]
         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 725
             isLargeOrStatic = true;
     }
726
     if (SymbolGroupValue::verbose)
727
         DebugPrint() << "isLargeOrStatic " << isLargeOrStatic;
728 729
     if (isLargeOrStatic) {
         // Retrieve the pointer array ourselves to avoid having to evaluate '*(class foo**)'
730 731 732
         if (void *data = readPointerArray(arrayAddress, count, v.context()))  {
             // Generate sequence of addresses from pointer array
             const AbstractSymbolGroupNodePtrVector rc = pointerSize == 8 ?
733 734 735 736 737
                         arrayChildList(v.node()->symbolGroup(),
                                        AddressArraySequence<ULONG64>(reinterpret_cast<const ULONG64 *>(data)),
                                        v.module(), innerType, count) :
                         arrayChildList(v.node()->symbolGroup(), AddressArraySequence<ULONG32>(reinterpret_cast<const ULONG32 *>(data)),
                                        v.module(), innerType, count);
738
             delete [] data;
739
             return rc;
740
         }
741
         return AbstractSymbolGroupNodePtrVector();
742
     }
743
     return arrayChildList(v.node()->symbolGroup(),
744
                           AddressSequence(arrayAddress, pointerSize),
745
                           v.module(), innerType, count);
746 747
}

748 749 750
// Return the list of buckets of a 'QHash<>' as 'QHashData::Node *' values from
// the list of addresses passed in
template<class AddressType>
751
SymbolGroupValueVector hashBuckets(SymbolGroup *sg, const std::string &hashNodeType,
752 753 754
                                   const AddressType *pointerArray,
                                   int numBuckets,
                                   AddressType ePtr,
755
                                   const std::string &module,
756 757 758 759 760 761 762 763 764 765
                                   const SymbolGroupValueContext &ctx)
{
    SymbolGroupValueVector rc;
    rc.reserve(numBuckets);
    const AddressType *end = pointerArray + numBuckets;
    std::string errorMessage;
    // Skip 'e' special values as they are used as placeholder for reserve(d)
    // empty array elements.
    for (const AddressType *p = pointerArray; p < end; p++) {
        if (*p != ePtr) {
766
            const std::string name = SymbolGroupValue::pointedToSymbolName(*p, hashNodeType);
767
            if (SymbolGroupNode *child = sg->addSymbol(module, name, std::string(), &errorMessage)) {
768 769 770 771 772 773 774 775 776 777
                rc.push_back(SymbolGroupValue(child, ctx));
            } else {
                return std::vector<SymbolGroupValue>();
                break;
            }
        }
    }
    return rc;
}

778
// Return the node type of a QHash/QMap:
779
// "class QHash<K,V>[ *]" -> [struct] "QtCored4!QHashNode<K,V>";
780 781
static inline std::string qHashNodeType(const SymbolGroupValue &v,
                                        const char *nodeType)
782
{
783
    std::string qHashType = SymbolGroupValue::stripPointerType(v.type());
784 785
    const std::string::size_type pos = qHashType.find('<');
    if (pos != std::string::npos)
786 787 788 789 790
        qHashType.insert(pos, nodeType);
    // A map node must be qualified with the current module and
    // the Qt namespace (particularly QMapNode, QHashNodes work also for
    // the unqualified case).
    const QtInfo &qtInfo = QtInfo::get(v.context());
791
    const std::string currentModule = v.module();
792
    return QtInfo::prependModuleAndNameSpace(qHashType, currentModule, qtInfo.nameSpace);
793 794 795 796 797 798 799 800 801 802 803
}

// Return up to count nodes of type "QHashNode<K,V>" of a "class QHash<K,V>".
SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
                                  VectorIndexType count)
{
    if (!count)
        return SymbolGroupValueVector();
    const SymbolGroupValue hashData = v["d"];
    // 'e' is used as a special value to indicate empty hash buckets in the array.
    const ULONG64 ePtr = v["e"].pointerValue();
804
    if (SymbolGroupValue::verbose)
805
        DebugPrint() << v << " Count=" << count << ",ePtr=0x" << std::hex << ePtr;
806 807 808 809 810 811 812 813 814 815 816
    if (!hashData || !ePtr)
        return SymbolGroupValueVector();
    // Retrieve the array of buckets of 'd'
    const int numBuckets = hashData["numBuckets"].intValue();
    const ULONG64 bucketArray = hashData["buckets"].pointerValue();
    if (numBuckets <= 0 || !bucketArray)
        return SymbolGroupValueVector();
    void *bucketPointers = readPointerArray(bucketArray, numBuckets, v.context());
    if (!bucketPointers)
        return SymbolGroupValueVector();
    // Get list of buckets (starting elements of 'QHashData::Node')
Friedemann Kleint's avatar
Friedemann Kleint committed
817
    const std::string dummyNodeType = QtInfo::get(v.context()).prependQtCoreModule("QHashData::Node");
818 819 820
    const SymbolGroupValueVector buckets = SymbolGroupValue::pointerSize() == 8 ?
        hashBuckets(v.node()->symbolGroup(), dummyNodeType,
                    reinterpret_cast<const ULONG64 *>(bucketPointers), numBuckets,
821
                    ePtr, v.module(), v.context()) :
822 823
        hashBuckets(v.node()->symbolGroup(), dummyNodeType,
                    reinterpret_cast<const ULONG32 *>(bucketPointers), numBuckets,
824
                    ULONG32(ePtr), v.module(), v.context());
825 826 827 828
    delete [] bucketPointers ;
    // Generate the list 'QHashData::Node *' by iterating over the linked list of
    // nodes starting at each bucket. Using the 'QHashData::Node *' instead of
    // the 'QHashNode<K,T>' is much faster. Each list has a trailing, unused
829 830
    // dummy element. The initial element as such is skipped due to the pointer/value
    // duality (since its 'next' element is identical to it when using typecast<> later on).
831 832 833 834 835 836 837 838
    SymbolGroupValueVector dummyNodeList;
    dummyNodeList.reserve(count);
    bool notEnough = true;
    const SymbolGroupValueVector::const_iterator ncend = buckets.end();
    for (SymbolGroupValueVector::const_iterator it = buckets.begin(); notEnough && it != ncend; ++it) {
        for (SymbolGroupValue l = *it; notEnough && l ; ) {
            const SymbolGroupValue next = l["next"];
            if (next && next.pointerValue()) { // Stop at trailing dummy element
839
                dummyNodeList.push_back(next);
840 841
                if (dummyNodeList.size() >= count) // Stop at maximum count
                    notEnough = false;
842
                if (SymbolGroupValue::verbose > 1)
843
                    DebugPrint() << '#' << (dummyNodeList.size() - 1) << " l=" << l << ",next=" << next;
844
                l = next;
845 846 847 848 849 850
            } else {
                break;
            }
        }
    }
    // 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 855 856 857
    SymbolGroupValueVector nodeList;
    nodeList.reserve(count);
    const SymbolGroupValueVector::const_iterator dcend = dummyNodeList.end();
    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);
Christian Stenger's avatar
Christian Stenger committed
860
        else
861 862 863 864 865 866 867
            return SymbolGroupValueVector();
    }
    return nodeList;
}

// QSet<>: Contains a 'QHash<key, QHashDummyValue>' as member 'q_hash'.
// Just dump the keys as an array.
868
static inline AbstractSymbolGroupNodePtrVector
869
    qSetChildList(const SymbolGroupValue &v, int count)
870 871 872 873 874 875 876 877 878 879
{
    const SymbolGroupValue qHash = v["q_hash"];
    AbstractSymbolGroupNodePtrVector rc;
    if (!count || !qHash)
        return rc;
    const SymbolGroupValueVector nodes = qHashNodes(qHash, count);
    if (nodes.size() != VectorIndexType(count))
        return rc;
    rc.reserve(count);
    for (int i = 0; i < count; i++) {
880
        if (const SymbolGroupValue key = nodes.at(i)["key"])
881
            rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, key.node()));
882
        else
883 884 885 886 887 888 889
            return AbstractSymbolGroupNodePtrVector();
    }
    return rc;
}

// QHash<>: Add with fake map nodes.
static inline AbstractSymbolGroupNodePtrVector
890
    qHashChildList(const SymbolGroupValue &v, int count)
891 892 893 894
{
    AbstractSymbolGroupNodePtrVector rc;
    if (!count)
        return rc;
895 896 897 898 899 900 901 902 903 904 905 906 907
    const SymbolGroupValueVector nodes = qHashNodes(v, count);
    if (nodes.size() != count)
        return rc;
    rc.reserve(count);
    for (int i = 0; i < count; i++) {
        const SymbolGroupValue &mapNode = nodes.at(i);
        const SymbolGroupValue key = mapNode["key"];
        const SymbolGroupValue value = mapNode["value"];
        if (!key || !value)
            return AbstractSymbolGroupNodePtrVector();
        rc.push_back(MapNodeSymbolGroupNode::create(i, mapNode.address(),
                                                    mapNode.type(), key.node(), value.node()));
    }
908 909 910
    return rc;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
911 912
// Qt 4: QMap<>: Return the list of QMapData::Node
static inline SymbolGroupValueVector qMap4Nodes(const SymbolGroupValue &v, VectorIndexType count)
913 914 915
{
    const SymbolGroupValue e = v["e"];
    const ULONG64 ePtr = e.pointerValue();
916
    if (SymbolGroupValue::verbose)
917 918 919
        DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
    if (!ePtr)
        return SymbolGroupValueVector();
920
    if (SymbolGroupValue::verbose)
921 922 923 924
        DebugPrint() << v.type() << " E=0x" << std::hex << ePtr;
    SymbolGroupValueVector rc;
    rc.reserve(count);
    SymbolGroupValue n = e["forward"][unsigned(0)];
Friedemann Kleint's avatar
Friedemann Kleint committed
925
    for (VectorIndexType i = 0; i < count && n && n.pointerValue() != ePtr; ++i) {
926 927 928 929 930 931
        rc.push_back(n);
        n = n["forward"][unsigned(0)];
    }
    return rc;
}

Friedemann Kleint's avatar
Friedemann Kleint committed
932 933 934 935 936 937 938 939 940 941 942 943 944 945
static void debugQMap5Node(const SymbolGroupValue &n, std::ostream &os, unsigned indent = 0)
{
    const char *color = (n["p"].intValue() & 1) ? "black" : "red";
    indentStream(os, indent);
    os << n.address() << ' ' <<color << " left: " << n["left"] << " right: " << n["right"];
}

// Qt 5: QMap<>: Return the list of QMapNode<K, V>
static inline AbstractSymbolGroupNodePtrVector qMap5Nodes(const SymbolGroupValue &v, VectorIndexType count)
{
    const SymbolGroupValue head = SymbolGroupValue::findMember(v["d"], "header");
    SymbolGroupValue root = head["left"];
    if (!root)
        return AbstractSymbolGroupNodePtrVector();
946 947 948 949 950 951

    const std::string nodeType = qHashNodeType(v, "Node");
    const std::string nodePtrType = nodeType +  " *";
    if (SymbolGroupValue::verbose)
        DebugPrint() << v.type() << "," << nodeType;

Friedemann Kleint's avatar
Friedemann Kleint committed
952 953 954 955 956 957
    RedBlackTreeNode *nodeTree =
        RedBlackTreeNode::buildMapRecursion(root, head.address(), 0, "left", "right");
    if (!nodeTree)
        return AbstractSymbolGroupNodePtrVector();
    if (SymbolGroupValue::verbose > 1)
        nodeTree->debug(DebugPrint(), debugQMap5Node);
958
    VectorIndexType i = 0;
Friedemann Kleint's avatar
Friedemann Kleint committed
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
    // Finally convert them into real nodes 'QHashNode<K,V> (potentially expensive)
    AbstractSymbolGroupNodePtrVector result;
    result.reserve(count);
    for (const RedBlackTreeNode *n = nodeTree->begin() ; n && i < count; n = RedBlackTreeNode::next(n), i++) {
        if (const SymbolGroupValue qmapNode = n->nodeValue().pointerTypeCast(nodePtrType.c_str())) {
            const SymbolGroupValue key = qmapNode["key"];
            const SymbolGroupValue value = qmapNode["value"];
            if (!key || !value) {
                delete nodeTree;
                return AbstractSymbolGroupNodePtrVector();
            }
            result.push_back(MapNodeSymbolGroupNode::create(i, key.address(),
                                                            nodeType,
                                                            key.node(), value.node()));
        }
    }
    delete nodeTree;
    return result;
}

979 980 981 982
// QMap<>: Add with fake map nodes.
static inline AbstractSymbolGroupNodePtrVector
    qMapChildList(const SymbolGroupValue &v, VectorIndexType count)
{
983
    if (SymbolGroupValue::verbose)
984 985 986 987
        DebugPrint() << v.type() << "," << count;

    if (!count)
        return AbstractSymbolGroupNodePtrVector();
Friedemann Kleint's avatar
Friedemann Kleint committed
988 989
    if (QtInfo::get(v.context()).version >= 5)
        return qMap5Nodes(v, count);
990 991 992 993 994 995 996
    // Get node type: 'class namespace::QMap<K,T>'
    // ->'QtCored4!namespace::QMapNode<K,T>'
    // Note: Any types QMapNode<> will not be found without modules!
    const std::string mapNodeType = qHashNodeType(v, "Node");
    const std::string mapPayloadNodeType = qHashNodeType(v, "PayloadNode");
    // Calculate the offset needed (see QMap::concrete() used by the iterator).
    const unsigned payloadNodeSize = SymbolGroupValue::sizeOf(mapPayloadNodeType.c_str());
997
    if (SymbolGroupValue::verbose) {
998
        DebugPrint() << v.type() << "," << mapNodeType << ':'
999 1000
                     << mapPayloadNodeType << ':' << payloadNodeSize
                     << ", pointerSize=" << SymbolGroupValue::pointerSize();
1001
    }
1002
    if (!payloadNodeSize)
1003
        return AbstractSymbolGroupNodePtrVector();
1004
    const ULONG64 payLoad  = payloadNodeSize - SymbolGroupValue::pointerSize();
1005 1006 1007 1008 1009 1010
    // Get the value offset. Manually determine the alignment to be able
    // to retrieve key/value without having to deal with QMapNode<> (see below).
    // Subtract the 2 trailing pointers of the node.
    const std::vector<std::string> innerTypes = v.innerTypes();
    if (innerTypes.size() != 2u)
        return AbstractSymbolGroupNodePtrVector();
1011 1012 1013
    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());
1014
    const unsigned valueOffset = SymbolGroupValue::fieldOffset(mapNodeType.c_str(), "value");
1015
    if (SymbolGroupValue::verbose)
1016 1017 1018 1019 1020
        DebugPrint() << "Payload=" << payLoad << ",valueOffset=" << valueOffset << ','
                     << innerTypes.front() << ',' << innerTypes.back() << ':' << valueSize;
    if (!valueOffset || !valueSize)
        return AbstractSymbolGroupNodePtrVector();
    // Get the children.
Friedemann Kleint's avatar
Friedemann Kleint committed
1021
    const SymbolGroupValueVector childNodes = qMap4Nodes(v, count);
1022
    if (SymbolGroupValue::verbose)
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
        DebugPrint() << "children: " << childNodes.size() << " of " << count;
    // Deep  expansion of the forward[0] sometimes fails. In that case,
    // take what we can get.
    if (childNodes.size() != count)
        count = childNodes.size();