PageRenderTime 67ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/share/qtcreator/dumper/dumper.cpp

https://bitbucket.org/kyanha/qt-creator
C++ | 3809 lines | 3347 code | 262 blank | 200 comment | 479 complexity | 22a4a2eb928155cb6332f220bac7630e MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of Qt Creator.
  7. **
  8. ** Commercial License Usage
  9. ** Licensees holding valid commercial Qt licenses may use this file in
  10. ** accordance with the commercial license agreement provided with the
  11. ** Software or, alternatively, in accordance with the terms contained in
  12. ** a written agreement between you and Digia. For licensing terms and
  13. ** conditions see http://qt.digia.com/licensing. For further information
  14. ** use the contact form at http://qt.digia.com/contact-us.
  15. **
  16. ** GNU Lesser General Public License Usage
  17. ** Alternatively, this file may be used under the terms of the GNU Lesser
  18. ** General Public License version 2.1 as published by the Free Software
  19. ** Foundation and appearing in the file LICENSE.LGPL included in the
  20. ** packaging of this file. Please review the following information to
  21. ** ensure the GNU Lesser General Public License version 2.1 requirements
  22. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  23. **
  24. ** In addition, as a special exception, Digia gives you certain additional
  25. ** rights. These rights are described in the Digia Qt LGPL Exception
  26. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  27. **
  28. ****************************************************************************/
  29. #include <qglobal.h>
  30. #if USE_QT_CORE
  31. #include <QDateTime>
  32. #include <QDebug>
  33. #include <QDir>
  34. #include <QFile>
  35. #include <QFileInfo>
  36. #include <QHash>
  37. #include <QLinkedList>
  38. #include <QList>
  39. #include <QQueue>
  40. #include <QLocale>
  41. #include <QMap>
  42. #include <QMetaEnum>
  43. #include <QMetaObject>
  44. #include <QMetaProperty>
  45. #include <QPoint>
  46. #include <QPointF>
  47. #include <QPointer>
  48. #include <QRect>
  49. #include <QRectF>
  50. #include <QStack>
  51. #include <QSize>
  52. #include <QSizeF>
  53. #include <QString>
  54. #include <QStringList>
  55. #include <QTextCodec>
  56. #include <QTextStream>
  57. #include <QVector>
  58. #ifndef QT_BOOTSTRAPPED
  59. #include <QModelIndex>
  60. #if QT_VERSION >= 0x040500
  61. #include <QSharedPointer>
  62. #include <QSharedDataPointer>
  63. #include <QSharedData>
  64. #include <QWeakPointer>
  65. #endif
  66. #ifndef USE_QT_GUI
  67. # ifdef QT_GUI_LIB
  68. # define USE_QT_GUI 1
  69. # endif
  70. #endif
  71. #ifndef USE_QT_WIDGETS
  72. # if defined(QT_WIDGETS_LIB) || ((QT_VERSION < 0x050000) && defined(USE_QT_GUI))
  73. # define USE_QT_WIDGETS 1
  74. # endif
  75. #endif
  76. #ifdef USE_QT_GUI
  77. # include <QImage>
  78. # include <QRegion>
  79. # include <QPixmap>
  80. # include <QFont>
  81. # include <QColor>
  82. # include <QKeySequence>
  83. #endif
  84. #ifdef USE_QT_WIDGETS
  85. # include <QSizePolicy>
  86. # include <QWidget>
  87. # include <QApplication>
  88. #endif
  89. #endif // QT_BOOTSTRAPPED
  90. #endif // USE_QT_CORE
  91. #ifdef Q_OS_WIN
  92. # include <windows.h>
  93. #endif
  94. #include <list>
  95. #include <map>
  96. #include <string>
  97. #include <set>
  98. #include <vector>
  99. #include <stdio.h>
  100. #ifdef QT_BOOTSTRAPPED
  101. # define NS ""
  102. # define NSX "'"
  103. # define NSY "'"
  104. #else
  105. # include "dumper_p.h"
  106. #endif // QT_BOOTSTRAPPED
  107. #if QT_VERSION >= 0x050000
  108. # define MAP_WORKS 0
  109. #else
  110. # define MAP_WORKS 1
  111. #endif
  112. int qtGhVersion = QT_VERSION;
  113. /*!
  114. \class QDumper
  115. \brief Helper class for producing "nice" output in Qt Creator's debugger.
  116. \internal
  117. The whole "custom dumper" implementation is currently far less modular
  118. than it could be. But as the code is still in a flux, making it nicer
  119. from a pure archtectural point of view seems still be a waste of resources.
  120. Some hints:
  121. New dumpers for non-templated classes should be mentioned in
  122. \c{qDumpObjectData440()} in the \c{protocolVersion == 1} branch.
  123. Templated classes need extra support on the IDE level
  124. (see plugins/debugger/gdbengine.cpp) and should not be mentiond in
  125. \c{qDumpObjectData440()}.
  126. In any case, dumper processesing should end up in
  127. \c{handleProtocolVersion2and3()} and needs an entry in the big switch there.
  128. Next step is to create a suitable \c{static void qDumpFoo(QDumper &d)}
  129. function. At the bare minimum it should contain something like this:
  130. \c{
  131. const Foo &foo = *reinterpret_cast<const Foo *>(d.data);
  132. d.putItem("value", ...);
  133. d.putItem("type", "Foo");
  134. d.putItem("numchild", "0");
  135. }
  136. 'd.putItem(name, value)' roughly expands to:
  137. d.put((name)).put("=\"").put(value).put("\"";
  138. Useful (i.e. understood by the IDE) names include:
  139. \list
  140. \o "name" shows up in the first column in the Locals&Watchers view.
  141. \o "value" shows up in the second column.
  142. \o "valueencoded" should be set to "1" if the value is base64 encoded.
  143. Always base64-encode values that might use unprintable or otherwise
  144. "confuse" the protocol (like spaces and quotes). [A-Za-z0-9] is "safe".
  145. A value of "3" is used for base64-encoded UCS4, "2" denotes
  146. base64-encoded UTF16.
  147. \o "numchild" return the number of children in the view. Effectively, only
  148. 0 and != 0 will be used, so don't try too hard to get the number right.
  149. \endlist
  150. If the current item has children, it might be queried to produce information
  151. about these children. In this case the dumper should use something like this:
  152. \c{
  153. if (d.dumpChildren) {
  154. d.beginChildren();
  155. [...]
  156. d.endChildren();
  157. }
  158. */
  159. #if defined(QT_BEGIN_NAMESPACE)
  160. QT_BEGIN_NAMESPACE
  161. #endif
  162. const char *stdStringTypeC = "std::basic_string<char,std::char_traits<char>,std::allocator<char> >";
  163. const char *stdWideStringTypeUShortC = "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
  164. #if defined(QT_BEGIN_NAMESPACE)
  165. QT_END_NAMESPACE
  166. #endif
  167. // This can be mangled typenames of nested templates, each char-by-char
  168. // comma-separated integer list...
  169. // The output buffer.
  170. #ifdef MACROSDEBUG
  171. Q_DECL_EXPORT char xDumpInBuffer[10000];
  172. Q_DECL_EXPORT char xDumpOutBuffer[1000000];
  173. # define inBuffer xDumpInBuffer
  174. # define outBuffer xDumpOutBuffer
  175. #else
  176. Q_DECL_EXPORT char qDumpInBuffer[10000];
  177. Q_DECL_EXPORT char qDumpOutBuffer[1000000];
  178. # define inBuffer qDumpInBuffer
  179. # define outBuffer qDumpOutBuffer
  180. #endif
  181. namespace {
  182. static QByteArray strPtrConst = "* const";
  183. static bool isPointerType(const QByteArray &type)
  184. {
  185. return type.endsWith('*') || type.endsWith(strPtrConst);
  186. }
  187. static QByteArray stripPointerType(const QByteArray &_type)
  188. {
  189. QByteArray type = _type;
  190. if (type.endsWith('*'))
  191. type.chop(1);
  192. if (type.endsWith(strPtrConst))
  193. type.chop(7);
  194. if (type.endsWith(' '))
  195. type.chop(1);
  196. return type;
  197. }
  198. // This is used to abort evaluation of custom data dumpers in a "coordinated"
  199. // way. Abortion will happen at the latest when we try to access a non-initialized
  200. // non-trivial object, so there is no way to prevent this from occurring at all
  201. // conceptually. Gdb will catch SIGSEGV and return to the calling frame.
  202. // This is just fine provided we only _read_ memory in the custom handlers below.
  203. // We don't use this code for MSVC/CDB anymore.
  204. volatile int qProvokeSegFaultHelper;
  205. static const void *addOffset(const void *p, int offset)
  206. {
  207. return offset + reinterpret_cast<const char *>(p);
  208. }
  209. static const void *deref(const void *p)
  210. {
  211. return *reinterpret_cast<const char* const*>(p);
  212. }
  213. #if USE_QT_CORE
  214. static const void *skipvtable(const void *p)
  215. {
  216. return sizeof(void *) + reinterpret_cast<const char *>(p);
  217. }
  218. static const void *dfunc(const void *p)
  219. {
  220. return deref(skipvtable(p));
  221. }
  222. #endif
  223. static bool isEqual(const char *s, const char *t)
  224. {
  225. return qstrcmp(s, t) == 0;
  226. }
  227. static bool startsWith(const char *s, const char *t)
  228. {
  229. while (char c = *t++)
  230. if (c != *s++)
  231. return false;
  232. return true;
  233. }
  234. // Check memory for read access and provoke segfault if nothing else helps.
  235. // On Windows, try to be less crash-prone by checking memory using WinAPI
  236. #ifdef Q_OS_WIN
  237. # define qCheckAccess(d) do { \
  238. if (IsBadReadPtr(d, 1)) \
  239. return; \
  240. qProvokeSegFaultHelper = *(char*)d; \
  241. } while (0)
  242. # define qCheckPointer(d) do { \
  243. if (d && IsBadReadPtr(d, 1)) \
  244. return; \
  245. if (d) qProvokeSegFaultHelper = *(char*)d; \
  246. } while (0)
  247. #else
  248. # define qCheckAccess(d) do { \
  249. if (!couldBePointer(d) && d != 0) \
  250. return; \
  251. qProvokeSegFaultHelper = *(char*)d; \
  252. } while (0)
  253. # define qCheckPointer(d) do { \
  254. if (!couldBePointer(d)) \
  255. return; \
  256. if (d) \
  257. qProvokeSegFaultHelper = *(char*)d; \
  258. } while (0)
  259. static bool couldBePointer(const void *p)
  260. {
  261. // we assume valid pointer to be 4-aligned at least.
  262. // So use this check only when this is guaranteed.
  263. // FIXME: this breaks e.g. in the QString dumper...
  264. const quintptr d = quintptr(p);
  265. //qDebug() << "CHECKING : " << p << ((d & 3) == 0 && (d > 1000 || d == 0));
  266. //return (d & 3) == 0 && (d > 1000 || d == 0);
  267. return d > 1000 || d == 0;
  268. }
  269. #endif
  270. #ifdef QT_NAMESPACE
  271. const char *stripNamespace(const char *type)
  272. {
  273. static const size_t nslen = strlen(NS);
  274. return startsWith(type, NS) ? type + nslen : type;
  275. }
  276. #else
  277. inline const char *stripNamespace(const char *type)
  278. {
  279. return type;
  280. }
  281. #endif
  282. static bool isSimpleType(const char *type)
  283. {
  284. switch (type[0]) {
  285. case 'c':
  286. return isEqual(type, "char");
  287. case 'd':
  288. return isEqual(type, "double");
  289. case 'f':
  290. return isEqual(type, "float");
  291. case 'i':
  292. return isEqual(type, "int");
  293. case 'l':
  294. return isEqual(type, "long") || startsWith(type, "long ");
  295. case 's':
  296. return isEqual(type, "short") || startsWith(type, "short ")
  297. || isEqual(type, "signed") || startsWith(type, "signed ");
  298. case 'u':
  299. return isEqual(type, "unsigned") || startsWith(type, "unsigned ");
  300. }
  301. return false;
  302. }
  303. static bool isStringType(const char *type)
  304. {
  305. return isEqual(type, NS "QString")
  306. || isEqual(type, NS "QByteArray")
  307. || isEqual(type, "std::string")
  308. || isEqual(type, "std::wstring")
  309. || isEqual(type, "wstring");
  310. }
  311. #if USE_QT_CORE
  312. static bool isMovableType(const char *type)
  313. {
  314. if (isPointerType(type))
  315. return true;
  316. if (isSimpleType(type))
  317. return true;
  318. type = stripNamespace(type);
  319. switch (type[1]) {
  320. case 'B':
  321. return isEqual(type, "QBrush")
  322. || isEqual(type, "QBitArray")
  323. || isEqual(type, "QByteArray") ;
  324. case 'C':
  325. return isEqual(type, "QCustomTypeInfo")
  326. || isEqual(type, "QChar");
  327. case 'D':
  328. return isEqual(type, "QDate")
  329. || isEqual(type, "QDateTime");
  330. case 'F':
  331. return isEqual(type, "QFileInfo")
  332. || isEqual(type, "QFixed")
  333. || isEqual(type, "QFixedPoint")
  334. || isEqual(type, "QFixedSize");
  335. case 'H':
  336. return isEqual(type, "QHashDummyValue");
  337. case 'I':
  338. return isEqual(type, "QIcon")
  339. || isEqual(type, "QImage");
  340. case 'L':
  341. return isEqual(type, "QLine")
  342. || isEqual(type, "QLineF")
  343. || isEqual(type, "QLatin1Char")
  344. || isEqual(type, "QLocal");
  345. case 'M':
  346. return isEqual(type, "QMatrix")
  347. || isEqual(type, "QModelIndex");
  348. case 'P':
  349. return isEqual(type, "QPoint")
  350. || isEqual(type, "QPointF")
  351. || isEqual(type, "QPen")
  352. || isEqual(type, "QPersistentModelIndex");
  353. case 'R':
  354. return isEqual(type, "QResourceRoot")
  355. || isEqual(type, "QRect")
  356. || isEqual(type, "QRectF")
  357. || isEqual(type, "QRegExp");
  358. case 'S':
  359. return isEqual(type, "QSize")
  360. || isEqual(type, "QSizeF")
  361. || isEqual(type, "QString");
  362. case 'T':
  363. return isEqual(type, "QTime")
  364. || isEqual(type, "QTextBlock");
  365. case 'U':
  366. return isEqual(type, "QUrl");
  367. case 'V':
  368. return isEqual(type, "QVariant");
  369. case 'X':
  370. return isEqual(type, "QXmlStreamAttribute")
  371. || isEqual(type, "QXmlStreamNamespaceDeclaration")
  372. || isEqual(type, "QXmlStreamNotationDeclaration")
  373. || isEqual(type, "QXmlStreamEntityDeclaration");
  374. }
  375. return false;
  376. }
  377. #endif
  378. struct QDumper
  379. {
  380. explicit QDumper();
  381. ~QDumper();
  382. // direct write to the output
  383. QDumper &put(long c);
  384. QDumper &put(int i);
  385. QDumper &put(double d);
  386. QDumper &put(float d);
  387. QDumper &put(unsigned long c);
  388. QDumper &put(unsigned int i);
  389. QDumper &put(const void *p);
  390. QDumper &put(qulonglong c);
  391. QDumper &put(long long c);
  392. QDumper &put(const char *str);
  393. QDumper &put(const QByteArray &ba);
  394. QDumper &put(const QString &str);
  395. QDumper &put(char c);
  396. // convienience functions for writing key="value" pairs:
  397. template <class Value>
  398. void putItem(const char *name, const Value &value)
  399. {
  400. putCommaIfNeeded();
  401. put(name).put('=').put('"').put(value).put('"');
  402. }
  403. void putItem(const char *name, const char *value, const char *setvalue)
  404. {
  405. if (!isEqual(value, setvalue))
  406. putItem(name, value);
  407. }
  408. // convienience functions for writing typical properties.
  409. // roughly equivalent to
  410. // beginHash();
  411. // putItem("name", name);
  412. // putItem("value", value);
  413. // putItem("type", NS "QString");
  414. // putItem("numchild", "0");
  415. // putItem("valueencoded", "2");
  416. // endHash();
  417. void putHash(const char *name, const QString &value);
  418. void putHash(const char *name, const QByteArray &value);
  419. void putHash(const char *name, int value);
  420. void putHash(const char *name, long value);
  421. void putHash(const char *name, bool value);
  422. void putHash(const char *name, QChar value);
  423. void putHash(const char *name, float value);
  424. void putHash(const char *name, double value);
  425. void putStringValue(const QString &value);
  426. void beginHash(); // start of data hash output
  427. void endHash(); // start of data hash output
  428. void beginChildren(const char *mainInnerType = 0); // start of children list
  429. void endChildren(); // end of children list
  430. void beginItem(const char *name); // start of named item, ready to accept value
  431. void endItem(); // end of named item, used after value output is complete
  432. // convenience for putting "<n items>"
  433. void putItemCount(const char *name, int count);
  434. // convenience for putting "<>n items>" (more than X items)
  435. void putTruncatedItemCount(const char *name, int count);
  436. void putCommaIfNeeded();
  437. // convienience function for writing the last item of an abbreviated list
  438. void putEllipsis();
  439. void disarm();
  440. void putBase64Encoded(const char *buf, int n);
  441. void checkFill();
  442. // the dumper arguments
  443. int protocolVersion; // dumper protocol version
  444. int token; // some token to show on success
  445. const char *outerType; // object type
  446. const char *iname; // object name used for display
  447. const char *exp; // object expression
  448. const char *innerType; // 'inner type' for class templates
  449. const void *data; // pointer to raw data
  450. bool dumpChildren; // do we want to see children?
  451. // handling of nested templates
  452. void setupTemplateParameters();
  453. enum { maxTemplateParameters = 10 };
  454. const char *templateParameters[maxTemplateParameters + 1];
  455. // internal state
  456. int extraInt[4];
  457. bool success; // are we finished?
  458. bool full;
  459. int pos;
  460. const char *currentChildType;
  461. const char *currentChildNumChild;
  462. };
  463. QDumper::QDumper()
  464. {
  465. success = false;
  466. full = false;
  467. outBuffer[0] = 'f'; // marks output as 'wrong'
  468. pos = 1;
  469. currentChildType = 0;
  470. currentChildNumChild = 0;
  471. }
  472. QDumper::~QDumper()
  473. {
  474. outBuffer[pos++] = '\0';
  475. if (success)
  476. outBuffer[0] = (full ? '+' : 't');
  477. }
  478. void QDumper::setupTemplateParameters()
  479. {
  480. char *s = const_cast<char *>(innerType);
  481. int templateParametersCount = 1;
  482. templateParameters[0] = s;
  483. for (int i = 1; i != maxTemplateParameters + 1; ++i)
  484. templateParameters[i] = 0;
  485. while (*s) {
  486. while (*s && *s != '@')
  487. ++s;
  488. if (*s) {
  489. *s = '\0';
  490. ++s;
  491. templateParameters[templateParametersCount++] = s;
  492. }
  493. }
  494. while (templateParametersCount < maxTemplateParameters)
  495. templateParameters[templateParametersCount++] = 0;
  496. }
  497. QDumper &QDumper::put(char c)
  498. {
  499. checkFill();
  500. if (!full)
  501. outBuffer[pos++] = c;
  502. return *this;
  503. }
  504. QDumper &QDumper::put(unsigned long long c)
  505. {
  506. checkFill();
  507. pos += sprintf(outBuffer + pos, "%llu", c);
  508. return *this;
  509. }
  510. QDumper &QDumper::put(long long c)
  511. {
  512. checkFill();
  513. pos += sprintf(outBuffer + pos, "%lld", c);
  514. return *this;
  515. }
  516. QDumper &QDumper::put(unsigned long c)
  517. {
  518. checkFill();
  519. pos += sprintf(outBuffer + pos, "%lu", c);
  520. return *this;
  521. }
  522. QDumper &QDumper::put(float d)
  523. {
  524. checkFill();
  525. pos += sprintf(outBuffer + pos, "%f", d);
  526. return *this;
  527. }
  528. QDumper &QDumper::put(double d)
  529. {
  530. checkFill();
  531. pos += sprintf(outBuffer + pos, "%f", d);
  532. return *this;
  533. }
  534. QDumper &QDumper::put(unsigned int i)
  535. {
  536. checkFill();
  537. pos += sprintf(outBuffer + pos, "%u", i);
  538. return *this;
  539. }
  540. QDumper &QDumper::put(long c)
  541. {
  542. checkFill();
  543. pos += sprintf(outBuffer + pos, "%ld", c);
  544. return *this;
  545. }
  546. QDumper &QDumper::put(int i)
  547. {
  548. checkFill();
  549. pos += sprintf(outBuffer + pos, "%d", i);
  550. return *this;
  551. }
  552. QDumper &QDumper::put(const void *p)
  553. {
  554. if (p) {
  555. // Pointer is 'long long' on WIN_64, only
  556. static const char *printFormat = sizeof(void *) == sizeof(long) ? "0x%lx" : "0x%llx";
  557. pos += sprintf(outBuffer + pos, printFormat, p);
  558. } else {
  559. pos += sprintf(outBuffer + pos, "<null>");
  560. }
  561. return *this;
  562. }
  563. QDumper &QDumper::put(const char *str)
  564. {
  565. if (!str)
  566. return put("<null>");
  567. while (*str)
  568. put(*(str++));
  569. return *this;
  570. }
  571. QDumper &QDumper::put(const QByteArray &ba)
  572. {
  573. putBase64Encoded(ba.constData(), ba.size());
  574. return *this;
  575. }
  576. QDumper &QDumper::put(const QString &str)
  577. {
  578. putBase64Encoded((const char *)str.constData(), 2 * str.size());
  579. return *this;
  580. }
  581. void QDumper::checkFill()
  582. {
  583. if (pos >= int(sizeof(outBuffer)) - 100)
  584. full = true;
  585. }
  586. void QDumper::putCommaIfNeeded()
  587. {
  588. if (pos == 0)
  589. return;
  590. char c = outBuffer[pos - 1];
  591. if (c == '}' || c == '"' || c == ']')
  592. put(',');
  593. }
  594. void QDumper::putBase64Encoded(const char *buf, int n)
  595. {
  596. const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
  597. "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
  598. const char padchar = '=';
  599. int padlen = 0;
  600. //int tmpsize = ((n * 4) / 3) + 3;
  601. int i = 0;
  602. while (i < n) {
  603. int chunk = 0;
  604. chunk |= int(uchar(buf[i++])) << 16;
  605. if (i == n) {
  606. padlen = 2;
  607. } else {
  608. chunk |= int(uchar(buf[i++])) << 8;
  609. if (i == n)
  610. padlen = 1;
  611. else
  612. chunk |= int(uchar(buf[i++]));
  613. }
  614. int j = (chunk & 0x00fc0000) >> 18;
  615. int k = (chunk & 0x0003f000) >> 12;
  616. int l = (chunk & 0x00000fc0) >> 6;
  617. int m = (chunk & 0x0000003f);
  618. put(alphabet[j]);
  619. put(alphabet[k]);
  620. put(padlen > 1 ? padchar : alphabet[l]);
  621. put(padlen > 0 ? padchar : alphabet[m]);
  622. }
  623. }
  624. void QDumper::putStringValue(const QString &str)
  625. {
  626. if (str.isNull()) {
  627. beginItem("value");
  628. putBase64Encoded("\"\" (null)", 9);
  629. endItem();
  630. putItem("valueencoded", "5");
  631. } else {
  632. putItem("value", str);
  633. putItem("valueencoded", "2");
  634. }
  635. }
  636. void QDumper::disarm()
  637. {
  638. success = true;
  639. }
  640. void QDumper::beginHash()
  641. {
  642. putCommaIfNeeded();
  643. put('{');
  644. }
  645. void QDumper::endHash()
  646. {
  647. put('}');
  648. }
  649. void QDumper::putEllipsis()
  650. {
  651. putCommaIfNeeded();
  652. put("{name=\"<incomplete>\",value=\"\",type=\"").put(innerType).put("\"}");
  653. }
  654. void QDumper::putItemCount(const char *name, int count)
  655. {
  656. putCommaIfNeeded();
  657. put(name).put("=\"<").put(count).put(" items>\"");
  658. }
  659. void QDumper::putTruncatedItemCount(const char *name, int count)
  660. {
  661. putCommaIfNeeded();
  662. put(name).put("=\"<>").put(count).put(" items>\"");
  663. }
  664. //
  665. // Some helpers to keep the dumper code short
  666. //
  667. void QDumper::beginItem(const char *name)
  668. {
  669. putCommaIfNeeded();
  670. put(name).put('=').put('"');
  671. }
  672. void QDumper::endItem()
  673. {
  674. put('"');
  675. }
  676. void QDumper::beginChildren(const char *mainInnerType)
  677. {
  678. if (mainInnerType) {
  679. putItem("childtype", mainInnerType);
  680. currentChildType = mainInnerType;
  681. if (isSimpleType(mainInnerType) || isStringType(mainInnerType)) {
  682. putItem("childnumchild", "0");
  683. currentChildNumChild = "0";
  684. } else if (isPointerType(mainInnerType)) {
  685. putItem("childnumchild", "1");
  686. currentChildNumChild = "1";
  687. }
  688. }
  689. putCommaIfNeeded();
  690. put("children=[");
  691. }
  692. void QDumper::endChildren()
  693. {
  694. put(']');
  695. currentChildType = 0;
  696. currentChildNumChild = 0;
  697. }
  698. // simple string property
  699. void QDumper::putHash(const char *name, const QString &value)
  700. {
  701. beginHash();
  702. putItem("name", name);
  703. putStringValue(value);
  704. putItem("type", NS "QString");
  705. putItem("numchild", "0");
  706. endHash();
  707. }
  708. void QDumper::putHash(const char *name, const QByteArray &value)
  709. {
  710. beginHash();
  711. putItem("name", name);
  712. putItem("value", value);
  713. putItem("type", NS "QByteArray");
  714. putItem("numchild", "0");
  715. putItem("valueencoded", "1");
  716. endHash();
  717. }
  718. // simple integer property
  719. void QDumper::putHash(const char *name, int value)
  720. {
  721. beginHash();
  722. putItem("name", name);
  723. putItem("value", value);
  724. putItem("type", "int");
  725. putItem("numchild", "0");
  726. endHash();
  727. }
  728. void QDumper::putHash(const char *name, long value)
  729. {
  730. beginHash();
  731. putItem("name", name);
  732. putItem("value", value);
  733. putItem("type", "long");
  734. putItem("numchild", "0");
  735. endHash();
  736. }
  737. void QDumper::putHash(const char *name, float value)
  738. {
  739. beginHash();
  740. putItem("name", name);
  741. putItem("value", value);
  742. putItem("type", "float");
  743. putItem("numchild", "0");
  744. endHash();
  745. }
  746. void QDumper::putHash(const char *name, double value)
  747. {
  748. beginHash();
  749. putItem("name", name);
  750. putItem("value", value);
  751. putItem("type", "double");
  752. putItem("numchild", "0");
  753. endHash();
  754. }
  755. // simple boolean property
  756. void QDumper::putHash(const char *name, bool value)
  757. {
  758. beginHash();
  759. putItem("name", name);
  760. putItem("value", (value ? "true" : "false"));
  761. putItem("type", "bool");
  762. putItem("numchild", "0");
  763. endHash();
  764. }
  765. // a single QChar
  766. void QDumper::putHash(const char *name, QChar value)
  767. {
  768. beginHash();
  769. putItem("name", name);
  770. putStringValue(QString(QLatin1String("'%1' (%2, 0x%3)"))
  771. .arg(value).arg(value.unicode()).arg(value.unicode(), 0, 16));
  772. putItem("type", NS "QChar");
  773. putItem("numchild", "0");
  774. endHash();
  775. }
  776. #define DUMPUNKNOWN_MESSAGE "<not in scope>"
  777. static void qDumpUnknown(QDumper &d, const char *why = 0)
  778. {
  779. if (!why)
  780. why = DUMPUNKNOWN_MESSAGE;
  781. d.putItem("value", why);
  782. d.putItem("valueeditable", "false");
  783. d.putItem("valueenabled", "false");
  784. d.putItem("numchild", "0", d.currentChildNumChild);
  785. d.disarm();
  786. }
  787. static void qDumpStdStringValue(QDumper &d, const std::string &str)
  788. {
  789. d.beginItem("value");
  790. d.putBase64Encoded(str.c_str(), str.size());
  791. d.endItem();
  792. d.putItem("valueencoded", "1");
  793. d.putItem("type", "std::string");
  794. d.putItem("numchild", "0", d.currentChildNumChild);
  795. }
  796. static void qDumpStdWStringValue(QDumper &d, const std::wstring &str)
  797. {
  798. d.beginItem("value");
  799. d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t));
  800. d.endItem();
  801. d.putItem("valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3"));
  802. d.putItem("type", "std::wstring", d.currentChildType);
  803. d.putItem("numchild", "0", d.currentChildNumChild);
  804. }
  805. // Called by templates, so, not static.
  806. static void qDumpInnerQCharValue(QDumper &d, QChar c, const char *field)
  807. {
  808. char buf[30];
  809. sprintf(buf, "'?', ucs=%d", c.unicode());
  810. if (c.isPrint() && c.unicode() < 127)
  811. buf[1] = char(c.unicode());
  812. d.putCommaIfNeeded();
  813. d.putItem(field, buf);
  814. d.putItem("numchild", "0", d.currentChildNumChild);
  815. }
  816. static void qDumpInnerCharValue(QDumper &d, char c, const char *field)
  817. {
  818. char buf[30];
  819. sprintf(buf, "'?', ascii=%d", c);
  820. if (QChar(QLatin1Char(c)).isPrint() && c < 127)
  821. buf[1] = c;
  822. d.putCommaIfNeeded();
  823. d.putItem(field, buf);
  824. d.putItem("numchild", "0", d.currentChildNumChild);
  825. }
  826. void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
  827. const char *field = "value")
  828. {
  829. type = stripNamespace(type);
  830. switch (type[1]) {
  831. case 'h':
  832. if (isEqual(type, "char"))
  833. qDumpInnerCharValue(d, *(char *)addr, field);
  834. break;
  835. case 'l':
  836. if (isEqual(type, "float"))
  837. d.putItem(field, *(float*)addr);
  838. break;
  839. case 'n':
  840. if (isEqual(type, "int"))
  841. d.putItem(field, *(int*)addr);
  842. else if (isEqual(type, "unsigned") || isEqual(type, "unsigned int"))
  843. d.putItem(field, *(unsigned int*)addr);
  844. else if (isEqual(type, "unsigned char"))
  845. qDumpInnerCharValue(d, *(char *)addr, field);
  846. else if (isEqual(type, "unsigned long"))
  847. d.putItem(field, *(unsigned long*)addr);
  848. else if (isEqual(type, "unsigned long long"))
  849. d.putItem(field, *(qulonglong*)addr);
  850. break;
  851. case 'o':
  852. if (isEqual(type, "bool")) {
  853. switch (*(unsigned char*)addr) {
  854. case 0: d.putItem(field, "false"); break;
  855. case 1: d.putItem(field, "true"); break;
  856. default: d.putItem(field, *(unsigned char*)addr); break;
  857. }
  858. } else if (isEqual(type, "double"))
  859. d.putItem(field, *(double*)addr);
  860. else if (isEqual(type, "long"))
  861. d.putItem(field, *(long*)addr);
  862. else if (isEqual(type, "long long"))
  863. d.putItem(field, *(qulonglong*)addr);
  864. break;
  865. case 'B':
  866. if (isEqual(type, "QByteArray")) {
  867. d.putCommaIfNeeded();
  868. d.put(field).put("encoded=\"1\",");
  869. d.putItem(field, *(QByteArray*)addr);
  870. }
  871. break;
  872. case 'C':
  873. if (isEqual(type, "QChar"))
  874. qDumpInnerQCharValue(d, *(QChar*)addr, field);
  875. break;
  876. case 'L':
  877. if (startsWith(type, "QList<")) {
  878. const QListData *ldata = reinterpret_cast<const QListData*>(addr);
  879. d.putItemCount("value", ldata->size());
  880. d.putItem("valueeditable", "false");
  881. d.putItem("numchild", ldata->size());
  882. }
  883. break;
  884. case 'O':
  885. # ifndef QT_BOOTSTRAPPED
  886. if (isEqual(type, "QObject *")) {
  887. if (addr) {
  888. const QObject *ob = reinterpret_cast<const QObject *>(addr);
  889. d.putItem("addr", ob);
  890. d.putItem("value", ob->objectName());
  891. d.putItem("valueencoded", "2");
  892. d.putItem("type", NS "QObject");
  893. d.putItem("displayedtype", ob->metaObject()->className());
  894. d.putItem("numchild", 1);
  895. } else {
  896. d.putItem("value", "0x0");
  897. d.putItem("type", NS "QObject *");
  898. d.putItem("numchild", 0);
  899. }
  900. }
  901. # endif
  902. break;
  903. case 'S':
  904. if (isEqual(type, "QString")) {
  905. d.putCommaIfNeeded();
  906. d.putItem(field, *(QString*)addr);
  907. d.put(',').put(field).put("encoded=\"2\"");
  908. }
  909. break;
  910. case 't':
  911. if (isEqual(type, "std::string")
  912. || isEqual(type, stdStringTypeC)) {
  913. d.putCommaIfNeeded();
  914. qDumpStdStringValue(d, *reinterpret_cast<const std::string*>(addr));
  915. } else if (isEqual(type, "std::wstring")
  916. || isEqual(type, stdWideStringTypeUShortC)) {
  917. qDumpStdWStringValue(d, *reinterpret_cast<const std::wstring*>(addr));
  918. }
  919. break;
  920. default:
  921. break;
  922. }
  923. }
  924. #if USE_QT_CORE
  925. static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
  926. {
  927. d.putItem("addr", addr);
  928. d.putItem("type", type, d.currentChildType);
  929. if (!type[0])
  930. return;
  931. return qDumpInnerValueHelper(d, type, addr);
  932. }
  933. #endif
  934. static void qDumpInnerValueOrPointer(QDumper &d,
  935. const char *type, const char *strippedtype, const void *addr)
  936. {
  937. if (strippedtype) {
  938. if (deref(addr)) {
  939. d.putItem("addr", deref(addr));
  940. d.putItem("type", strippedtype, d.currentChildType);
  941. qDumpInnerValueHelper(d, strippedtype, deref(addr));
  942. } else {
  943. d.putItem("addr", addr);
  944. d.putItem("type", strippedtype);
  945. d.putItem("value", "<null>");
  946. d.putItem("numchild", "0");
  947. }
  948. } else {
  949. d.putItem("addr", addr);
  950. d.putItem("type", type, d.currentChildType);
  951. qDumpInnerValueHelper(d, type, addr);
  952. }
  953. }
  954. //////////////////////////////////////////////////////////////////////////////
  955. #if USE_QT_CORE
  956. #ifndef QT_BOOTSTRAPPED
  957. struct ModelIndex { int r; int c; void *p; void *m; };
  958. static void qDumpQAbstractItem(QDumper &d)
  959. {
  960. QModelIndex mi;
  961. {
  962. ModelIndex *mm = reinterpret_cast<ModelIndex *>(&mi);
  963. memset(&mi, 0, sizeof(mi));
  964. static const char *printFormat = sizeof(void *) == sizeof(long) ?
  965. "%d,%d,0x%lx,0x%lx" : "%d,%d,0x%llx,0x%llx";
  966. sscanf(d.templateParameters[0], printFormat, &mm->r, &mm->c, &mm->p, &mm->m);
  967. }
  968. const QAbstractItemModel *m = mi.model();
  969. const int rowCount = m->rowCount(mi);
  970. if (rowCount < 0)
  971. return;
  972. const int columnCount = m->columnCount(mi);
  973. if (columnCount < 0)
  974. return;
  975. d.putItem("type", NS "QAbstractItem");
  976. d.beginItem("addr");
  977. d.put('$').put(mi.row()).put(',').put(mi.column()).put(',')
  978. .put(mi.internalPointer()).put(',').put(mi.model());
  979. d.endItem();
  980. //d.putItem("value", "(").put(rowCount).put(",").put(columnCount).put(")");
  981. d.putItem("value", m->data(mi, Qt::DisplayRole).toString());
  982. d.putItem("valueencoded", "2");
  983. d.putItem("numchild", rowCount * columnCount);
  984. if (d.dumpChildren) {
  985. d.beginChildren();
  986. for (int row = 0; row < rowCount; ++row) {
  987. for (int column = 0; column < columnCount; ++column) {
  988. QModelIndex child = m->index(row, column, mi);
  989. d.beginHash();
  990. d.beginItem("name");
  991. d.put("[").put(row).put(",").put(column).put("]");
  992. d.endItem();
  993. //d.putItem("numchild", (m->hasChildren(child) ? "1" : "0"));
  994. d.putItem("numchild", m->rowCount(child) * m->columnCount(child));
  995. d.beginItem("addr");
  996. d.put("$").put(child.row()).put(",").put(child.column()).put(",")
  997. .put(child.internalPointer()).put(",").put(child.model());
  998. d.endItem();
  999. d.putItem("type", NS "QAbstractItem");
  1000. d.putItem("value", m->data(child, Qt::DisplayRole).toString());
  1001. d.putItem("valueencoded", "2");
  1002. d.endHash();
  1003. }
  1004. }
  1005. /*
  1006. d.beginHash();
  1007. d.putItem("name", "DisplayRole");
  1008. d.putItem("numchild", 0);
  1009. d.putItem("value", m->data(mi, Qt::DisplayRole).toString());
  1010. d.putItem("valueencoded", 2);
  1011. d.putItem("type", NS "QString");
  1012. d.endHash();
  1013. */
  1014. d.endChildren();
  1015. }
  1016. d.disarm();
  1017. }
  1018. static void qDumpQAbstractItemModel(QDumper &d)
  1019. {
  1020. const QAbstractItemModel &m = *reinterpret_cast<const QAbstractItemModel *>(d.data);
  1021. const int rowCount = m.rowCount();
  1022. if (rowCount < 0)
  1023. return;
  1024. const int columnCount = m.columnCount();
  1025. if (columnCount < 0)
  1026. return;
  1027. d.putItem("type", NS "QAbstractItemModel");
  1028. d.beginItem("value");
  1029. d.put("(").put(rowCount).put(",").put(columnCount).put(")");
  1030. d.endItem();
  1031. d.putItem("numchild", "1");
  1032. if (d.dumpChildren) {
  1033. d.beginChildren();
  1034. d.beginHash();
  1035. d.putItem("numchild", "1");
  1036. d.putItem("name", NS "QObject");
  1037. d.putItem("addr", d.data);
  1038. d.putItem("value", m.objectName());
  1039. d.putItem("valueencoded", "2");
  1040. d.putItem("type", NS "QObject");
  1041. d.putItem("displayedtype", m.metaObject()->className());
  1042. d.endHash();
  1043. for (int row = 0; row < rowCount; ++row) {
  1044. for (int column = 0; column < columnCount; ++column) {
  1045. QModelIndex mi = m.index(row, column);
  1046. d.beginHash();
  1047. d.beginItem("name");
  1048. d.put("[").put(row).put(",").put(column).put("]");
  1049. d.endItem();
  1050. d.putItem("value", m.data(mi, Qt::DisplayRole).toString());
  1051. d.putItem("valueencoded", "2");
  1052. //d.putItem("numchild", (m.hasChildren(mi) ? "1" : "0"));
  1053. d.putItem("numchild", m.rowCount(mi) * m.columnCount(mi));
  1054. d.beginItem("addr");
  1055. d.put("$").put(mi.row()).put(",").put(mi.column()).put(",");
  1056. d.put(mi.internalPointer()).put(",").put(mi.model());
  1057. d.endItem();
  1058. d.putItem("type", NS "QAbstractItem");
  1059. d.endHash();
  1060. }
  1061. }
  1062. d.endChildren();
  1063. }
  1064. d.disarm();
  1065. }
  1066. #endif // QT_BOOTSTRAPPED
  1067. static void qDumpQByteArray(QDumper &d)
  1068. {
  1069. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1070. const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
  1071. const int size = ba.size();
  1072. if (size < 0)
  1073. return;
  1074. if (!ba.isEmpty()) {
  1075. qCheckAccess(ba.constData());
  1076. qCheckAccess(ba.constData() + size);
  1077. }
  1078. d.beginItem("value");
  1079. if (size <= 100)
  1080. d.put(ba);
  1081. else
  1082. d.put(ba.left(100)).put(" <size: ").put(size).put(", cut...>");
  1083. d.endItem();
  1084. d.putItem("valueencoded", "1");
  1085. d.putItem("type", NS "QByteArray");
  1086. d.putItem("numchild", size);
  1087. if (d.dumpChildren) {
  1088. d.putItem("childtype", "char");
  1089. d.putItem("childnumchild", "0");
  1090. d.beginChildren();
  1091. char buf[20];
  1092. for (int i = 0; i != size; ++i) {
  1093. unsigned char c = ba.at(i);
  1094. unsigned char u = (isprint(c) && c != '\'' && c != '"') ? c : '?';
  1095. sprintf(buf, "%02x (%u '%c')", c, c, u);
  1096. d.beginHash();
  1097. d.putItem("value", buf);
  1098. d.endHash();
  1099. }
  1100. d.endChildren();
  1101. }
  1102. d.disarm();
  1103. }
  1104. static void qDumpQChar(QDumper &d)
  1105. {
  1106. qDumpInnerQCharValue(d, *reinterpret_cast<const QChar *>(d.data), "value");
  1107. d.disarm();
  1108. }
  1109. static void qDumpQDate(QDumper &d)
  1110. {
  1111. #ifdef QT_NO_DATESTRING
  1112. qDumpUnknown(d);
  1113. #else
  1114. const QDate &date = *reinterpret_cast<const QDate *>(d.data);
  1115. if (date.isNull()) {
  1116. d.putItem("value", "(null)");
  1117. d.putItem("type", NS "QDate");
  1118. d.putItem("numchild", "0");
  1119. return;
  1120. }
  1121. d.putItem("value", date.toString());
  1122. d.putItem("valueencoded", "2");
  1123. d.putItem("type", NS "QDate");
  1124. d.putItem("numchild", "1");
  1125. if (d.dumpChildren) {
  1126. d.beginChildren();
  1127. d.putHash("isNull", date.isNull());
  1128. d.putHash("toString", date.toString());
  1129. # if QT_VERSION >= 0x040500
  1130. d.putHash("toString_(ISO)", date.toString(Qt::ISODate));
  1131. d.putHash("toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
  1132. d.putHash("toString_(Locale)", date.toString(Qt::LocaleDate));
  1133. # endif
  1134. d.endChildren();
  1135. }
  1136. d.disarm();
  1137. #endif // ifdef QT_NO_DATESTRING
  1138. }
  1139. static void qDumpQTime(QDumper &d)
  1140. {
  1141. #ifdef QT_NO_DATESTRING
  1142. qDumpUnknown(d);
  1143. #else
  1144. const QTime &date = *reinterpret_cast<const QTime *>(d.data);
  1145. if (date.isNull()) {
  1146. d.putItem("value", "(null)");
  1147. d.putItem("type", NS "QTime");
  1148. d.putItem("numchild", "0");
  1149. return;
  1150. }
  1151. d.putItem("value", date.toString());
  1152. d.putItem("valueencoded", "2");
  1153. d.putItem("type", NS "QTime");
  1154. d.putItem("numchild", "1");
  1155. if (d.dumpChildren) {
  1156. d.beginChildren();
  1157. d.putHash("isNull", date.isNull());
  1158. d.putHash("toString", date.toString());
  1159. # if QT_VERSION >= 0x040500
  1160. d.putHash("toString_(ISO)", date.toString(Qt::ISODate));
  1161. d.putHash("toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
  1162. d.putHash("toString_(Locale)", date.toString(Qt::LocaleDate));
  1163. # endif
  1164. d.endChildren();
  1165. }
  1166. d.disarm();
  1167. #endif // ifdef QT_NO_DATESTRING
  1168. }
  1169. static void qDumpQDateTime(QDumper &d)
  1170. {
  1171. #ifdef QT_NO_DATESTRING
  1172. qDumpUnknown(d);
  1173. #else
  1174. const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data);
  1175. if (date.isNull()) {
  1176. d.putItem("value", "(null)");
  1177. d.putItem("type", NS "QDateTime");
  1178. d.putItem("numchild", "0");
  1179. d.disarm();
  1180. return;
  1181. }
  1182. d.putItem("value", date.toString());
  1183. d.putItem("valueencoded", "2");
  1184. d.putItem("type", NS "QDateTime");
  1185. d.putItem("numchild", "1");
  1186. if (d.dumpChildren) {
  1187. d.beginChildren();
  1188. d.putHash("toTime_t", (long)date.toTime_t());
  1189. d.putHash("toString", date.toString());
  1190. # if QT_VERSION >= 0x040500
  1191. d.putHash("toString_(ISO)", date.toString(Qt::ISODate));
  1192. d.putHash("toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
  1193. d.putHash("toString_(Locale)", date.toString(Qt::LocaleDate));
  1194. # endif
  1195. # if 0
  1196. d.beginHash();
  1197. d.putItem("name", "toUTC");
  1198. d.putItem("exp", "((" NSX "QDateTime" NSY "*)").put(d.data).put(")"
  1199. "->toTimeSpec('" NS "Qt::UTC')");
  1200. d.putItem("type", NS "QDateTime");
  1201. d.putItem("numchild", "1");
  1202. d.endHash();
  1203. # endif
  1204. # if 0
  1205. d.beginHash();
  1206. d.putItem("name", "toLocalTime");
  1207. d.putItem("exp", "((" NSX "QDateTime" NSY "*)").put(d.data).put(")"
  1208. "->toTimeSpec('" NS "Qt::LocalTime')");
  1209. d.putItem("type", NS "QDateTime");
  1210. d.putItem("numchild", "1");
  1211. d.endHash();
  1212. # endif
  1213. d.endChildren();
  1214. }
  1215. d.disarm();
  1216. #endif // ifdef QT_NO_DATESTRING
  1217. }
  1218. static void qDumpQDir(QDumper &d)
  1219. {
  1220. const QDir &dir = *reinterpret_cast<const QDir *>(d.data);
  1221. d.putItem("value", dir.path());
  1222. d.putItem("valueencoded", "2");
  1223. d.putItem("type", NS "QDir");
  1224. d.putItem("numchild", "3");
  1225. if (d.dumpChildren) {
  1226. d.beginChildren();
  1227. d.putHash("absolutePath", dir.absolutePath());
  1228. d.putHash("canonicalPath", dir.canonicalPath());
  1229. d.endChildren();
  1230. }
  1231. d.disarm();
  1232. }
  1233. static void qDumpQFile(QDumper &d)
  1234. {
  1235. const QFile &file = *reinterpret_cast<const QFile *>(d.data);
  1236. d.putItem("value", file.fileName());
  1237. d.putItem("valueencoded", "2");
  1238. d.putItem("type", NS "QFile");
  1239. d.putItem("numchild", "2");
  1240. if (d.dumpChildren) {
  1241. d.beginChildren();
  1242. d.putHash("fileName", file.fileName());
  1243. d.putHash("exists", file.exists());
  1244. d.endChildren();
  1245. }
  1246. d.disarm();
  1247. }
  1248. static void qDumpQFileInfo(QDumper &d)
  1249. {
  1250. const QFileInfo &info = *reinterpret_cast<const QFileInfo *>(d.data);
  1251. d.putItem("value", info.filePath());
  1252. d.putItem("valueencoded", "2");
  1253. d.putItem("type", NS "QFileInfo");
  1254. d.putItem("numchild", "3");
  1255. if (d.dumpChildren) {
  1256. d.beginChildren();
  1257. d.putHash("absolutePath", info.absolutePath());
  1258. d.putHash("absoluteFilePath", info.absoluteFilePath());
  1259. d.putHash("canonicalPath", info.canonicalPath());
  1260. d.putHash("canonicalFilePath", info.canonicalFilePath());
  1261. d.putHash("completeBaseName", info.completeBaseName());
  1262. d.putHash("completeSuffix", info.completeSuffix());
  1263. d.putHash("baseName", info.baseName());
  1264. #ifdef Q_OS_MACX
  1265. d.putHash("isBundle", info.isBundle());
  1266. d.putHash("bundleName", info.bundleName());
  1267. #endif
  1268. d.putHash("fileName", info.fileName());
  1269. d.putHash("filePath", info.filePath());
  1270. d.putHash("group", info.group());
  1271. d.putHash("owner", info.owner());
  1272. d.putHash("path", info.path());
  1273. d.putHash("groupid", (long)info.groupId());
  1274. d.putHash("ownerid", (long)info.ownerId());
  1275. //QFile::Permissions permissions () const
  1276. long perms = info.permissions();
  1277. d.beginHash();
  1278. d.putItem("name", "permissions");
  1279. d.putItem("value", " ");
  1280. d.putItem("type", NS "QFile::Permissions");
  1281. d.putItem("numchild", 10);
  1282. d.beginChildren();
  1283. d.putHash("ReadOwner", bool(perms & QFile::ReadOwner));
  1284. d.putHash("WriteOwner", bool(perms & QFile::WriteOwner));
  1285. d.putHash("ExeOwner", bool(perms & QFile::ExeOwner));
  1286. d.putHash("ReadUser", bool(perms & QFile::ReadUser));
  1287. d.putHash("WriteUser", bool(perms & QFile::WriteUser));
  1288. d.putHash("ExeUser", bool(perms & QFile::ExeUser));
  1289. d.putHash("ReadGroup", bool(perms & QFile::ReadGroup));
  1290. d.putHash("WriteGroup", bool(perms & QFile::WriteGroup));
  1291. d.putHash("ExeGroup", bool(perms & QFile::ExeGroup));
  1292. d.putHash("ReadOther", bool(perms & QFile::ReadOther));
  1293. d.putHash("WriteOther", bool(perms & QFile::WriteOther));
  1294. d.putHash("ExeOther", bool(perms & QFile::ExeOther));
  1295. d.endChildren();
  1296. d.endHash();
  1297. //QDir absoluteDir () const
  1298. //QDir dir () const
  1299. d.putHash("caching", info.caching());
  1300. d.putHash("exists", info.exists());
  1301. d.putHash("isAbsolute", info.isAbsolute());
  1302. d.putHash("isDir", info.isDir());
  1303. d.putHash("isExecutable", info.isExecutable());
  1304. d.putHash("isFile", info.isFile());
  1305. d.putHash("isHidden", info.isHidden());
  1306. d.putHash("isReadable", info.isReadable());
  1307. d.putHash("isRelative", info.isRelative());
  1308. d.putHash("isRoot", info.isRoot());
  1309. d.putHash("isSymLink", info.isSymLink());
  1310. d.putHash("isWritable", info.isWritable());
  1311. d.beginHash();
  1312. d.putItem("name", "created");
  1313. d.putItem("value", info.created().toString());
  1314. d.putItem("valueencoded", "2");
  1315. d.beginItem("exp");
  1316. d.put("((" NSX "QFileInfo" NSY "*)").put(d.data).put(")->created()");
  1317. d.endItem();
  1318. d.putItem("type", NS "QDateTime");
  1319. d.putItem("numchild", "1");
  1320. d.endHash();
  1321. d.beginHash();
  1322. d.putItem("name", "lastModified");
  1323. d.putItem("value", info.lastModified().toString());
  1324. d.putItem("valueencoded", "2");
  1325. d.beginItem("exp");
  1326. d.put("((" NSX "QFileInfo" NSY "*)").put(d.data).put(")->lastModified()");
  1327. d.endItem();
  1328. d.putItem("type", NS "QDateTime");
  1329. d.putItem("numchild", "1");
  1330. d.endHash();
  1331. d.beginHash();
  1332. d.putItem("name", "lastRead");
  1333. d.putItem("value", info.lastRead().toString());
  1334. d.putItem("valueencoded", "2");
  1335. d.beginItem("exp");
  1336. d.put("((" NSX "QFileInfo" NSY "*)").put(d.data).put(")->lastRead()");
  1337. d.endItem();
  1338. d.putItem("type", NS "QDateTime");
  1339. d.putItem("numchild", "1");
  1340. d.endHash();
  1341. d.endChildren();
  1342. }
  1343. d.disarm();
  1344. }
  1345. bool isOptimizedIntKey(const char *keyType)
  1346. {
  1347. return isEqual(keyType, "int")
  1348. #if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
  1349. || isEqual(keyType, "short")
  1350. || isEqual(keyType, "ushort")
  1351. #endif
  1352. || isEqual(keyType, "uint");
  1353. }
  1354. int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned valueSize)
  1355. {
  1356. // int-key optimization, small value
  1357. struct NodeOS { void *next; uint k; uint v; } nodeOS;
  1358. // int-key optimiatzion, large value
  1359. struct NodeOL { void *next; uint k; void *v; } nodeOL;
  1360. // no optimization, small value
  1361. struct NodeNS { void *next; uint h; uint k; uint v; } nodeNS;
  1362. // no optimization, large value
  1363. struct NodeNL { void *next; uint h; uint k; void *v; } nodeNL;
  1364. // complex key
  1365. struct NodeL { void *next; uint h; void *k; void *v; } nodeL;
  1366. if (forKey) {
  1367. // offsetof(...,...) not yet in Standard C++
  1368. const ulong nodeOSk ( (char *)&nodeOS.k - (char *)&nodeOS );
  1369. const ulong nodeOLk ( (char *)&nodeOL.k - (char *)&nodeOL );
  1370. const ulong nodeNSk ( (char *)&nodeNS.k - (char *)&nodeNS );
  1371. const ulong nodeNLk ( (char *)&nodeNL.k - (char *)&nodeNL );
  1372. const ulong nodeLk ( (char *)&nodeL.k - (char *)&nodeL );
  1373. if (optimizedIntKey)
  1374. return valueSize > sizeof(int) ? nodeOLk : nodeOSk;
  1375. if (keySize > sizeof(int))
  1376. return nodeLk;
  1377. return valueSize > sizeof(int) ? nodeNLk : nodeNSk;
  1378. } else {
  1379. const ulong nodeOSv ( (char *)&nodeOS.v - (char *)&nodeOS );
  1380. const ulong nodeOLv ( (char *)&nodeOL.v - (char *)&nodeOL );
  1381. const ulong nodeNSv ( (char *)&nodeNS.v - (char *)&nodeNS );
  1382. const ulong nodeNLv ( (char *)&nodeNL.v - (char *)&nodeNL );
  1383. const ulong nodeLv ( (char *)&nodeL.v - (char *)&nodeL );
  1384. if (optimizedIntKey)
  1385. return valueSize > sizeof(int) ? nodeOLv : nodeOSv;
  1386. if (keySize > sizeof(int))
  1387. return nodeLv;
  1388. return valueSize > sizeof(int) ? nodeNLv : nodeNSv;
  1389. }
  1390. }
  1391. static void qDumpQHash(QDumper &d)
  1392. {
  1393. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1394. const char *keyType = d.templateParameters[0];
  1395. const char *valueType = d.templateParameters[1];
  1396. QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
  1397. qCheckPointer(h->fakeNext);
  1398. qCheckPointer(h->buckets);
  1399. unsigned keySize = d.extraInt[0];
  1400. unsigned valueSize = d.extraInt[1];
  1401. int n = h->size;
  1402. if (n < 0)
  1403. return;
  1404. if (n > 0) {
  1405. qCheckPointer(h->fakeNext);
  1406. qCheckPointer(*h->buckets);
  1407. }
  1408. d.putItemCount("value", n);
  1409. d.putItem("numchild", n);
  1410. if (d.dumpChildren) {
  1411. const bool isSimpleKey = isSimpleType(keyType);
  1412. const bool isSimpleValue = isSimpleType(valueType);
  1413. const bool opt = isOptimizedIntKey(keyType);
  1414. const int keyOffset = hashOffset(opt, true, keySize, valueSize);
  1415. const int valueOffset = hashOffset(opt, false, keySize, valueSize);
  1416. #if 0
  1417. d.beginItem("extra");
  1418. d.put("isSimpleKey: ").put(isSimpleKey);
  1419. d.put(" isSimpleValue: ").put(isSimpleValue);
  1420. d.put(" valueType: '").put(isSimpleValue);
  1421. d.put(" keySize: ").put(keyOffset);
  1422. d.put(" valueOffset: ").put(valueOffset);
  1423. d.put(" opt: ").put(opt);
  1424. d.endItem();
  1425. #endif
  1426. QHashData::Node *node = h->firstNode();
  1427. QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h);
  1428. int i = 0;
  1429. d.beginChildren();
  1430. while (node != end) {
  1431. d.beginHash();
  1432. qDumpInnerValueHelper(d, keyType, addOffset(node, keyOffset), "key");
  1433. qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
  1434. if (isSimpleKey && isSimpleValue) {
  1435. d.putItem("type", valueType);
  1436. d.putItem("addr", addOffset(node, valueOffset));
  1437. } else {
  1438. d.putItem("addr", node);
  1439. d.beginItem("type");
  1440. d.put(NS "QHashNode<").put(keyType).put(",")
  1441. .put(valueType).put(" >");
  1442. d.endItem();
  1443. }
  1444. d.endHash();
  1445. ++i;
  1446. node = QHashData::nextNode(node);
  1447. }
  1448. d.endChildren();
  1449. }
  1450. d.disarm();
  1451. }
  1452. static void qDumpQHashNode(QDumper &d)
  1453. {
  1454. const QHashData *h = reinterpret_cast<const QHashData *>(d.data);
  1455. const char *keyType = d.templateParameters[0];
  1456. const char *valueType = d.templateParameters[1];
  1457. unsigned keySize = d.extraInt[0];
  1458. unsigned valueSize = d.extraInt[1];
  1459. bool opt = isOptimizedIntKey(keyType);
  1460. int keyOffset = hashOffset(opt, true, keySize, valueSize);
  1461. int valueOffset = hashOffset(opt, false, keySize, valueSize);
  1462. if (isSimpleType(valueType))
  1463. qDumpInnerValueHelper(d, valueType, addOffset(h, valueOffset));
  1464. else
  1465. d.putItem("value", "");
  1466. d.putItem("numchild", 2);
  1467. if (d.dumpChildren) {
  1468. // there is a hash specialization in case the keys are integers or shorts
  1469. d.beginChildren();
  1470. d.beginHash();
  1471. d.putItem("name", "key");
  1472. d.putItem("type", keyType);
  1473. d.putItem("addr", addOffset(h, keyOffset));
  1474. d.endHash();
  1475. d.beginHash();
  1476. d.putItem("name", "value");
  1477. d.putItem("type", valueType);
  1478. d.putItem("addr", addOffset(h, valueOffset));
  1479. d.endHash();
  1480. d.endChildren();
  1481. }
  1482. d.disarm();
  1483. }
  1484. #if USE_QT_GUI
  1485. static void qDumpQImage(QDumper &d)
  1486. {
  1487. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1488. const QImage &im = *reinterpret_cast<const QImage *>(d.data);
  1489. d.beginItem("value");
  1490. d.put("(").put(im.width()).put("x").put(im.height()).put(")");
  1491. d.endItem();
  1492. d.putItem("type", NS "QImage");
  1493. d.putItem("numchild", "0");
  1494. #if 0
  1495. if (d.dumpChildren) {
  1496. d.beginChildren();
  1497. d.beginHash();
  1498. d.putItem("name", "data");
  1499. d.putItem("type", NS "QImageData");
  1500. d.putItem("addr", d.data);
  1501. d.endHash();
  1502. d.endChildren();
  1503. }
  1504. #endif
  1505. d.disarm();
  1506. }
  1507. #endif
  1508. #if USE_QT_GUI
  1509. static void qDumpQImageData(QDumper &d)
  1510. {
  1511. const QImage &im = *reinterpret_cast<const QImage *>(d.data);
  1512. const QByteArray ba(QByteArray::fromRawData((const char*)im.bits(), im.byteCount()));
  1513. d.putItem("type", NS "QImageData");
  1514. d.putItem("numchild", "0");
  1515. #if 1
  1516. d.putItem("value", "<hover here>");
  1517. d.putItem("valuetooltipencoded", "1");
  1518. d.putItem("valuetooltipsize", ba.size());
  1519. d.putItem("valuetooltip", ba);
  1520. #else
  1521. d.putItem("valueencoded", "1");
  1522. d.putItem("value", ba);
  1523. #endif
  1524. d.disarm();
  1525. }
  1526. #endif
  1527. static void qDumpQList(QDumper &d)
  1528. {
  1529. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1530. // This uses the knowledge that QList<T> has only a single member
  1531. // of type union { QListData p; QListData::Data *d; };
  1532. const QListData &pdata = *reinterpret_cast<const QListData*>(d.data);
  1533. const int nn = pdata.size();
  1534. if (nn < 0)
  1535. return;
  1536. const bool innerTypeIsPointer = isPointerType(d.innerType);
  1537. const int n = qMin(nn, 1000);
  1538. if (nn > 0) {
  1539. if (pdata.d->begin < 0)
  1540. return;
  1541. if (pdata.d->begin > pdata.d->end)
  1542. return;
  1543. #if QT_VERSION >= 0x050000
  1544. if (pdata.d->ref.atomic._q_value <= 0)
  1545. return;
  1546. #elif QT_VERSION >= 0x040400
  1547. if (pdata.d->ref._q_value <= 0)
  1548. return;
  1549. #endif
  1550. qCheckAccess(pdata.d->array);
  1551. // Additional checks on pointer arrays
  1552. if (innerTypeIsPointer)
  1553. for (int i = 0; i != n; ++i)
  1554. if (const void *p = pdata.d->array + i + pdata.d->begin)
  1555. qCheckPointer(deref(p));
  1556. }
  1557. d.putItemCount("value", nn);
  1558. d.putItem("valueeditable", "false");
  1559. d.putItem("numchild", n);
  1560. if (d.dumpChildren) {
  1561. const unsigned innerSize = d.extraInt[0];
  1562. QByteArray strippedInnerType = stripPointerType(d.innerType);
  1563. // The exact condition here is:
  1564. // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
  1565. // but this data is available neither in the compiled binary nor
  1566. // in the frontend.
  1567. // So as first approximation only do the 'isLarge' check:
  1568. bool isInternal = innerSize <= int(sizeof(void*))
  1569. && isMovableType(d.innerType);
  1570. d.putItem("internal", (int)isInternal);
  1571. d.beginChildren(n ? d.innerType : 0);
  1572. for (int i = 0; i != n; ++i) {
  1573. d.beginHash();
  1574. if (innerTypeIsPointer) {
  1575. void *p = pdata.d->array + i + pdata.d->begin;
  1576. if (*(void**)p) {
  1577. //d.putItem("value","@").put(p);
  1578. qDumpInnerValue(d, strippedInnerType.data(), deref(p));
  1579. } else {
  1580. d.putItem("value", "<null>");
  1581. d.putItem("numchild", "0");
  1582. }
  1583. } else {
  1584. void *p = pdata.d->array + i + pdata.d->begin;
  1585. if (isInternal) {
  1586. //qDumpInnerValue(d, d.innerType, p);
  1587. d.putItem("addr", p);
  1588. qDumpInnerValueHelper(d, d.innerType, p);
  1589. } else {
  1590. //qDumpInnerValue(d, d.innerType, deref(p));
  1591. d.putItem("addr", deref(p));
  1592. qDumpInnerValueHelper(d, d.innerType, deref(p));
  1593. }
  1594. }
  1595. d.endHash();
  1596. }
  1597. if (n < nn)
  1598. d.putEllipsis();
  1599. d.endChildren();
  1600. }
  1601. d.disarm();
  1602. }
  1603. static void qDumpQLinkedList(QDumper &d)
  1604. {
  1605. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1606. // This uses the knowledge that QLinkedList<T> has only a single member
  1607. // of type union { QLinkedListData *d; QLinkedListNode<T> *e; };
  1608. const QLinkedListData *ldata =
  1609. reinterpret_cast<const QLinkedListData*>(deref(d.data));
  1610. int nn = ldata->size;
  1611. if (nn < 0)
  1612. return;
  1613. int n = nn;
  1614. d.putItemCount("value", n);
  1615. d.putItem("valueeditable", "false");
  1616. d.putItem("numchild", n);
  1617. if (d.dumpChildren) {
  1618. //unsigned innerSize = d.extraInt[0];
  1619. //bool innerTypeIsPointer = isPointerType(d.innerType);
  1620. QByteArray strippedInnerType = stripPointerType(d.innerType);
  1621. const char *stripped =
  1622. isPointerType(d.innerType) ? strippedInnerType.data() : 0;
  1623. if (n > 1000)
  1624. n = 1000;
  1625. d.beginChildren(d.innerType);
  1626. const void *p = deref(ldata);
  1627. for (int i = 0; i != n; ++i) {
  1628. d.beginHash();
  1629. const void *addr = addOffset(p, 2 * sizeof(void*));
  1630. qDumpInnerValueOrPointer(d, d.innerType, stripped, addr);
  1631. p = deref(p);
  1632. d.endHash();
  1633. }
  1634. if (n < nn)
  1635. d.putEllipsis();
  1636. d.endChildren();
  1637. }
  1638. d.disarm();
  1639. }
  1640. static void qDumpQLocale(QDumper &d)
  1641. {
  1642. const QLocale &locale = *reinterpret_cast<const QLocale *>(d.data);
  1643. d.putItem("value", locale.name());
  1644. d.putItem("valueencoded", "2");
  1645. d.putItem("type", NS "QLocale");
  1646. d.putItem("numchild", "8");
  1647. if (d.dumpChildren) {
  1648. d.beginChildren();
  1649. d.beginHash();
  1650. d.putItem("name", "country");
  1651. d.beginItem("exp");
  1652. d.put("((" NSX "QLocale" NSY "*)").put(d.data).put(")->country()");
  1653. d.endItem();
  1654. d.endHash();
  1655. d.beginHash();
  1656. d.putItem("name", "language");
  1657. d.beginItem("exp");
  1658. d.put("((" NSX "QLocale" NSY "*)").put(d.data).put(")->language()");
  1659. d.endItem();
  1660. d.endHash();
  1661. d.beginHash();
  1662. d.putItem("name", "measurementSystem");
  1663. d.beginItem("exp");
  1664. d.put("((" NSX "QLocale" NSY "*)").put(d.data).put(")->measurementSystem()");
  1665. d.endItem();
  1666. d.endHash();
  1667. d.beginHash();
  1668. d.putItem("name", "numberOptions");
  1669. d.beginItem("exp");
  1670. d.put("((" NSX "QLocale" NSY "*)").put(d.data).put(")->numberOptions()");
  1671. d.endItem();
  1672. d.endHash();
  1673. d.putHash("timeFormat_(short)", locale.timeFormat(QLocale::ShortFormat));
  1674. d.putHash("timeFormat_(long)", locale.timeFormat(QLocale::LongFormat));
  1675. d.putHash("decimalPoint", locale.decimalPoint());
  1676. d.putHash("exponential", locale.exponential());
  1677. d.putHash("percent", locale.percent());
  1678. d.putHash("zeroDigit", locale.zeroDigit());
  1679. d.putHash("groupSeparator", locale.groupSeparator());
  1680. d.putHash("negativeSign", locale.negativeSign());
  1681. d.endChildren();
  1682. }
  1683. d.disarm();
  1684. }
  1685. #if MAP_WORKS
  1686. static void qDumpQMapNode(QDumper &d)
  1687. {
  1688. const QMapData *h = reinterpret_cast<const QMapData *>(d.data);
  1689. const char *keyType = d.templateParameters[0];
  1690. const char *valueType = d.templateParameters[1];
  1691. qCheckAccess(h->backward);
  1692. qCheckAccess(h->forward[0]);
  1693. d.putItem("value", "");
  1694. d.putItem("numchild", 2);
  1695. if (d.dumpChildren) {
  1696. unsigned mapnodesize = d.extraInt[2];
  1697. unsigned valueOff = d.extraInt[3];
  1698. unsigned keyOffset = 2 * sizeof(void*) - mapnodesize;
  1699. unsigned valueOffset = 2 * sizeof(void*) - mapnodesize + valueOff;
  1700. d.beginChildren();
  1701. d.beginHash();
  1702. d.putItem("name", "key");
  1703. qDumpInnerValue(d, keyType, addOffset(h, keyOffset));
  1704. d.endHash();
  1705. d.beginHash();
  1706. d.putItem("name", "value");
  1707. qDumpInnerValue(d, valueType, addOffset(h, valueOffset));
  1708. d.endHash();
  1709. d.endChildren();
  1710. }
  1711. d.disarm();
  1712. }
  1713. static void qDumpQMap(QDumper &d)
  1714. {
  1715. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1716. QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
  1717. const char *keyType = d.templateParameters[0];
  1718. const char *valueType = d.templateParameters[1];
  1719. int n = h->size;
  1720. if (n < 0)
  1721. return;
  1722. if (n > 0) {
  1723. qCheckAccess(h->backward);
  1724. qCheckAccess(h->forward[0]);
  1725. qCheckPointer(h->backward->backward);
  1726. qCheckPointer(h->forward[0]->backward);
  1727. }
  1728. d.putItemCount("value", n);
  1729. d.putItem("numchild", n);
  1730. if (d.dumpChildren) {
  1731. //unsigned keySize = d.extraInt[0];
  1732. //unsigned valueSize = d.extraInt[1];
  1733. unsigned mapnodesize = d.extraInt[2];
  1734. unsigned valueOff = d.extraInt[3];
  1735. bool isSimpleKey = isSimpleType(keyType);
  1736. bool isSimpleValue = isSimpleType(valueType);
  1737. // both negative:
  1738. int keyOffset = 2 * sizeof(void*) - int(mapnodesize);
  1739. int valueOffset = 2 * sizeof(void*) - int(mapnodesize) + valueOff;
  1740. d.beginItem("extra");
  1741. d.put("simplekey: ").put(isSimpleKey).put(" isSimpleValue: ").put(isSimpleValue);
  1742. d.put(" keyOffset: ").put(keyOffset).put(" valueOffset: ").put(valueOffset);
  1743. d.put(" mapnodesize: ").put(mapnodesize);
  1744. d.endItem();
  1745. d.beginChildren();
  1746. QMapData::Node *node = reinterpret_cast<QMapData::Node *>(h->forward[0]);
  1747. QMapData::Node *end = reinterpret_cast<QMapData::Node *>(h);
  1748. int i = 0;
  1749. while (node != end) {
  1750. d.beginHash();
  1751. qDumpInnerValueHelper(d, keyType, addOffset(node, keyOffset), "key");
  1752. qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
  1753. if (isSimpleKey && isSimpleValue) {
  1754. d.putItem("type", valueType);
  1755. d.putItem("addr", addOffset(node, valueOffset));
  1756. } else {
  1757. #if QT_VERSION >= 0x040500
  1758. d.putItem("addr", node);
  1759. // actually, any type (even 'char') will do...
  1760. d.beginItem("type");
  1761. d.put(NS "QMapNode<").put(keyType).put(",");
  1762. d.put(valueType).put(" >");
  1763. d.endItem();
  1764. #else
  1765. d.beginItem("type");
  1766. d.put(NS "QMapData::Node<").put(keyType).put(",");
  1767. d.put(valueType).put(" >");
  1768. d.endItem();
  1769. d.beginItem("exp");
  1770. d.put("*('" NS "QMapData::Node<").put(keyType).put(",");
  1771. d.put(valueType).put(" >'*)").put(node);
  1772. d.endItem();
  1773. #endif
  1774. }
  1775. d.endHash();
  1776. ++i;
  1777. node = node->forward[0];
  1778. }
  1779. d.endChildren();
  1780. }
  1781. d.disarm();
  1782. }
  1783. static void qDumpQMultiMap(QDumper &d)
  1784. {
  1785. qDumpQMap(d);
  1786. }
  1787. #endif // MAP_WORKS
  1788. #ifndef QT_BOOTSTRAPPED
  1789. static void qDumpQModelIndex(QDumper &d)
  1790. {
  1791. const QModelIndex *mi = reinterpret_cast<const QModelIndex *>(d.data);
  1792. d.putItem("type", NS "QModelIndex");
  1793. if (mi->isValid()) {
  1794. d.beginItem("value");
  1795. d.put("(").put(mi->row()).put(", ").put(mi->column()).put(")");
  1796. d.endItem();
  1797. d.putItem("numchild", 5);
  1798. if (d.dumpChildren) {
  1799. d.beginChildren();
  1800. d.putHash("row", mi->row());
  1801. d.putHash("column", mi->column());
  1802. d.beginHash();
  1803. d.putItem("name", "parent");
  1804. const QModelIndex parent = mi->parent();
  1805. d.beginItem("value");
  1806. if (parent.isValid())
  1807. d.put("(").put(parent.row()).put(", ").put(parent.column()).put(")");
  1808. else
  1809. d.put("<invalid>");
  1810. d.endItem();
  1811. d.beginItem("exp");
  1812. d.put("((" NSX "QModelIndex" NSY "*)").put(d.data).put(")->parent()");
  1813. d.endItem();
  1814. d.putItem("type", NS "QModelIndex");
  1815. d.putItem("numchild", "1");
  1816. d.endHash();
  1817. d.putHash("internalId", QString::number(mi->internalId(), 10));
  1818. d.beginHash();
  1819. d.putItem("name", "model");
  1820. d.putItem("value", static_cast<const void *>(mi->model()));
  1821. d.putItem("type", NS "QAbstractItemModel*");
  1822. d.putItem("numchild", "1");
  1823. d.endHash();
  1824. d.endChildren();
  1825. }
  1826. } else {
  1827. d.putItem("value", "<invalid>");
  1828. d.putItem("numchild", 0);
  1829. }
  1830. d.disarm();
  1831. }
  1832. static void qDumpQObject(QDumper &d)
  1833. {
  1834. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  1835. const QObject *ob = reinterpret_cast<const QObject *>(d.data);
  1836. const QMetaObject *mo = ob->metaObject();
  1837. d.putItem("value", ob->objectName());
  1838. d.putItem("valueencoded", "2");
  1839. d.putItem("type", NS "QObject");
  1840. d.putItem("displayedtype", mo->className());
  1841. d.putItem("numchild", 4);
  1842. if (d.dumpChildren) {
  1843. int slotCount = 0;
  1844. int signalCount = 0;
  1845. for (int i = mo->methodCount(); --i >= 0; ) {
  1846. QMetaMethod::MethodType mt = mo->method(i).methodType();
  1847. signalCount += (mt == QMetaMethod::Signal);
  1848. slotCount += (mt == QMetaMethod::Slot);
  1849. }
  1850. d.beginChildren();
  1851. d.beginHash();
  1852. d.putItem("name", "properties");
  1853. // using 'addr' does not work in gdb as 'exp' is recreated as
  1854. // (type *)addr, and here we have different 'types':
  1855. // QObject vs QObjectPropertyList!
  1856. d.putItem("addr", d.data);
  1857. d.putItem("type", NS "QObjectPropertyList");
  1858. d.putItemCount("value", mo->propertyCount());
  1859. d.putItem("numchild", mo->propertyCount());
  1860. d.endHash();
  1861. d.beginHash();
  1862. d.putItem("name", "signals");
  1863. d.putItem("addr", d.data);
  1864. d.putItem("type", NS "QObjectSignalList");
  1865. d.putItemCount("value", signalCount);
  1866. d.putItem("numchild", signalCount);
  1867. d.endHash();
  1868. d.beginHash();
  1869. d.putItem("name", "slots");
  1870. d.putItem("addr", d.data);
  1871. d.putItem("type", NS "QObjectSlotList");
  1872. d.putItemCount("value", slotCount);
  1873. d.putItem("numchild", slotCount);
  1874. d.endHash();
  1875. const QObjectList objectChildren = ob->children();
  1876. if (!objectChildren.empty()) {
  1877. d.beginHash();
  1878. d.putItem("name", "children");
  1879. d.putItem("addr", d.data);
  1880. d.putItem("type", NS "QObjectChildList");
  1881. d.putItemCount("value", objectChildren.size());
  1882. d.putItem("numchild", objectChildren.size());
  1883. d.endHash();
  1884. }
  1885. d.beginHash();
  1886. d.putItem("name", "parent");
  1887. qDumpInnerValueHelper(d, NS "QObject *", ob->parent());
  1888. d.endHash();
  1889. #if 1
  1890. d.beginHash();
  1891. d.putItem("name", "className");
  1892. d.putItem("value", ob->metaObject()->className());
  1893. d.putItem("type", "");
  1894. d.putItem("numchild", "0");
  1895. d.endHash();
  1896. #endif
  1897. d.endChildren();
  1898. }
  1899. d.disarm();
  1900. }
  1901. #endif // QT_BOOTSTRAPPED
  1902. #if USE_QT_GUI
  1903. static const char *sizePolicyEnumValue(QSizePolicy::Policy p)
  1904. {
  1905. switch (p) {
  1906. case QSizePolicy::Fixed:
  1907. return "Fixed";
  1908. case QSizePolicy::Minimum:
  1909. return "Minimum";
  1910. case QSizePolicy::Maximum:
  1911. return "Maximum";
  1912. case QSizePolicy::Preferred:
  1913. return "Preferred";
  1914. case QSizePolicy::Expanding:
  1915. return "Expanding";
  1916. case QSizePolicy::MinimumExpanding:
  1917. return "MinimumExpanding";
  1918. case QSizePolicy::Ignored:
  1919. break;
  1920. }
  1921. return "Ignored";
  1922. }
  1923. static QString sizePolicyValue(const QSizePolicy &sp)
  1924. {
  1925. QString rc;
  1926. QTextStream str(&rc);
  1927. // Display as in Designer
  1928. str << '[' << sizePolicyEnumValue(sp.horizontalPolicy())
  1929. << ", " << sizePolicyEnumValue(sp.verticalPolicy())
  1930. << ", " << sp.horizontalStretch() << ", " << sp.verticalStretch() << ']';
  1931. return rc;
  1932. }
  1933. #endif
  1934. static void qDumpQVariantHelper(const QVariant *v, QString *value,
  1935. QString *exp, int *numchild)
  1936. {
  1937. switch (v->type()) {
  1938. case QVariant::Invalid:
  1939. *value = QLatin1String("<invalid>");
  1940. *numchild = 0;
  1941. break;
  1942. case QVariant::String:
  1943. *value = QLatin1Char('"') + v->toString() + QLatin1Char('"');
  1944. *numchild = 0;
  1945. break;
  1946. # if QT_VERSION >= 0x040500
  1947. case QVariant::StringList:
  1948. *exp = QString(QLatin1String("(*('" NS "QStringList'*)%1)"))
  1949. .arg((quintptr)v);
  1950. *numchild = v->toStringList().size();
  1951. break;
  1952. # endif
  1953. case QVariant::Int:
  1954. *value = QString::number(v->toInt());
  1955. *numchild= 0;
  1956. break;
  1957. case QVariant::Double:
  1958. *value = QString::number(v->toDouble());
  1959. *numchild = 0;
  1960. break;
  1961. # ifndef QT_BOOTSTRAPPED
  1962. case QVariant::Point: {
  1963. const QPoint p = v->toPoint();
  1964. *value = QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y());
  1965. }
  1966. *numchild = 0;
  1967. break;
  1968. case QVariant::Size: {
  1969. const QSize size = v->toSize();
  1970. *value = QString::fromLatin1("%1x%2")
  1971. .arg(size.width()).arg(size.height());
  1972. }
  1973. *numchild = 0;
  1974. break;
  1975. case QVariant::Rect: {
  1976. const QRect rect = v->toRect();
  1977. *value = QString::fromLatin1("%1x%2+%3+%4")
  1978. .arg(rect.width()).arg(rect.height())
  1979. .arg(rect.x()).arg(rect.y());
  1980. }
  1981. *numchild = 0;
  1982. break;
  1983. case QVariant::PointF: {
  1984. const QPointF p = v->toPointF();
  1985. *value = QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y());
  1986. }
  1987. *numchild = 0;
  1988. break;
  1989. case QVariant::SizeF: {
  1990. const QSizeF size = v->toSizeF();
  1991. *value = QString::fromLatin1("%1x%2")
  1992. .arg(size.width()).arg(size.height());
  1993. }
  1994. *numchild = 0;
  1995. break;
  1996. case QVariant::RectF: {
  1997. const QRectF rect = v->toRectF();
  1998. *value = QString::fromLatin1("%1x%2+%3+%4")
  1999. .arg(rect.width()).arg(rect.height())
  2000. .arg(rect.x()).arg(rect.y());
  2001. }
  2002. *numchild = 0;
  2003. break;
  2004. # endif // QT_BOOTSTRAPPED
  2005. # if USE_QT_GUI
  2006. case QVariant::Font:
  2007. *value = qvariant_cast<QFont>(*v).toString();
  2008. break;
  2009. case QVariant::Color:
  2010. *value = qvariant_cast<QColor>(*v).name();
  2011. break;
  2012. case QVariant::KeySequence:
  2013. # ifndef QT_NO_SHORTCUT
  2014. *value = qvariant_cast<QKeySequence>(*v).toString();
  2015. # else
  2016. *value = QString::fromLatin1("Disabled by QT_NO_SHORTCUT");
  2017. # endif
  2018. break;
  2019. case QVariant::SizePolicy:
  2020. *value = sizePolicyValue(qvariant_cast<QSizePolicy>(*v));
  2021. break;
  2022. # endif
  2023. default: {
  2024. static const char *qTypeFormat = sizeof(void *) == sizeof(long)
  2025. ? "'" NS "%s " NS "qvariant_cast<" NS "%s >'(*('" NS "QVariant'*)0x%lx)"
  2026. : "'" NS "%s " NS "qvariant_cast<" NS "%s >'(*('" NS "QVariant'*)0x%llx)";
  2027. static const char *nonQTypeFormat = sizeof(void *) == sizeof(long)
  2028. ? "'%s " NS "qvariant_cast<%s >'(*('" NS "QVariant'*)0x%lx)"
  2029. : "'%s " NS "qvariant_cast<%s >'(*('" NS "QVariant'*)0x%llx)";
  2030. char buf[1000];
  2031. const char *format = (v->typeName()[0] == 'Q') ? qTypeFormat : nonQTypeFormat;
  2032. qsnprintf(buf, sizeof(buf) - 1, format, v->typeName(), v->typeName(), v);
  2033. *exp = QLatin1String(buf);
  2034. *numchild = 1;
  2035. break;
  2036. }
  2037. }
  2038. }
  2039. static void qDumpQVariant(QDumper &d, const QVariant *v)
  2040. {
  2041. QString value;
  2042. QString exp;
  2043. int numchild = 0;
  2044. qDumpQVariantHelper(v, &value, &exp, &numchild);
  2045. bool isInvalid = (v->typeName() == 0);
  2046. if (isInvalid) {
  2047. d.putItem("value", "(invalid)");
  2048. } else if (value.isEmpty()) {
  2049. d.beginItem("value");
  2050. d.put("(").put(v->typeName()).put(") ");
  2051. d.endItem();
  2052. } else {
  2053. QByteArray ba;
  2054. ba += '(';
  2055. ba += v->typeName();
  2056. ba += ") ";
  2057. ba += qPrintable(value);
  2058. d.putItem("value", ba);
  2059. d.putItem("valueencoded", "5");
  2060. }
  2061. d.putItem("type", NS "QVariant");
  2062. if (isInvalid || !numchild) {
  2063. d.putItem("numchild", "0");
  2064. } else {
  2065. d.putItem("numchild", "1");
  2066. if (d.dumpChildren) {
  2067. d.beginChildren();
  2068. d.beginHash();
  2069. d.putItem("name", "value");
  2070. if (!exp.isEmpty())
  2071. d.putItem("exp", qPrintable(exp));
  2072. if (!value.isEmpty()) {
  2073. d.putItem("value", value);
  2074. d.putItem("valueencoded", "4");
  2075. }
  2076. d.putItem("type", v->typeName());
  2077. d.putItem("numchild", numchild);
  2078. d.endHash();
  2079. d.endChildren();
  2080. }
  2081. }
  2082. d.disarm();
  2083. }
  2084. static inline void qDumpQVariant(QDumper &d)
  2085. {
  2086. qCheckAccess(d.data);
  2087. qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data));
  2088. }
  2089. // Meta enumeration helpers
  2090. static inline void dumpMetaEnumType(QDumper &d, const QMetaEnum &me)
  2091. {
  2092. QByteArray type = me.scope();
  2093. if (!type.isEmpty())
  2094. type += "::";
  2095. type += me.name();
  2096. d.putItem("type", type.constData());
  2097. }
  2098. static inline void dumpMetaEnumValue(QDumper &d, const QMetaProperty &mop,
  2099. int value)
  2100. {
  2101. const QMetaEnum me = mop.enumerator();
  2102. dumpMetaEnumType(d, me);
  2103. if (const char *enumValue = me.valueToKey(value)) {
  2104. d.putItem("value", enumValue);
  2105. } else {
  2106. d.putItem("value", value);
  2107. }
  2108. d.putItem("numchild", 0);
  2109. }
  2110. static inline void dumpMetaFlagValue(QDumper &d, const QMetaProperty &mop,
  2111. int value)
  2112. {
  2113. const QMetaEnum me = mop.enumerator();
  2114. dumpMetaEnumType(d, me);
  2115. const QByteArray flagsValue = me.valueToKeys(value);
  2116. if (flagsValue.isEmpty()) {
  2117. d.putItem("value", value);
  2118. } else {
  2119. d.putItem("value", flagsValue.constData());
  2120. }
  2121. d.putItem("numchild", 0);
  2122. }
  2123. #ifndef QT_BOOTSTRAPPED
  2124. static void qDumpQObjectProperty(QDumper &d)
  2125. {
  2126. const QObject *ob = (const QObject *)d.data;
  2127. const QMetaObject *mob = ob->metaObject();
  2128. // extract "local.Object.property"
  2129. QString iname = d.iname;
  2130. const int dotPos = iname.lastIndexOf(QLatin1Char('.'));
  2131. if (dotPos == -1)
  2132. return;
  2133. iname.remove(0, dotPos + 1);
  2134. const int index = mob->indexOfProperty(iname.toLatin1());
  2135. if (index == -1)
  2136. return;
  2137. const QMetaProperty mop = mob->property(index);
  2138. const QVariant value = mop.read(ob);
  2139. const bool isInteger = value.type() == QVariant::Int;
  2140. if (isInteger && mop.isEnumType()) {
  2141. dumpMetaEnumValue(d, mop, value.toInt());
  2142. } else if (isInteger && mop.isFlagType()) {
  2143. dumpMetaFlagValue(d, mop, value.toInt());
  2144. } else {
  2145. qDumpQVariant(d, &value);
  2146. }
  2147. d.disarm();
  2148. }
  2149. static void qDumpQObjectPropertyList(QDumper &d)
  2150. {
  2151. const QObject *ob = (const QObject *)d.data;
  2152. const QMetaObject *mo = ob->metaObject();
  2153. const int propertyCount = mo->propertyCount();
  2154. d.putItem("addr", "<synthetic>");
  2155. d.putItem("type", NS "QObjectPropertyList");
  2156. d.putItem("numchild", propertyCount);
  2157. d.putItemCount("value", propertyCount);
  2158. if (d.dumpChildren) {
  2159. d.beginChildren();
  2160. for (int i = propertyCount; --i >= 0; ) {
  2161. const QMetaProperty & prop = mo->property(i);
  2162. d.beginHash();
  2163. d.putItem("name", prop.name());
  2164. switch (prop.type()) {
  2165. case QVariant::String:
  2166. d.putItem("type", prop.typeName());
  2167. d.putItem("value", prop.read(ob).toString());
  2168. d.putItem("valueencoded", "2");
  2169. d.putItem("numchild", "0");
  2170. break;
  2171. case QVariant::Bool:
  2172. d.putItem("type", prop.typeName());
  2173. d.putItem("value", (prop.read(ob).toBool() ? "true" : "false"));
  2174. d.putItem("numchild", "0");
  2175. break;
  2176. case QVariant::Int:
  2177. if (prop.isEnumType()) {
  2178. dumpMetaEnumValue(d, prop, prop.read(ob).toInt());
  2179. } else if (prop.isFlagType()) {
  2180. dumpMetaFlagValue(d, prop, prop.read(ob).toInt());
  2181. } else {
  2182. d.putItem("value", prop.read(ob).toInt());
  2183. d.putItem("numchild", "0");
  2184. }
  2185. break;
  2186. default:
  2187. d.putItem("addr", d.data);
  2188. d.putItem("type", NS "QObjectProperty");
  2189. d.putItem("numchild", "1");
  2190. break;
  2191. }
  2192. d.endHash();
  2193. }
  2194. d.endChildren();
  2195. }
  2196. d.disarm();
  2197. }
  2198. static QByteArray methodSignature(const QMetaMethod &method)
  2199. {
  2200. #if QT_VERSION >= 0x050000
  2201. return method.methodSignature();
  2202. #else
  2203. return QByteArray(method.signature());
  2204. #endif
  2205. }
  2206. static void qDumpQObjectMethodList(QDumper &d)
  2207. {
  2208. const QObject *ob = (const QObject *)d.data;
  2209. const QMetaObject *mo = ob->metaObject();
  2210. d.putItem("addr", "<synthetic>");
  2211. d.putItem("type", NS "QObjectMethodList");
  2212. d.putItem("numchild", mo->methodCount());
  2213. if (d.dumpChildren) {
  2214. d.putItem("childtype", NS "QMetaMethod::Method");
  2215. d.putItem("childnumchild", "0");
  2216. d.beginChildren();
  2217. for (int i = 0; i != mo->methodCount(); ++i) {
  2218. const QMetaMethod & method = mo->method(i);
  2219. int mt = method.methodType();
  2220. const QByteArray sig = methodSignature(method);
  2221. d.beginHash();
  2222. d.beginItem("name");
  2223. d.put(i).put(" ").put(mo->indexOfMethod(sig));
  2224. d.put(" ").put(sig);
  2225. d.endItem();
  2226. d.beginItem("value");
  2227. d.put((mt == QMetaMethod::Signal ? "<Signal>" : "<Slot>"));
  2228. d.put(" (").put(mt).put(")");
  2229. d.endItem();
  2230. d.endHash();
  2231. }
  2232. d.endChildren();
  2233. }
  2234. d.disarm();
  2235. }
  2236. static const char *qConnectionType(uint type)
  2237. {
  2238. Qt::ConnectionType connType = static_cast<Qt::ConnectionType>(type);
  2239. const char *output = "unknown";
  2240. switch (connType) {
  2241. case Qt::AutoConnection: output = "auto"; break;
  2242. case Qt::DirectConnection: output = "direct"; break;
  2243. case Qt::QueuedConnection: output = "queued"; break;
  2244. case Qt::BlockingQueuedConnection: output = "blockingqueued"; break;
  2245. #if QT_VERSION < 0x050000
  2246. case 3: output = "autocompat"; break;
  2247. #endif
  2248. #if QT_VERSION >= 0x040600
  2249. case Qt::UniqueConnection: break; // Can't happen.
  2250. #endif
  2251. };
  2252. return output;
  2253. }
  2254. #if QT_VERSION < 0x040400
  2255. #else
  2256. static const ConnectionList &qConnectionList(const QObject *ob, int signalNumber)
  2257. {
  2258. static const ConnectionList emptyList;
  2259. const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob));
  2260. if (!p->connectionLists)
  2261. return emptyList;
  2262. typedef QVector<ConnectionList> ConnLists;
  2263. const ConnLists *lists = reinterpret_cast<const ConnLists *>(p->connectionLists);
  2264. // there's an optimization making the lists only large enough to hold the
  2265. // last non-empty item
  2266. if (signalNumber >= lists->size())
  2267. return emptyList;
  2268. return lists->at(signalNumber);
  2269. }
  2270. #endif
  2271. // Write party involved in a slot/signal element,
  2272. // avoid to recursion to self.
  2273. static inline void qDumpQObjectConnectionPart(QDumper &d,
  2274. const QObject *owner,
  2275. const QObject *partner,
  2276. int number, const char *namePostfix)
  2277. {
  2278. d.beginHash();
  2279. d.beginItem("name");
  2280. d.put(number).put(namePostfix);
  2281. d.endItem();
  2282. if (partner == owner) {
  2283. d.putItem("value", "<this>");
  2284. d.putItem("type", owner->metaObject()->className());
  2285. d.putItem("numchild", 0);
  2286. d.putItem("addr", owner);
  2287. } else {
  2288. qDumpInnerValueHelper(d, NS "QObject *", partner);
  2289. }
  2290. d.endHash();
  2291. }
  2292. static void qDumpQObjectSignal(QDumper &d)
  2293. {
  2294. unsigned signalNumber = d.extraInt[0];
  2295. d.putItem("addr", "<synthetic>");
  2296. d.putItem("numchild", "1");
  2297. d.putItem("type", NS "QObjectSignal");
  2298. #if QT_VERSION >= 0x040400
  2299. if (d.dumpChildren) {
  2300. const QObject *ob = reinterpret_cast<const QObject *>(d.data);
  2301. d.beginChildren();
  2302. const ConnectionList &connList = qConnectionList(ob, signalNumber);
  2303. for (int i = 0; i != connList.size(); ++i) {
  2304. const Connection &conn = connectionAt(connList, i);
  2305. qDumpQObjectConnectionPart(d, ob, conn.receiver, i, " receiver");
  2306. d.beginHash();
  2307. d.beginItem("name");
  2308. d.put(i).put(" slot");
  2309. d.endItem();
  2310. d.putItem("type", "");
  2311. if (conn.receiver)
  2312. d.putItem("value", methodSignature(conn.receiver->metaObject()
  2313. ->method(conn.method_())));
  2314. else
  2315. d.putItem("value", "<invalid receiver>");
  2316. d.putItem("numchild", "0");
  2317. d.endHash();
  2318. d.beginHash();
  2319. d.beginItem("name");
  2320. d.put(i).put(" type");
  2321. d.endItem();
  2322. d.putItem("type", "");
  2323. d.beginItem("value");
  2324. d.put("<").put(qConnectionType(conn.connectionType)).put(" connection>");
  2325. d.endItem();
  2326. d.putItem("numchild", "0");
  2327. d.endHash();
  2328. }
  2329. d.endChildren();
  2330. d.putItem("numchild", connList.size());
  2331. }
  2332. #endif
  2333. d.disarm();
  2334. }
  2335. static void qDumpQObjectSignalList(QDumper &d)
  2336. {
  2337. const QObject *ob = reinterpret_cast<const QObject *>(d.data);
  2338. const QMetaObject *mo = ob->metaObject();
  2339. int count = 0;
  2340. const int methodCount = mo->methodCount();
  2341. for (int i = methodCount; --i >= 0; )
  2342. count += (mo->method(i).methodType() == QMetaMethod::Signal);
  2343. d.putItem("type", NS "QObjectSignalList");
  2344. d.putItemCount("value", count);
  2345. d.putItem("addr", d.data);
  2346. d.putItem("numchild", count);
  2347. #if QT_VERSION >= 0x040400
  2348. if (d.dumpChildren) {
  2349. d.beginChildren();
  2350. for (int i = 0; i != methodCount; ++i) {
  2351. const QMetaMethod & method = mo->method(i);
  2352. if (method.methodType() == QMetaMethod::Signal) {
  2353. int k = mo->indexOfSignal(methodSignature(method));
  2354. const ConnectionList &connList = qConnectionList(ob, k);
  2355. d.beginHash();
  2356. d.putItem("name", k);
  2357. d.putItem("value", methodSignature(method));
  2358. d.putItem("numchild", connList.size());
  2359. d.putItem("addr", d.data);
  2360. d.putItem("type", NS "QObjectSignal");
  2361. d.endHash();
  2362. }
  2363. }
  2364. d.endChildren();
  2365. }
  2366. #endif
  2367. d.disarm();
  2368. }
  2369. static void qDumpQObjectSlot(QDumper &d)
  2370. {
  2371. int slotNumber = d.extraInt[0];
  2372. d.putItem("addr", d.data);
  2373. d.putItem("numchild", "1");
  2374. d.putItem("type", NS "QObjectSlot");
  2375. #if QT_VERSION >= 0x040400
  2376. if (d.dumpChildren) {
  2377. d.beginChildren();
  2378. int numchild = 0;
  2379. const QObject *ob = reinterpret_cast<const QObject *>(d.data);
  2380. const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob));
  2381. #if QT_VERSION >= 0x040600
  2382. int s = 0;
  2383. for (SenderList senderList = p->senders; senderList != 0;
  2384. senderList = senderList->next, ++s) {
  2385. const QObject *sender = senderList->sender;
  2386. int signal = senderList->method_(); // FIXME: 'method' is wrong.
  2387. #else
  2388. for (int s = 0; s != p->senders.size(); ++s) {
  2389. const QObject *sender = senderAt(p->senders, s);
  2390. int signal = signalAt(p->senders, s);
  2391. #endif
  2392. const ConnectionList &connList = qConnectionList(sender, signal);
  2393. for (int i = 0; i != connList.size(); ++i) {
  2394. const Connection &conn = connectionAt(connList, i);
  2395. if (conn.receiver == ob && conn.method_() == slotNumber) {
  2396. ++numchild;
  2397. QMetaMethod method = sender->metaObject()->method(signal);
  2398. qDumpQObjectConnectionPart(d, ob, sender, s, " sender");
  2399. d.beginHash();
  2400. d.beginItem("name");
  2401. d.put(s).put(" signal");
  2402. d.endItem();
  2403. d.putItem("type", "");
  2404. d.putItem("value", methodSignature(method));
  2405. d.putItem("numchild", "0");
  2406. d.endHash();
  2407. d.beginHash();
  2408. d.beginItem("name");
  2409. d.put(s).put(" type");
  2410. d.endItem();
  2411. d.putItem("type", "");
  2412. d.beginItem("value");
  2413. d.put("<").put(qConnectionType(conn.method_()));
  2414. d.put(" connection>");
  2415. d.endItem();
  2416. d.putItem("numchild", "0");
  2417. d.endHash();
  2418. }
  2419. }
  2420. }
  2421. d.endChildren();
  2422. d.putItem("numchild", numchild);
  2423. }
  2424. #endif
  2425. d.disarm();
  2426. }
  2427. static void qDumpQObjectSlotList(QDumper &d)
  2428. {
  2429. const QObject *ob = reinterpret_cast<const QObject *>(d.data);
  2430. #if QT_VERSION >= 0x040400
  2431. const ObjectPrivate *p = reinterpret_cast<const ObjectPrivate *>(dfunc(ob));
  2432. #endif
  2433. const QMetaObject *mo = ob->metaObject();
  2434. int count = 0;
  2435. const int methodCount = mo->methodCount();
  2436. for (int i = methodCount; --i >= 0; )
  2437. count += (mo->method(i).methodType() == QMetaMethod::Slot);
  2438. d.putItem("numchild", count);
  2439. d.putItemCount("value", count);
  2440. d.putItem("type", NS "QObjectSlotList");
  2441. if (d.dumpChildren) {
  2442. d.beginChildren();
  2443. #if QT_VERSION >= 0x040400
  2444. for (int i = 0; i != methodCount; ++i) {
  2445. QMetaMethod method = mo->method(i);
  2446. if (method.methodType() == QMetaMethod::Slot) {
  2447. d.beginHash();
  2448. QByteArray sig = methodSignature(method);
  2449. int k = mo->indexOfSlot(sig);
  2450. d.putItem("name", k);
  2451. d.putItem("value", sig);
  2452. // count senders. expensive...
  2453. int numchild = 0;
  2454. #if QT_VERSION >= 0x040600
  2455. int s = 0;
  2456. for (SenderList senderList = p->senders; senderList != 0;
  2457. senderList = senderList->next, ++s) {
  2458. const QObject *sender = senderList->sender;
  2459. int signal = senderList->method_(); // FIXME: 'method' is wrong.
  2460. #else
  2461. for (int s = 0; s != p->senders.size(); ++s) {
  2462. const QObject *sender = senderAt(p->senders, s);
  2463. int signal = signalAt(p->senders, s);
  2464. #endif
  2465. const ConnectionList &connList = qConnectionList(sender, signal);
  2466. for (int c = 0; c != connList.size(); ++c) {
  2467. const Connection &conn = connectionAt(connList, c);
  2468. if (conn.receiver == ob && conn.method_() == k)
  2469. ++numchild;
  2470. }
  2471. }
  2472. d.putItem("numchild", numchild);
  2473. d.putItem("addr", d.data);
  2474. d.putItem("type", NS "QObjectSlot");
  2475. d.endHash();
  2476. }
  2477. }
  2478. #endif
  2479. d.endChildren();
  2480. }
  2481. d.disarm();
  2482. }
  2483. static void qDumpQObjectChildList(QDumper &d)
  2484. {
  2485. const QObject *ob = reinterpret_cast<const QObject *>(d.data);
  2486. const QObjectList children = ob->children();
  2487. const int size = children.size();
  2488. d.putItem("numchild", size);
  2489. d.putItemCount("value", size);
  2490. d.putItem("type", NS "QObjectChildList");
  2491. if (d.dumpChildren) {
  2492. d.beginChildren();
  2493. for (int i = 0; i != size; ++i) {
  2494. d.beginHash();
  2495. qDumpInnerValueHelper(d, NS "QObject *", children.at(i));
  2496. d.endHash();
  2497. }
  2498. d.endChildren();
  2499. }
  2500. d.disarm();
  2501. }
  2502. #endif // QT_BOOTSTRAPPED
  2503. #if USE_QT_GUI
  2504. static void qDumpQPixmap(QDumper &d)
  2505. {
  2506. const QPixmap &im = *reinterpret_cast<const QPixmap *>(d.data);
  2507. d.beginItem("value");
  2508. d.put("(").put(im.width()).put("x").put(im.height()).put(")");
  2509. d.endItem();
  2510. d.putItem("type", NS "QPixmap");
  2511. d.putItem("numchild", "0");
  2512. d.disarm();
  2513. }
  2514. #endif
  2515. #ifndef QT_BOOTSTRAPPED
  2516. static void qDumpQPoint(QDumper &d)
  2517. {
  2518. const QPoint &pnt = *reinterpret_cast<const QPoint *>(d.data);
  2519. d.beginItem("value");
  2520. d.put("(").put(pnt.x()).put(", ").put(pnt.y()).put(")");
  2521. d.endItem();
  2522. d.putItem("type", NS "QPoint");
  2523. d.putItem("numchild", "2");
  2524. if (d.dumpChildren) {
  2525. d.beginChildren();
  2526. d.putHash("x", pnt.x());
  2527. d.putHash("y", pnt.y());
  2528. d.endChildren();
  2529. }
  2530. d.disarm();
  2531. }
  2532. static void qDumpQPointF(QDumper &d)
  2533. {
  2534. const QPointF &pnt = *reinterpret_cast<const QPointF *>(d.data);
  2535. d.beginItem("value");
  2536. d.put("(").put(pnt.x()).put(", ").put(pnt.y()).put(")");
  2537. d.endItem();
  2538. d.putItem("type", NS "QPointF");
  2539. d.putItem("numchild", "2");
  2540. if (d.dumpChildren) {
  2541. d.beginChildren();
  2542. d.putHash("x", pnt.x());
  2543. d.putHash("y", pnt.y());
  2544. d.endChildren();
  2545. }
  2546. d.disarm();
  2547. }
  2548. static void qDumpQRect(QDumper &d)
  2549. {
  2550. const QRect &rc = *reinterpret_cast<const QRect *>(d.data);
  2551. d.beginItem("value");
  2552. d.put("(").put(rc.width()).put("x").put(rc.height());
  2553. if (rc.x() >= 0)
  2554. d.put("+");
  2555. d.put(rc.x());
  2556. if (rc.y() >= 0)
  2557. d.put("+");
  2558. d.put(rc.y());
  2559. d.put(")");
  2560. d.endItem();
  2561. d.putItem("type", NS "QRect");
  2562. d.putItem("numchild", "4");
  2563. if (d.dumpChildren) {
  2564. d.beginChildren();
  2565. d.putHash("x", rc.x());
  2566. d.putHash("y", rc.y());
  2567. d.putHash("width", rc.width());
  2568. d.putHash("height", rc.height());
  2569. d.endChildren();
  2570. }
  2571. d.disarm();
  2572. }
  2573. static void qDumpQRectF(QDumper &d)
  2574. {
  2575. const QRectF &rc = *reinterpret_cast<const QRectF *>(d.data);
  2576. d.beginItem("value");
  2577. d.put("(").put(rc.width()).put("x").put(rc.height());
  2578. if (rc.x() >= 0)
  2579. d.put("+");
  2580. d.put(rc.x());
  2581. if (rc.y() >= 0)
  2582. d.put("+");
  2583. d.put(rc.y());
  2584. d.put(")");
  2585. d.endItem();
  2586. d.putItem("type", NS "QRectF");
  2587. d.putItem("numchild", "4");
  2588. if (d.dumpChildren) {
  2589. d.beginChildren();
  2590. d.putHash("x", rc.x());
  2591. d.putHash("y", rc.y());
  2592. d.putHash("width", rc.width());
  2593. d.putHash("height", rc.height());
  2594. d.endChildren();
  2595. }
  2596. d.disarm();
  2597. }
  2598. #endif
  2599. static void qDumpQSet(QDumper &d)
  2600. {
  2601. // This uses the knowledge that QHash<T> has only a single member
  2602. // of union { QHashData *d; QHashNode<Key, T> *e; };
  2603. QHashData *hd = *(QHashData**)d.data;
  2604. QHashData::Node *node = hd->firstNode();
  2605. int n = hd->size;
  2606. if (n < 0)
  2607. return;
  2608. if (n > 0) {
  2609. qCheckAccess(node);
  2610. qCheckPointer(node->next);
  2611. }
  2612. d.putItemCount("value", n);
  2613. d.putItem("valueeditable", "false");
  2614. d.putItem("numchild", 2 * n);
  2615. if (d.dumpChildren) {
  2616. d.beginChildren();
  2617. int i = 0;
  2618. for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) {
  2619. for (node = hd->buckets[bucket]; node->next; node = node->next) {
  2620. d.beginHash();
  2621. d.putItem("type", d.innerType);
  2622. d.beginItem("exp");
  2623. d.put("(('" NS "QHashNode<").put(d.innerType
  2624. ).put("," NS "QHashDummyValue>'*)"
  2625. ).put(static_cast<const void*>(node)).put(")->key");
  2626. d.endItem();
  2627. d.endHash();
  2628. ++i;
  2629. if (i > 10000) {
  2630. d.putEllipsis();
  2631. break;
  2632. }
  2633. }
  2634. }
  2635. d.endChildren();
  2636. }
  2637. d.disarm();
  2638. }
  2639. #ifndef QT_BOOTSTRAPPED
  2640. #if QT_VERSION >= 0x040500
  2641. static void qDumpQSharedPointer(QDumper &d)
  2642. {
  2643. const QSharedPointer<int> &ptr =
  2644. *reinterpret_cast<const QSharedPointer<int> *>(d.data);
  2645. if (ptr.isNull()) {
  2646. d.putItem("value", "<null>");
  2647. d.putItem("valueeditable", "false");
  2648. d.putItem("numchild", 0);
  2649. d.disarm();
  2650. return;
  2651. }
  2652. if (isSimpleType(d.innerType))
  2653. qDumpInnerValueHelper(d, d.innerType, ptr.data());
  2654. else
  2655. d.putItem("value", "");
  2656. d.putItem("valueeditable", "false");
  2657. d.putItem("numchild", 1);
  2658. if (d.dumpChildren) {
  2659. d.beginChildren();
  2660. d.beginHash();
  2661. d.putItem("name", "data");
  2662. qDumpInnerValue(d, d.innerType, ptr.data());
  2663. d.endHash();
  2664. const int v = sizeof(void *);
  2665. d.beginHash();
  2666. const void *weak = addOffset(deref(addOffset(d.data, v)), v);
  2667. d.putItem("name", "weakref");
  2668. d.putItem("value", *static_cast<const int *>(weak));
  2669. d.putItem("type", "int");
  2670. d.putItem("addr", weak);
  2671. d.putItem("numchild", "0");
  2672. d.endHash();
  2673. d.beginHash();
  2674. const void *strong = addOffset(weak, sizeof(int));
  2675. d.putItem("name", "strongref");
  2676. d.putItem("value", *static_cast<const int *>(strong));
  2677. d.putItem("type", "int");
  2678. d.putItem("addr", strong);
  2679. d.putItem("numchild", "0");
  2680. d.endHash();
  2681. d.endChildren();
  2682. }
  2683. d.disarm();
  2684. }
  2685. #endif // QT_VERSION >= 0x040500
  2686. #endif // QT_BOOTSTRAPPED
  2687. static void qDumpQSize(QDumper &d)
  2688. {
  2689. const QSize s = *reinterpret_cast<const QSize *>(d.data);
  2690. d.beginItem("value");
  2691. d.put("(").put(s.width()).put("x").put(s.height()).put(")");
  2692. d.endItem();
  2693. d.putItem("type", NS "QSize");
  2694. d.putItem("numchild", "2");
  2695. if (d.dumpChildren) {
  2696. d.beginChildren();
  2697. d.putHash("w", s.width());
  2698. d.putHash("h", s.height());
  2699. d.endChildren();
  2700. }
  2701. d.disarm();
  2702. }
  2703. static void qDumpQSizeF(QDumper &d)
  2704. {
  2705. const QSizeF s = *reinterpret_cast<const QSizeF *>(d.data);
  2706. d.beginItem("value");
  2707. d.put("(").put(s.width()).put("x").put(s.height()).put(")");
  2708. d.endItem();
  2709. d.putItem("type", NS "QSizeF");
  2710. d.putItem("numchild", "2");
  2711. if (d.dumpChildren) {
  2712. d.beginChildren();
  2713. d.putHash("w", s.width());
  2714. d.putHash("h", s.height());
  2715. d.endChildren();
  2716. }
  2717. d.disarm();
  2718. }
  2719. static void qDumpQString(QDumper &d)
  2720. {
  2721. //qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  2722. const QString &str = *reinterpret_cast<const QString *>(d.data);
  2723. const int size = str.size();
  2724. if (size < 0)
  2725. return;
  2726. if (size) {
  2727. const QChar *unicode = str.unicode();
  2728. qCheckAccess(unicode);
  2729. qCheckAccess(unicode + size);
  2730. if (!unicode[size].isNull()) // must be '\0' terminated
  2731. return;
  2732. }
  2733. d.putStringValue(str);
  2734. d.putItem("type", NS "QString");
  2735. //d.putItem("editvalue", str); // handled generically below
  2736. d.putItem("numchild", "0");
  2737. d.disarm();
  2738. }
  2739. static void qDumpQStringList(QDumper &d)
  2740. {
  2741. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  2742. const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
  2743. int n = list.size();
  2744. if (n < 0)
  2745. return;
  2746. if (n > 0) {
  2747. qCheckAccess(&list.front());
  2748. qCheckAccess(&list.back());
  2749. }
  2750. d.putItemCount("value", n);
  2751. d.putItem("valueeditable", "false");
  2752. d.putItem("numchild", n);
  2753. if (d.dumpChildren) {
  2754. if (n > 1000)
  2755. n = 1000;
  2756. d.beginChildren(n ? NS "QString" : 0);
  2757. for (int i = 0; i != n; ++i) {
  2758. d.beginHash();
  2759. d.putStringValue(list.at(i));
  2760. d.endHash();
  2761. }
  2762. if (n < list.size())
  2763. d.putEllipsis();
  2764. d.endChildren();
  2765. }
  2766. d.disarm();
  2767. }
  2768. static void qDumpQTextCodec(QDumper &d)
  2769. {
  2770. qCheckPointer(deref(d.data));
  2771. const QTextCodec &codec = *reinterpret_cast<const QTextCodec *>(d.data);
  2772. d.putItem("value", codec.name());
  2773. d.putItem("valueencoded", "1");
  2774. d.putItem("type", NS "QTextCodec");
  2775. d.putItem("numchild", "2");
  2776. if (d.dumpChildren) {
  2777. d.beginChildren();
  2778. d.putHash("name", codec.name());
  2779. d.putHash("mibEnum", codec.mibEnum());
  2780. d.endChildren();
  2781. }
  2782. d.disarm();
  2783. }
  2784. static void qDumpQVector(QDumper &d)
  2785. {
  2786. qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid
  2787. #if QT_VERSION >= 0x050000
  2788. QArrayData *v = *reinterpret_cast<QArrayData *const*>(d.data);
  2789. const unsigned typeddatasize = (char *)(&v->offset) - (char *)v;
  2790. #else
  2791. QVectorData *v = *reinterpret_cast<QVectorData *const*>(d.data);
  2792. QVectorTypedData<int> *dummy = 0;
  2793. const unsigned typeddatasize = (char*)(&dummy->array) - (char*)dummy;
  2794. #endif
  2795. // Try to provoke segfaults early to prevent the frontend
  2796. // from asking for unavailable child details
  2797. int nn = v->size;
  2798. if (nn < 0)
  2799. return;
  2800. const bool innerIsPointerType = isPointerType(d.innerType);
  2801. const unsigned innersize = d.extraInt[0];
  2802. const int n = qMin(nn, 1000);
  2803. // Check pointers
  2804. if (innerIsPointerType && nn > 0)
  2805. for (int i = 0; i != n; ++i)
  2806. if (const void *p = addOffset(v, i * innersize + typeddatasize))
  2807. qCheckPointer(deref(p));
  2808. d.putItemCount("value", nn);
  2809. d.putItem("valueeditable", "false");
  2810. d.putItem("numchild", nn);
  2811. if (d.dumpChildren) {
  2812. QByteArray strippedInnerType = stripPointerType(d.innerType);
  2813. const char *stripped = innerIsPointerType ? strippedInnerType.data() : 0;
  2814. d.beginChildren(d.innerType);
  2815. for (int i = 0; i != n; ++i) {
  2816. d.beginHash();
  2817. qDumpInnerValueOrPointer(d, d.innerType, stripped,
  2818. addOffset(v, i * innersize + typeddatasize));
  2819. d.endHash();
  2820. }
  2821. if (n < nn)
  2822. d.putEllipsis();
  2823. d.endChildren();
  2824. }
  2825. d.disarm();
  2826. }
  2827. #ifndef QT_BOOTSTRAPPED
  2828. #if QT_VERSION >= 0x040500
  2829. static void qDumpQWeakPointer(QDumper &d)
  2830. {
  2831. const int v = sizeof(void *);
  2832. const void *value = deref(addOffset(d.data, v));
  2833. const void *data = deref(d.data);
  2834. if (value == 0 || data == 0) {
  2835. d.putItem("value", "<null>");
  2836. d.putItem("valueeditable", "false");
  2837. d.putItem("numchild", 0);
  2838. d.disarm();
  2839. return;
  2840. }
  2841. if (isSimpleType(d.innerType))
  2842. qDumpInnerValueHelper(d, d.innerType, value);
  2843. else
  2844. d.putItem("value", "");
  2845. d.putItem("valueeditable", "false");
  2846. d.putItem("numchild", 1);
  2847. if (d.dumpChildren) {
  2848. d.beginChildren();
  2849. d.beginHash();
  2850. d.putItem("name", "data");
  2851. qDumpInnerValue(d, d.innerType, value);
  2852. d.endHash();
  2853. d.beginHash();
  2854. const void *weak = addOffset(deref(d.data), v);
  2855. d.putItem("name", "weakref");
  2856. d.putItem("value", *static_cast<const int *>(weak));
  2857. d.putItem("type", "int");
  2858. d.putItem("addr", weak);
  2859. d.putItem("numchild", "0");
  2860. d.endHash();
  2861. d.beginHash();
  2862. const void *strong = addOffset(weak, sizeof(int));
  2863. d.putItem("name", "strongref");
  2864. d.putItem("value", *static_cast<const int *>(strong));
  2865. d.putItem("type", "int");
  2866. d.putItem("addr", strong);
  2867. d.putItem("numchild", "0");
  2868. d.endHash();
  2869. d.endChildren();
  2870. }
  2871. d.disarm();
  2872. }
  2873. #endif // QT_VERSION >= 0x040500
  2874. #endif // QT_BOOTSTRAPPED
  2875. #endif // QT_CORE
  2876. static void qDumpStdList(QDumper &d)
  2877. {
  2878. const std::list<int> &list = *reinterpret_cast<const std::list<int> *>(d.data);
  2879. const void *p = d.data;
  2880. qCheckAccess(p);
  2881. p = deref(p);
  2882. qCheckAccess(p);
  2883. p = deref(p);
  2884. qCheckAccess(p);
  2885. p = deref(addOffset(d.data, sizeof(void*)));
  2886. qCheckAccess(p);
  2887. p = deref(addOffset(p, sizeof(void*)));
  2888. qCheckAccess(p);
  2889. p = deref(addOffset(p, sizeof(void*)));
  2890. qCheckAccess(p);
  2891. std::list<int>::size_type nn = 0;
  2892. const std::list<int>::size_type maxItems = 100;
  2893. std::list<int>::const_iterator it = list.begin();
  2894. const std::list<int>::const_iterator cend = list.end();
  2895. for (; nn < maxItems && it != cend; ++nn, ++it)
  2896. qCheckAccess(it.operator->());
  2897. if (it != cend) {
  2898. d.putTruncatedItemCount("value", nn);
  2899. } else {
  2900. d.putItemCount("value", nn);
  2901. }
  2902. d.putItem("numchild", nn);
  2903. d.putItem("valueeditable", "false");
  2904. if (d.dumpChildren) {
  2905. QByteArray strippedInnerType = stripPointerType(d.innerType);
  2906. const char *stripped =
  2907. isPointerType(d.innerType) ? strippedInnerType.data() : 0;
  2908. d.beginChildren(d.innerType);
  2909. it = list.begin();
  2910. for (std::list<int>::size_type i = 0; i < maxItems && it != cend; ++i, ++it) {
  2911. d.beginHash();
  2912. qDumpInnerValueOrPointer(d, d.innerType, stripped, it.operator->());
  2913. d.endHash();
  2914. }
  2915. if (it != list.end())
  2916. d.putEllipsis();
  2917. d.endChildren();
  2918. }
  2919. d.disarm();
  2920. }
  2921. /* Dump out an arbitrary map. To iterate the map,
  2922. * it is cast to a map of <KeyType,Value>. 'int' can be used for both
  2923. * for all types if the implementation does not depend on the types
  2924. * which is the case for GNU STL. The implementation used by MS VC, however,
  2925. * does depend on the key/value type, so, special cases need to be hardcoded. */
  2926. template <class KeyType, class ValueType>
  2927. static void qDumpStdMapHelper(QDumper &d)
  2928. {
  2929. typedef std::map<KeyType, ValueType> DummyType;
  2930. const DummyType &map = *reinterpret_cast<const DummyType*>(d.data);
  2931. const char *keyType = d.templateParameters[0];
  2932. const char *valueType = d.templateParameters[1];
  2933. const void *p = d.data;
  2934. qCheckAccess(p);
  2935. const int nn = map.size();
  2936. if (nn < 0)
  2937. return;
  2938. typename DummyType::const_iterator it = map.begin();
  2939. const typename DummyType::const_iterator cend = map.end();
  2940. for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it)
  2941. qCheckAccess(it.operator->());
  2942. d.putItem("numchild", nn);
  2943. d.putItemCount("value", nn);
  2944. d.putItem("valueeditable", "false");
  2945. d.putItem("valueoffset", d.extraInt[2]);
  2946. // HACK: we need a properly const qualified version of the
  2947. // std::pair used. We extract it from the allocator parameter
  2948. // (#4, "std::allocator<std::pair<key, value> >")
  2949. // as it is there, and, equally importantly, in an order that
  2950. // gdb accepts when fed with it.
  2951. char *pairType = (char *)(d.templateParameters[3]) + 15;
  2952. pairType[strlen(pairType) - 2] = 0;
  2953. d.putItem("pairtype", pairType);
  2954. if (d.dumpChildren) {
  2955. bool isSimpleKey = isSimpleType(keyType);
  2956. bool isSimpleValue = isSimpleType(valueType);
  2957. int valueOffset = d.extraInt[2];
  2958. d.beginItem("extra");
  2959. d.put("isSimpleKey: ").put(isSimpleKey);
  2960. d.put(" isSimpleValue: ").put(isSimpleValue);
  2961. d.put(" valueType: '").put(valueType);
  2962. d.put(" valueOffset: ").put(valueOffset);
  2963. d.endItem();
  2964. d.beginChildren(d.innerType);
  2965. it = map.begin();
  2966. for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
  2967. d.beginHash();
  2968. const void *node = it.operator->();
  2969. qDumpInnerValueHelper(d, keyType, node, "key");
  2970. qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
  2971. if (isSimpleKey && isSimpleValue) {
  2972. d.putItem("type", valueType);
  2973. d.putItem("addr", addOffset(node, valueOffset));
  2974. d.putItem("numchild", 0);
  2975. } else {
  2976. d.putItem("addr", node);
  2977. d.putItem("type", pairType);
  2978. d.putItem("numchild", 2);
  2979. }
  2980. d.endHash();
  2981. }
  2982. if (it != map.end())
  2983. d.putEllipsis();
  2984. d.endChildren();
  2985. }
  2986. d.disarm();
  2987. }
  2988. static void qDumpStdMap(QDumper &d)
  2989. {
  2990. qDumpStdMapHelper<int,int>(d);
  2991. }
  2992. /* Dump out an arbitrary set. To iterate the set,
  2993. * it is cast to a set of <KeyType>. 'int' can be used
  2994. * for all types if the implementation does not depend on the key type
  2995. * which is the case for GNU STL. The implementation used by MS VC, however,
  2996. * does depend on the key type, so, special cases need to be hardcoded. */
  2997. template <class KeyType>
  2998. static void qDumpStdSetHelper(QDumper &d)
  2999. {
  3000. typedef std::set<KeyType> DummyType;
  3001. const DummyType &set = *reinterpret_cast<const DummyType*>(d.data);
  3002. const void *p = d.data;
  3003. qCheckAccess(p);
  3004. const int nn = set.size();
  3005. if (nn < 0)
  3006. return;
  3007. typename DummyType::const_iterator it = set.begin();
  3008. const typename DummyType::const_iterator cend = set.end();
  3009. for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it)
  3010. qCheckAccess(it.operator->());
  3011. d.putItemCount("value", nn);
  3012. d.putItem("valueeditable", "false");
  3013. d.putItem("numchild", nn);
  3014. d.putItem("valueoffset", d.extraInt[0]);
  3015. if (d.dumpChildren) {
  3016. int valueOffset = 0; // d.extraInt[0];
  3017. QByteArray strippedInnerType = stripPointerType(d.innerType);
  3018. const char *stripped =
  3019. isPointerType(d.innerType) ? strippedInnerType.data() : 0;
  3020. d.beginItem("extra");
  3021. d.put("valueOffset: ").put(valueOffset);
  3022. d.endItem();
  3023. d.beginChildren(d.innerType);
  3024. it = set.begin();
  3025. for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
  3026. const void *node = it.operator->();
  3027. d.beginHash();
  3028. qDumpInnerValueOrPointer(d, d.innerType, stripped, node);
  3029. d.endHash();
  3030. }
  3031. if (it != set.end())
  3032. d.putEllipsis();
  3033. d.endChildren();
  3034. }
  3035. d.disarm();
  3036. }
  3037. static void qDumpStdSet(QDumper &d)
  3038. {
  3039. qDumpStdSetHelper<int>(d);
  3040. }
  3041. static void qDumpStdString(QDumper &d)
  3042. {
  3043. const std::string &str = *reinterpret_cast<const std::string *>(d.data);
  3044. const std::string::size_type size = str.size();
  3045. if (int(size) < 0)
  3046. return;
  3047. if (size) {
  3048. qCheckAccess(str.c_str());
  3049. qCheckAccess(str.c_str() + size - 1);
  3050. }
  3051. qDumpStdStringValue(d, str);
  3052. d.disarm();
  3053. }
  3054. static void qDumpStdWString(QDumper &d)
  3055. {
  3056. const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data);
  3057. const std::wstring::size_type size = str.size();
  3058. if (int(size) < 0)
  3059. return;
  3060. if (size) {
  3061. qCheckAccess(str.c_str());
  3062. qCheckAccess(str.c_str() + size - 1);
  3063. }
  3064. qDumpStdWStringValue(d, str);
  3065. d.disarm();
  3066. }
  3067. static void qDumpStdVector(QDumper &d)
  3068. {
  3069. // Correct type would be something like:
  3070. // std::_Vector_base<int,std::allocator<int, std::allocator<int> >>::_Vector_impl
  3071. struct VectorImpl {
  3072. char *start;
  3073. char *finish;
  3074. char *end_of_storage;
  3075. };
  3076. const VectorImpl *v = static_cast<const VectorImpl *>(d.data);
  3077. // Try to provoke segfaults early to prevent the frontend
  3078. // from asking for unavailable child details
  3079. int nn = (v->finish - v->start) / d.extraInt[0];
  3080. if (nn < 0)
  3081. return;
  3082. if (nn > 0) {
  3083. qCheckAccess(v->start);
  3084. qCheckAccess(v->finish);
  3085. qCheckAccess(v->end_of_storage);
  3086. }
  3087. int n = nn;
  3088. d.putItemCount("value", n);
  3089. d.putItem("valueeditable", "false");
  3090. d.putItem("numchild", n);
  3091. if (d.dumpChildren) {
  3092. unsigned innersize = d.extraInt[0];
  3093. QByteArray strippedInnerType = stripPointerType(d.innerType);
  3094. const char *stripped =
  3095. isPointerType(d.innerType) ? strippedInnerType.data() : 0;
  3096. if (n > 1000)
  3097. n = 1000;
  3098. d.beginChildren(n ? d.innerType : 0);
  3099. for (int i = 0; i != n; ++i) {
  3100. d.beginHash();
  3101. qDumpInnerValueOrPointer(d, d.innerType, stripped,
  3102. addOffset(v->start, i * innersize));
  3103. d.endHash();
  3104. }
  3105. if (n < nn)
  3106. d.putEllipsis();
  3107. d.endChildren();
  3108. }
  3109. d.disarm();
  3110. }
  3111. static void qDumpStdVectorBool(QDumper &d)
  3112. {
  3113. // FIXME
  3114. return qDumpStdVector(d);
  3115. }
  3116. static void handleProtocolVersion2and3(QDumper &d)
  3117. {
  3118. if (!d.outerType[0]) {
  3119. qDumpUnknown(d);
  3120. return;
  3121. }
  3122. d.setupTemplateParameters();
  3123. d.putItem("iname", d.iname);
  3124. if (d.data)
  3125. d.putItem("addr", d.data);
  3126. #ifdef QT_NO_QDATASTREAM
  3127. if (d.protocolVersion == 3) {
  3128. QVariant::Type type = QVariant::nameToType(d.outerType);
  3129. if (type != QVariant::Invalid) {
  3130. QVariant v(type, d.data);
  3131. QByteArray ba;
  3132. QDataStream ds(&ba, QIODevice::WriteOnly);
  3133. ds << v;
  3134. d.putItem("editvalue", ba);
  3135. }
  3136. }
  3137. #endif
  3138. const char *type = stripNamespace(d.outerType);
  3139. // type[0] is usually 'Q', so don't use it
  3140. switch (type[1]) {
  3141. case 'a':
  3142. if (isEqual(type, "map"))
  3143. qDumpStdMap(d);
  3144. break;
  3145. case 'e':
  3146. if (isEqual(type, "vector"))
  3147. qDumpStdVector(d);
  3148. else if (isEqual(type, "set"))
  3149. qDumpStdSet(d);
  3150. break;
  3151. case 'i':
  3152. if (isEqual(type, "list"))
  3153. qDumpStdList(d);
  3154. break;
  3155. case 's':
  3156. if (isEqual(type, "wstring"))
  3157. qDumpStdWString(d);
  3158. break;
  3159. case 't':
  3160. if (isEqual(type, "std::vector"))
  3161. qDumpStdVector(d);
  3162. else if (isEqual(type, "std::vector::bool"))
  3163. qDumpStdVectorBool(d);
  3164. else if (isEqual(type, "std::list"))
  3165. qDumpStdList(d);
  3166. else if (isEqual(type, "std::map"))
  3167. qDumpStdMap(d);
  3168. else if (isEqual(type, "std::set"))
  3169. qDumpStdSet(d);
  3170. else if (isEqual(type, "std::string") || isEqual(type, "string"))
  3171. qDumpStdString(d);
  3172. else if (isEqual(type, "std::wstring"))
  3173. qDumpStdWString(d);
  3174. break;
  3175. #if USE_QT_CORE
  3176. case 'A':
  3177. # ifndef QT_BOOTSTRAPPED
  3178. if (isEqual(type, "QAbstractItemModel"))
  3179. qDumpQAbstractItemModel(d);
  3180. else if (isEqual(type, "QAbstractItem"))
  3181. qDumpQAbstractItem(d);
  3182. # endif
  3183. break;
  3184. case 'B':
  3185. if (isEqual(type, "QByteArray"))
  3186. qDumpQByteArray(d);
  3187. break;
  3188. case 'C':
  3189. if (isEqual(type, "QChar"))
  3190. qDumpQChar(d);
  3191. break;
  3192. case 'D':
  3193. if (isEqual(type, "QDate"))
  3194. qDumpQDate(d);
  3195. else if (isEqual(type, "QDateTime"))
  3196. qDumpQDateTime(d);
  3197. else if (isEqual(type, "QDir"))
  3198. qDumpQDir(d);
  3199. break;
  3200. case 'F':
  3201. # ifndef QT_BOOTSTRAPPED
  3202. if (isEqual(type, "QFile"))
  3203. qDumpQFile(d);
  3204. else if (isEqual(type, "QFileInfo"))
  3205. qDumpQFileInfo(d);
  3206. # endif
  3207. break;
  3208. case 'H':
  3209. if (isEqual(type, "QHash"))
  3210. qDumpQHash(d);
  3211. else if (isEqual(type, "QHashNode"))
  3212. qDumpQHashNode(d);
  3213. break;
  3214. case 'I':
  3215. # if USE_QT_GUI
  3216. if (isEqual(type, "QImage"))
  3217. qDumpQImage(d);
  3218. else if (isEqual(type, "QImageData"))
  3219. qDumpQImageData(d);
  3220. # endif
  3221. break;
  3222. case 'L':
  3223. # ifndef QT_BOOTSTRAPPED
  3224. if (isEqual(type, "QList"))
  3225. qDumpQList(d);
  3226. else if (isEqual(type, "QLinkedList"))
  3227. qDumpQLinkedList(d);
  3228. else if (isEqual(type, "QLocale"))
  3229. qDumpQLocale(d);
  3230. # endif
  3231. break;
  3232. case 'M':
  3233. # ifndef QT_BOOTSTRAPPED
  3234. if (isEqual(type, "QModelIndex"))
  3235. qDumpQModelIndex(d);
  3236. # if MAP_WORKS
  3237. else if (isEqual(type, "QMap"))
  3238. qDumpQMap(d);
  3239. else if (isEqual(type, "QMapNode"))
  3240. qDumpQMapNode(d);
  3241. else if (isEqual(type, "QMultiMap"))
  3242. qDumpQMultiMap(d);
  3243. # endif
  3244. # endif
  3245. break;
  3246. case 'O':
  3247. # ifndef QT_BOOTSTRAPPED
  3248. if (isEqual(type, "QObject"))
  3249. qDumpQObject(d);
  3250. else if (isEqual(type, "QObjectPropertyList"))
  3251. qDumpQObjectPropertyList(d);
  3252. else if (isEqual(type, "QObjectProperty"))
  3253. qDumpQObjectProperty(d);
  3254. else if (isEqual(type, "QObjectMethodList"))
  3255. qDumpQObjectMethodList(d);
  3256. else if (isEqual(type, "QObjectSignalList"))
  3257. qDumpQObjectSignalList(d);
  3258. else if (isEqual(type, "QObjectSignal"))
  3259. qDumpQObjectSignal(d);
  3260. else if (isEqual(type, "QObjectSlot"))
  3261. qDumpQObjectSlot(d);
  3262. else if (isEqual(type, "QObjectSlotList"))
  3263. qDumpQObjectSlotList(d);
  3264. else if (isEqual(type, "QObjectChildList"))
  3265. qDumpQObjectChildList(d);
  3266. # endif
  3267. break;
  3268. case 'P':
  3269. # if USE_QT_GUI
  3270. if (isEqual(type, "QPixmap"))
  3271. qDumpQPixmap(d);
  3272. # endif
  3273. # ifndef QT_BOOTSTRAPPED
  3274. if (isEqual(type, "QPoint"))
  3275. qDumpQPoint(d);
  3276. else if (isEqual(type, "QPointF"))
  3277. qDumpQPointF(d);
  3278. # endif
  3279. break;
  3280. case 'R':
  3281. # ifndef QT_BOOTSTRAPPED
  3282. if (isEqual(type, "QRect"))
  3283. qDumpQRect(d);
  3284. else if (isEqual(type, "QRectF"))
  3285. qDumpQRectF(d);
  3286. # endif
  3287. break;
  3288. case 'S':
  3289. if (isEqual(type, "QString"))
  3290. qDumpQString(d);
  3291. else if (isEqual(type, "QStringList"))
  3292. qDumpQStringList(d);
  3293. # ifndef QT_BOOTSTRAPPED
  3294. else if (isEqual(type, "QSet"))
  3295. qDumpQSet(d);
  3296. else if (isEqual(type, "QStack"))
  3297. qDumpQVector(d);
  3298. # if QT_VERSION >= 0x040500
  3299. else if (isEqual(type, "QSharedPointer"))
  3300. qDumpQSharedPointer(d);
  3301. # endif
  3302. # endif // QT_BOOTSTRAPPED
  3303. else if (isEqual(type, "QSize"))
  3304. qDumpQSize(d);
  3305. else if (isEqual(type, "QSizeF"))
  3306. qDumpQSizeF(d);
  3307. break;
  3308. case 'T':
  3309. # ifndef QT_BOOTSTRAPPED
  3310. if (isEqual(type, "QTextCodec"))
  3311. qDumpQTextCodec(d);
  3312. # endif
  3313. if (isEqual(type, "QTime"))
  3314. qDumpQTime(d);
  3315. break;
  3316. case 'V':
  3317. # ifndef QT_BOOTSTRAPPED
  3318. if (isEqual(type, "QVariantList")) { // resolve typedef
  3319. d.outerType = "QList";
  3320. d.innerType = "QVariant";
  3321. d.extraInt[0] = sizeof(QVariant);
  3322. qDumpQList(d);
  3323. } else if (isEqual(type, "QVariant")) {
  3324. qDumpQVariant(d);
  3325. } else if (isEqual(type, "QVector")) {
  3326. qDumpQVector(d);
  3327. }
  3328. # endif
  3329. break;
  3330. case 'W':
  3331. # ifndef QT_BOOTSTRAPPED
  3332. # if QT_VERSION >= 0x040500
  3333. if (isEqual(type, "QWeakPointer"))
  3334. qDumpQWeakPointer(d);
  3335. # endif
  3336. # endif
  3337. break;
  3338. #endif
  3339. }
  3340. if (!d.success)
  3341. qDumpUnknown(d);
  3342. }
  3343. } // anonymous namespace
  3344. #if USE_QT_GUI
  3345. extern "C" Q_DECL_EXPORT
  3346. void *watchPoint(int x, int y)
  3347. {
  3348. return QApplication::widgetAt(x, y);
  3349. }
  3350. #endif
  3351. extern "C" Q_DECL_EXPORT
  3352. void *qDumpObjectData440(
  3353. int protocolVersion,
  3354. int token,
  3355. const void *data,
  3356. int dumpChildren,
  3357. int extraInt0,
  3358. int extraInt1,
  3359. int extraInt2,
  3360. int extraInt3)
  3361. {
  3362. //sleep(20);
  3363. if (protocolVersion == 1) {
  3364. QDumper d;
  3365. d.protocolVersion = protocolVersion;
  3366. d.token = token;
  3367. // This is a list of all available dumpers. Note that some templates
  3368. // currently require special hardcoded handling in the debugger plugin.
  3369. // They are mentioned here nevertheless. For types that are not listed
  3370. // here, dumpers won't be used.
  3371. d.put("dumpers=["
  3372. "\"" NS "QAbstractItem\","
  3373. "\"" NS "QAbstractItemModel\","
  3374. "\"" NS "QByteArray\","
  3375. "\"" NS "QChar\","
  3376. "\"" NS "QDate\","
  3377. "\"" NS "QDateTime\","
  3378. "\"" NS "QDir\","
  3379. "\"" NS "QFile\","
  3380. "\"" NS "QFileInfo\","
  3381. "\"" NS "QHash\","
  3382. "\"" NS "QHashNode\","
  3383. "\"" NS "QImage\","
  3384. //"\"" NS "QImageData\","
  3385. "\"" NS "QLinkedList\","
  3386. "\"" NS "QList\","
  3387. "\"" NS "QLocale\","
  3388. #if MAP_WORKS
  3389. "\"" NS "QMap\","
  3390. "\"" NS "QMapNode\","
  3391. #endif
  3392. "\"" NS "QModelIndex\","
  3393. "\"" NS "QObject\","
  3394. "\"" NS "QObjectMethodList\"," // hack to get nested properties display
  3395. "\"" NS "QObjectProperty\","
  3396. "\"" NS "QObjectPropertyList\","
  3397. "\"" NS "QObjectSignal\","
  3398. "\"" NS "QObjectSignalList\","
  3399. "\"" NS "QObjectSlot\","
  3400. "\"" NS "QObjectSlotList\","
  3401. "\"" NS "QObjectChildList\","
  3402. "\"" NS "QPoint\","
  3403. "\"" NS "QPointF\","
  3404. "\"" NS "QRect\","
  3405. "\"" NS "QRectF\","
  3406. //"\"" NS "QRegion\","
  3407. "\"" NS "QSet\","
  3408. "\"" NS "QSize\","
  3409. "\"" NS "QSizeF\","
  3410. "\"" NS "QStack\","
  3411. "\"" NS "QString\","
  3412. "\"" NS "QStringList\","
  3413. "\"" NS "QTextCodec\","
  3414. "\"" NS "QTime\","
  3415. "\"" NS "QVariant\","
  3416. "\"" NS "QVariantList\","
  3417. "\"" NS "QVector\","
  3418. #if QT_VERSION >= 0x040500
  3419. #if MAP_WORKS
  3420. "\"" NS "QMultiMap\","
  3421. #endif
  3422. "\"" NS "QSharedPointer\","
  3423. "\"" NS "QWeakPointer\","
  3424. #endif
  3425. #if USE_QT_GUI
  3426. "\"" NS "QPixmap\","
  3427. "\"" NS "QWidget\","
  3428. #endif
  3429. #ifdef Q_OS_WIN
  3430. "\"basic_string\","
  3431. "\"list\","
  3432. "\"map\","
  3433. "\"set\","
  3434. "\"vector\","
  3435. #endif
  3436. "\"string\","
  3437. "\"wstring\","
  3438. "\"std::basic_string\","
  3439. "\"std::list\","
  3440. "\"std::map\","
  3441. "\"std::set\","
  3442. "\"std::string\","
  3443. "\"std::vector\","
  3444. "\"std::wstring\","
  3445. "]");
  3446. d.put(",qtversion=["
  3447. "\"").put(((QT_VERSION >> 16) & 255)).put("\","
  3448. "\"").put(((QT_VERSION >> 8) & 255)).put("\","
  3449. "\"").put(((QT_VERSION) & 255)).put("\"]");
  3450. d.put(",namespace=\"" NS "\",");
  3451. d.put("dumperversion=\"1.3\",");
  3452. d.disarm();
  3453. }
  3454. else if (protocolVersion == 2 || protocolVersion == 3) {
  3455. QDumper d;
  3456. d.protocolVersion = protocolVersion;
  3457. d.token = token;
  3458. d.data = data;
  3459. d.dumpChildren = dumpChildren;
  3460. d.extraInt[0] = extraInt0;
  3461. d.extraInt[1] = extraInt1;
  3462. d.extraInt[2] = extraInt2;
  3463. d.extraInt[3] = extraInt3;
  3464. const char *inbuffer = inBuffer;
  3465. d.outerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
  3466. d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
  3467. d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
  3468. d.innerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
  3469. d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
  3470. #if 0
  3471. qDebug() << "data=" << d.data << "dumpChildren=" << d.dumpChildren
  3472. << " extra=" << d.extraInt[0] << d.extraInt[1] << d.extraInt[2] << d.extraInt[3]
  3473. << d.outerType << d.iname << d.exp << d.iname;
  3474. #endif
  3475. handleProtocolVersion2and3(d);
  3476. }
  3477. else {
  3478. #if USE_QT_CORE
  3479. # ifndef QT_BOOTSTRAPPED
  3480. qDebug() << "Unsupported protocol version" << protocolVersion;
  3481. # endif
  3482. #endif
  3483. }
  3484. return outBuffer;
  3485. }