1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Qt Software Information (qt-info@nokia.com)
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at qt-sales@nokia.com.
28 **************************************************************************/
32 // this relies on contents copied from qobject_p.h
33 #define PRIVATE_OBJECT_ALLOWED 1
35 #include <QtCore/QDateTime>
36 #include <QtCore/QDebug>
37 #include <QtCore/QDir>
38 #include <QtCore/QFile>
39 #include <QtCore/QFileInfo>
40 #include <QtCore/QHash>
41 #include <QtCore/QLinkedList>
42 #include <QtCore/QLocale>
43 #include <QtCore/QMap>
44 #include <QtCore/QMetaObject>
45 #include <QtCore/QMetaProperty>
46 #include <QtCore/QModelIndex>
47 #include <QtCore/QObject>
48 #include <QtCore/QPointer>
49 #include <QtCore/QString>
50 #include <QtCore/QTextCodec>
51 #include <QtCore/QVector>
53 int qtGhVersion = QT_VERSION;
56 # include <QtGui/QPixmap>
57 # include <QtGui/QImage>
71 \brief Helper class for producing "nice" output in Qt Creator's debugger.
75 The whole "custom dumper" implementation is currently far less modular
76 than it could be. But as the code is still in a flux, making it nicer
77 from a pure archtectural point of view seems still be a waste of resources.
81 New dumpers for non-templated classes should be mentioned in
82 \c{qDumpObjectData440()} in the \c{protocolVersion == 1} branch.
84 Templated classes need extra support on the IDE level
85 (see plugins/debugger/gdbengine.cpp) and should not be mentiond in
86 \c{qDumpObjectData440()}.
88 In any case, dumper processesing should end up in
89 \c{handleProtocolVersion2and3()} and needs an entry in the bis switch there.
91 Next step is to create a suitable \c{static void qDumpFoo(QDumper &d)}
92 function. At the bare minimum it should contain something like:
96 const Foo &foo = *reinterpret_cast<const Foo *>(d.data);
100 P(d, "numchild", "0");
104 'P(d, name, value)' roughly expands to:
105 d << (name) << "=\"" << value << "\"";
107 Useful (i.e. understood by the IDE) names include:
110 \o "name" shows up in the first column in the Locals&Watchers view.
111 \o "value" shows up in the second column.
112 \o "valueencoded" should be set to "1" if the value is base64 encoded.
113 Always base64-encode values that might use unprintable or otherwise
114 "confuse" the protocol (like spaces and quotes). [A-Za-z0-9] is "safe".
115 A value of "3" is used for base64-encoded UCS4, "2" denotes
116 base64-encoded UTF16.
117 \o "numchild" return the number of children in the view. Effectively, only
118 0 and != 0 will be used, so don't try too hard to get the number right.
121 If the current item has children, it might be queried to produce information
122 about thes children. In this case the dumper should use something like
125 if (d.dumpChildren) {
133 # define STRINGIFY0(s) #s
134 # define STRINGIFY1(s) STRINGIFY0(s)
135 # define NS STRINGIFY1(QT_NAMESPACE) "::"
136 # define NSX "'" STRINGIFY1(QT_NAMESPACE) "::"
145 #if PRIVATE_OBJECT_ALLOWED
147 #if defined(QT_BEGIN_NAMESPACE)
153 class QObjectConnectionListVector;
155 class QObjectPrivate : public QObjectData
157 Q_DECLARE_PUBLIC(QObject)
161 virtual ~QObjectPrivate() {}
163 // preserve binary compatibility with code compiled without Qt 3 support
164 QList<QObject *> pendingChildInsertedEvents; // unused
166 // id of the thread that owns the object
167 QThreadData *threadData;
176 Sender *currentSender; // object currently activating the object
177 QObject *currentChildBeingDeleted;
179 QList<QPointer<QObject> > eventFilters;
182 ExtraData *extraData;
183 mutable quint32 connectedSignals;
191 uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
192 QBasicAtomicPointer<int> argumentTypes;
194 typedef QList<Connection> ConnectionList;
196 QObjectConnectionListVector *connectionLists;
197 QList<Sender> senders;
201 #if defined(QT_BEGIN_NAMESPACE)
205 #endif // PRIVATE_OBJECT_ALLOWED
208 // this can be mangled typenames of nested templates, each char-by-char
209 // comma-separated integer list
210 static char qDumpInBuffer[10000];
211 static char qDumpOutBuffer[100000];
212 //static char qDumpSize[20];
216 static bool isPointerType(const QByteArray &type)
218 return type.endsWith("*") || type.endsWith("* const");
221 static QByteArray stripPointerType(QByteArray type)
223 if (type.endsWith("*"))
225 if (type.endsWith("* const"))
227 if (type.endsWith(' '))
232 // This is used to abort evaluation of custom data dumpers in a "coordinated"
233 // way. Abortion will happen anyway when we try to access a non-initialized
234 // non-trivial object, so there is no way to prevent this from occuring at all
235 // conceptionally. Gdb will catch SIGSEGV and return to the calling frame.
236 // This is just fine provided we only _read_ memory in the custom handlers
239 volatile int qProvokeSegFaultHelper;
241 static const void *addOffset(const void *p, int offset)
243 return offset + reinterpret_cast<const char *>(p);
246 static const void *skipvtable(const void *p)
248 return sizeof(void*) + reinterpret_cast<const char *>(p);
251 static const void *deref(const void *p)
253 return *reinterpret_cast<const char* const*>(p);
256 static const void *dfunc(const void *p)
258 return deref(skipvtable(p));
261 static bool isEqual(const char *s, const char *t)
263 return qstrcmp(s, t) == 0;
266 static bool startsWith(const char *s, const char *t)
268 return qstrncmp(s, t, strlen(t)) == 0;
271 // provoke segfault when address is not readable
272 #define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0)
273 #define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
274 // provoke segfault unconditionally
275 #define qCheck(b) do { if (!(b)) qProvokeSegFaultHelper = *(char*)0; } while (0)
277 const char *stripNamespace(const char *type)
279 static const size_t nslen = strlen(NS);
280 return startsWith(type, NS) ? type + nslen : type;
283 static bool isSimpleType(const char *type)
287 return isEqual(type, "char");
289 return isEqual(type, "double");
291 return isEqual(type, "float");
293 return isEqual(type, "int");
295 return isEqual(type, "long") || startsWith(type, "long ");
297 return isEqual(type, "short") || isEqual(type, "signed")
298 || startsWith(type, "signed ");
300 return isEqual(type, "unsigned") || startsWith(type, "unsigned ");
306 static bool isStringType(const char *type)
308 return isEqual(type, NS"QString")
309 || isEqual(type, NS"QByteArray")
310 || isEqual(type, "std::string")
311 || isEqual(type, "std::wstring")
312 || isEqual(type, "wstring");
316 static bool isMovableType(const char *type)
318 if (isPointerType(type))
321 if (isSimpleType(type))
324 type = stripNamespace(type);
328 return isEqual(type, "QBrush")
329 || isEqual(type, "QBitArray")
330 || isEqual(type, "QByteArray") ;
332 return isEqual(type, "QCustomTypeInfo");
334 return isEqual(type, "QDate")
335 || isEqual(type, "QDateTime");
337 return isEqual(type, "QFileInfo")
338 || isEqual(type, "QFixed")
339 || isEqual(type, "QFixedPoint")
340 || isEqual(type, "QFixedSize");
342 return isEqual(type, "QHashDummyValue");
344 return isEqual(type, "QIcon")
345 || isEqual(type, "QImage");
347 return isEqual(type, "QLine")
348 || isEqual(type, "QLineF")
349 || isEqual(type, "QLocal");
351 return isEqual(type, "QMatrix")
352 || isEqual(type, "QModelIndex");
354 return isEqual(type, "QPoint")
355 || isEqual(type, "QPointF")
356 || isEqual(type, "QPen")
357 || isEqual(type, "QPersistentModelIndex");
359 return isEqual(type, "QResourceRoot")
360 || isEqual(type, "QRect")
361 || isEqual(type, "QRectF")
362 || isEqual(type, "QRegExp");
364 return isEqual(type, "QSize")
365 || isEqual(type, "QSizeF")
366 || isEqual(type, "QString");
368 return isEqual(type, "QTime")
369 || isEqual(type, "QTextBlock");
371 return isEqual(type, "QUrl");
373 return isEqual(type, "QVariant");
375 return isEqual(type, "QXmlStreamAttribute")
376 || isEqual(type, "QXmlStreamNamespaceDeclaration")
377 || isEqual(type, "QXmlStreamNotationDeclaration")
378 || isEqual(type, "QXmlStreamEntityDeclaration");
388 QDumper &operator<<(long c);
389 QDumper &operator<<(int i);
390 QDumper &operator<<(double d);
391 QDumper &operator<<(float d);
392 QDumper &operator<<(unsigned long c);
393 QDumper &operator<<(unsigned int i);
394 QDumper &operator<<(const void *p);
395 QDumper &operator<<(qulonglong c);
396 QDumper &operator<<(const char *str);
397 QDumper &operator<<(const QByteArray &ba);
398 QDumper &operator<<(const QString &str);
400 void addCommaIfNeeded();
401 void putBase64Encoded(const char *buf, int n);
405 void beginHash(); // start of data hash output
406 void endHash(); // start of data hash output
408 // the dumper arguments
409 int protocolVersion; // dumper protocol version
410 int token; // some token to show on success
411 const char *outertype; // object type
412 const char *iname; // object name used for display
413 const char *exp; // object expression
414 const char *innertype; // 'inner type' for class templates
415 const void *data; // pointer to raw data
416 bool dumpChildren; // do we want to see children?
418 // handling of nested templates
419 void setupTemplateParameters();
420 enum { maxTemplateParameters = 10 };
421 const char *templateParameters[maxTemplateParameters + 1];
422 int templateParametersCount;
425 bool success; // are we finished?
437 qDumpOutBuffer[0] = 'f'; // marks output as 'wrong'
443 qDumpOutBuffer[pos++] = '\0';
445 qDumpOutBuffer[0] = (full ? '+' : 't');
448 void QDumper::setupTemplateParameters()
450 char *s = const_cast<char *>(innertype);
452 templateParametersCount = 1;
453 templateParameters[0] = s;
454 for (int i = 1; i != maxTemplateParameters + 1; ++i)
455 templateParameters[i] = 0;
458 while (*s && *s != '@')
463 templateParameters[templateParametersCount++] = s;
468 QDumper &QDumper::operator<<(unsigned long long c)
471 pos += sprintf(qDumpOutBuffer + pos, "%llu", c);
475 QDumper &QDumper::operator<<(unsigned long c)
478 pos += sprintf(qDumpOutBuffer + pos, "%lu", c);
482 QDumper &QDumper::operator<<(float d)
485 pos += sprintf(qDumpOutBuffer + pos, "%f", d);
489 QDumper &QDumper::operator<<(double d)
492 pos += sprintf(qDumpOutBuffer + pos, "%f", d);
496 QDumper &QDumper::operator<<(unsigned int i)
499 pos += sprintf(qDumpOutBuffer + pos, "%u", i);
503 QDumper &QDumper::operator<<(long c)
506 pos += sprintf(qDumpOutBuffer + pos, "%ld", c);
510 QDumper &QDumper::operator<<(int i)
513 pos += sprintf(qDumpOutBuffer + pos, "%d", i);
517 QDumper &QDumper::operator<<(const void *p)
519 static char buf[100];
521 sprintf(buf, "%p", p);
522 // we get a '0x' prefix only on some implementations.
523 // if it isn't there, write it out manually.
535 void QDumper::checkFill()
537 if (pos >= int(sizeof(qDumpOutBuffer)) - 100)
541 void QDumper::put(char c)
545 qDumpOutBuffer[pos++] = c;
548 void QDumper::addCommaIfNeeded()
552 char c = qDumpOutBuffer[pos - 1];
553 if (c == '}' || c == '"' || c == ']')
557 void QDumper::putBase64Encoded(const char *buf, int n)
559 const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
560 "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
561 const char padchar = '=';
564 //int tmpsize = ((n * 4) / 3) + 3;
569 chunk |= int(uchar(buf[i++])) << 16;
573 chunk |= int(uchar(buf[i++])) << 8;
577 chunk |= int(uchar(buf[i++]));
580 int j = (chunk & 0x00fc0000) >> 18;
581 int k = (chunk & 0x0003f000) >> 12;
582 int l = (chunk & 0x00000fc0) >> 6;
583 int m = (chunk & 0x0000003f);
586 put(padlen > 1 ? padchar : alphabet[l]);
587 put(padlen > 0 ? padchar : alphabet[m]);
591 QDumper &QDumper::operator<<(const char *str)
594 return *this << "<null>";
600 QDumper &QDumper::operator<<(const QByteArray &ba)
602 putBase64Encoded(ba.constData(), ba.size());
606 QDumper &QDumper::operator<<(const QString &str)
608 QByteArray ba = str.toUtf8();
609 putBase64Encoded(ba.constData(), ba.size());
613 void QDumper::disarm()
618 void QDumper::beginHash()
624 void QDumper::endHash()
629 void QDumper::putEllipsis()
632 *this << "{name=\"<incomplete>\",value=\"\",type=\"" << innertype << "\"}";
636 // Some helpers to keep the dumper code short
639 // dump property=value pair
641 #define P(dumper,name,value) \
643 dumper.addCommaIfNeeded(); \
644 dumper << (name) << "=\"" << value << "\""; \
647 // simple string property
649 #define S(dumper, name, value) \
650 dumper.beginHash(); \
651 P(dumper, "name", name); \
652 P(dumper, "value", value); \
653 P(dumper, "type", NS"QString"); \
654 P(dumper, "numchild", "0"); \
655 P(dumper, "valueencoded", "1"); \
658 // simple integer property
660 #define I(dumper, name, value) \
661 dumper.beginHash(); \
662 P(dumper, "name", name); \
663 P(dumper, "value", value); \
664 P(dumper, "type", "int"); \
665 P(dumper, "numchild", "0"); \
668 // simple boolean property
670 #define BL(dumper, name, value) \
671 dumper.beginHash(); \
672 P(dumper, "name", name); \
673 P(dumper, "value", (value ? "true" : "false")); \
674 P(dumper, "type", "bool"); \
675 P(dumper, "numchild", "0"); \
681 #define QC(dumper, name, value) \
682 dumper.beginHash(); \
683 P(dumper, "name", name); \
684 P(dumper, "value", QString(QLatin1String("'%1' (%2, 0x%3)")) \
685 .arg(value).arg(value.unicode()).arg(value.unicode(), 0, 16)); \
686 P(dumper, "valueencoded", "1"); \
687 P(dumper, "type", NS"QChar"); \
688 P(dumper, "numchild", "0"); \
692 #define TT(type, value) \
693 "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>"
695 static void qDumpUnknown(QDumper &d)
697 P(d, "iname", d.iname);
698 P(d, "addr", d.data);
699 P(d, "value", "<internal error>");
700 P(d, "type", d.outertype);
701 P(d, "numchild", "0");
705 static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
706 const char *field = "value")
708 type = stripNamespace(type);
711 if (isEqual(type, "float"))
712 P(d, field, *(float*)addr);
715 if (isEqual(type, "int"))
716 P(d, field, *(int*)addr);
717 else if (isEqual(type, "unsigned"))
718 P(d, field, *(unsigned int*)addr);
719 else if (isEqual(type, "unsigned int"))
720 P(d, field, *(unsigned int*)addr);
721 else if (isEqual(type, "unsigned long"))
722 P(d, field, *(unsigned long*)addr);
723 else if (isEqual(type, "unsigned long long"))
724 P(d, field, *(qulonglong*)addr);
727 if (isEqual(type, "bool"))
728 switch (*(bool*)addr) {
729 case 0: P(d, field, "false"); break;
730 case 1: P(d, field, "true"); break;
731 default: P(d, field, *(bool*)addr); break;
733 else if (isEqual(type, "double"))
734 P(d, field, *(double*)addr);
735 else if (isEqual(type, "long"))
736 P(d, field, *(long*)addr);
737 else if (isEqual(type, "long long"))
738 P(d, field, *(qulonglong*)addr);
741 if (isEqual(type, "QByteArray")) {
742 d.addCommaIfNeeded();
743 d << field << "encoded=\"1\",";
744 P(d, field, *(QByteArray*)addr);
748 if (startsWith(type, "QList<")) {
749 const QListData *ldata = reinterpret_cast<const QListData*>(addr);
750 P(d, "value", "<" << ldata->size() << " items>");
751 P(d, "valuedisabled", "true");
752 P(d, "numchild", ldata->size());
756 if (isEqual(type, "QObject *")) {
758 const QObject *ob = reinterpret_cast<const QObject *>(addr);
760 P(d, "value", ob->objectName());
761 P(d, "valueencoded", "1");
762 P(d, "type", NS"QObject");
763 P(d, "displayedtype", ob->metaObject()->className());
765 P(d, "value", "0x0");
766 P(d, "type", NS"QObject *");
771 if (isEqual(type, "QString")) {
772 d.addCommaIfNeeded();
773 d << field << "encoded=\"1\",";
774 P(d, field, *(QString*)addr);
782 static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
790 qDumpInnerValueHelper(d, type, addr);
794 static void qDumpInnerValueOrPointer(QDumper &d,
795 const char *type, const char *strippedtype, const void *addr)
799 P(d, "addr", deref(addr));
800 P(d, "type", strippedtype);
801 qDumpInnerValueHelper(d, strippedtype, deref(addr));
804 P(d, "type", strippedtype);
805 P(d, "value", "<null>");
806 P(d, "numchild", "0");
811 qDumpInnerValueHelper(d, type, addr);
815 //////////////////////////////////////////////////////////////////////////////
817 static void qDumpQByteArray(QDumper &d)
819 const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
822 qCheckAccess(ba.constData());
823 qCheckAccess(ba.constData() + ba.size());
826 if (ba.size() <= 100)
829 P(d, "value", ba.left(100) << " <size: " << ba.size() << ", cut...>");
830 P(d, "valueencoded", "1");
831 P(d, "type", NS"QByteArray");
832 P(d, "numchild", ba.size());
833 P(d, "childtype", "char");
834 P(d, "childnumchild", "0");
835 if (d.dumpChildren) {
838 for (int i = 0; i != ba.size(); ++i) {
839 unsigned char c = ba.at(i);
840 unsigned char u = (isprint(c) && c != '\'' && c != '"') ? c : '?';
841 sprintf(buf, "%02x (%u '%c')", c, c, u);
852 static void qDumpQDateTime(QDumper &d)
854 #ifdef QT_NO_DATESTRING
857 const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data);
859 P(d, "value", "(null)");
861 P(d, "value", date.toString());
862 P(d, "valueencoded", "1");
864 P(d, "type", NS"QDateTime");
865 P(d, "numchild", "3");
866 if (d.dumpChildren) {
868 BL(d, "isNull", date.isNull());
869 I(d, "toTime_t", (long)date.toTime_t());
870 S(d, "toString", date.toString());
871 S(d, "toString_(ISO)", date.toString(Qt::ISODate));
872 S(d, "toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
873 S(d, "toString_(Locale)", date.toString(Qt::LocaleDate));
874 S(d, "toString", date.toString());
878 P(d, "name", "toUTC");
879 P(d, "exp", "(("NSX"QDateTime"NSY"*)" << d.data << ")"
880 "->toTimeSpec('"NS"Qt::UTC')");
881 P(d, "type", NS"QDateTime");
882 P(d, "numchild", "1");
888 P(d, "name", "toLocalTime");
889 P(d, "exp", "(("NSX"QDateTime"NSY"*)" << d.data << ")"
890 "->toTimeSpec('"NS"Qt::LocalTime')");
891 P(d, "type", NS"QDateTime");
892 P(d, "numchild", "1");
899 #endif // ifdef QT_NO_DATESTRING
902 static void qDumpQDir(QDumper &d)
904 const QDir &dir = *reinterpret_cast<const QDir *>(d.data);
905 P(d, "value", dir.path());
906 P(d, "valueencoded", "1");
907 P(d, "type", NS"QDir");
908 P(d, "numchild", "3");
909 if (d.dumpChildren) {
911 S(d, "absolutePath", dir.absolutePath());
912 S(d, "canonicalPath", dir.canonicalPath());
918 static void qDumpQFile(QDumper &d)
920 const QFile &file = *reinterpret_cast<const QFile *>(d.data);
921 P(d, "value", file.fileName());
922 P(d, "valueencoded", "1");
923 P(d, "type", NS"QFile");
924 P(d, "numchild", "2");
925 if (d.dumpChildren) {
927 S(d, "fileName", file.fileName());
928 BL(d, "exists", file.exists());
934 static void qDumpQFileInfo(QDumper &d)
936 const QFileInfo &info = *reinterpret_cast<const QFileInfo *>(d.data);
937 P(d, "value", info.filePath());
938 P(d, "valueencoded", "1");
939 P(d, "type", NS"QFileInfo");
940 P(d, "numchild", "3");
941 if (d.dumpChildren) {
943 S(d, "absolutePath", info.absolutePath());
944 S(d, "absoluteFilePath", info.absoluteFilePath());
945 S(d, "canonicalPath", info.canonicalPath());
946 S(d, "canonicalFilePath", info.canonicalFilePath());
947 S(d, "completeBaseName", info.completeBaseName());
948 S(d, "completeSuffix", info.completeSuffix());
949 S(d, "baseName", info.baseName());
951 BL(d, "isBundle", info.isBundle());
952 S(d, "bundleName", info.bundleName());
954 S(d, "completeSuffix", info.completeSuffix());
955 S(d, "fileName", info.fileName());
956 S(d, "filePath", info.filePath());
957 S(d, "group", info.group());
958 S(d, "owner", info.owner());
959 S(d, "path", info.path());
961 I(d, "groupid", (long)info.groupId());
962 I(d, "ownerid", (long)info.ownerId());
963 //QFile::Permissions permissions () const
964 I(d, "permissions", info.permissions());
966 //QDir absoluteDir () const
969 BL(d, "caching", info.caching());
970 BL(d, "exists", info.exists());
971 BL(d, "isAbsolute", info.isAbsolute());
972 BL(d, "isDir", info.isDir());
973 BL(d, "isExecutable", info.isExecutable());
974 BL(d, "isFile", info.isFile());
975 BL(d, "isHidden", info.isHidden());
976 BL(d, "isReadable", info.isReadable());
977 BL(d, "isRelative", info.isRelative());
978 BL(d, "isRoot", info.isRoot());
979 BL(d, "isSymLink", info.isSymLink());
980 BL(d, "isWritable", info.isWritable());
983 P(d, "name", "created");
984 P(d, "value", info.created().toString());
985 P(d, "valueencoded", "1");
986 P(d, "exp", "(("NSX"QFileInfo"NSY"*)" << d.data << ")->created()");
987 P(d, "type", NS"QDateTime");
988 P(d, "numchild", "1");
992 P(d, "name", "lastModified");
993 P(d, "value", info.lastModified().toString());
994 P(d, "valueencoded", "1");
995 P(d, "exp", "(("NSX"QFileInfo"NSY"*)" << d.data << ")->lastModified()");
996 P(d, "type", NS"QDateTime");
997 P(d, "numchild", "1");
1001 P(d, "name", "lastRead");
1002 P(d, "value", info.lastRead().toString());
1003 P(d, "valueencoded", "1");
1004 P(d, "exp", "(("NSX"QFileInfo"NSY"*)" << d.data << ")->lastRead()");
1005 P(d, "type", NS"QDateTime");
1006 P(d, "numchild", "1");
1014 bool isOptimizedIntKey(const char *keyType)
1016 return isEqual(keyType, "int")
1017 #if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
1018 || isEqual(keyType, "short")
1019 || isEqual(keyType, "ushort")
1021 || isEqual(keyType, "uint");
1024 int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned valueSize)
1026 // int-key optimization, small value
1027 struct NodeOS { void *next; uint k; uint v; } nodeOS;
1028 // int-key optimiatzion, large value
1029 struct NodeOL { void *next; uint k; void *v; } nodeOL;
1030 // no optimization, small value
1031 struct NodeNS { void *next; uint h; uint k; uint v; } nodeNS;
1032 // no optimization, large value
1033 struct NodeNL { void *next; uint h; uint k; void *v; } nodeNL;
1035 struct NodeL { void *next; uint h; void *k; void *v; } nodeL;
1038 // offsetof(...,...) not yet in Standard C++
1039 const ulong nodeOSk ( (char *)&nodeOS.k - (char *)&nodeOS );
1040 const ulong nodeOLk ( (char *)&nodeOL.k - (char *)&nodeOL );
1041 const ulong nodeNSk ( (char *)&nodeNS.k - (char *)&nodeNS );
1042 const ulong nodeNLk ( (char *)&nodeNL.k - (char *)&nodeNL );
1043 const ulong nodeLk ( (char *)&nodeL.k - (char *)&nodeL );
1044 if (optimizedIntKey)
1045 return valueSize > sizeof(int) ? nodeOLk : nodeOSk;
1046 if (keySize > sizeof(int))
1048 return valueSize > sizeof(int) ? nodeNLk : nodeNSk;
1050 const ulong nodeOSv ( (char *)&nodeOS.v - (char *)&nodeOS );
1051 const ulong nodeOLv ( (char *)&nodeOL.v - (char *)&nodeOL );
1052 const ulong nodeNSv ( (char *)&nodeNS.v - (char *)&nodeNS );
1053 const ulong nodeNLv ( (char *)&nodeNL.v - (char *)&nodeNL );
1054 const ulong nodeLv ( (char *)&nodeL.v - (char *)&nodeL );
1055 if (optimizedIntKey)
1056 return valueSize > sizeof(int) ? nodeOLv : nodeOSv;
1057 if (keySize > sizeof(int))
1059 return valueSize > sizeof(int) ? nodeNLv : nodeNSv;
1064 static void qDumpQHash(QDumper &d)
1066 QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
1067 const char *keyType = d.templateParameters[0];
1068 const char *valueType = d.templateParameters[1];
1070 qCheckPointer(h->fakeNext);
1071 qCheckPointer(h->buckets);
1073 unsigned keySize = d.extraInt[0];
1074 unsigned valueSize = d.extraInt[1];
1081 qCheckPointer(h->fakeNext);
1082 qCheckPointer(*h->buckets);
1085 P(d, "value", "<" << n << " items>");
1086 P(d, "numchild", n);
1087 if (d.dumpChildren) {
1090 bool isSimpleKey = isSimpleType(keyType);
1091 bool isSimpleValue = isSimpleType(valueType);
1092 bool opt = isOptimizedIntKey(keyType);
1093 int keyOffset = hashOffset(opt, true, keySize, valueSize);
1094 int valueOffset = hashOffset(opt, false, keySize, valueSize);
1096 P(d, "extra", "isSimpleKey: " << isSimpleKey
1097 << " isSimpleValue: " << isSimpleValue
1098 << " valueType: '" << isSimpleValue
1099 << " keySize: " << keyOffset << " valueOffset: " << valueOffset
1100 << " opt: " << opt);
1102 QHashData::Node *node = h->firstNode();
1103 QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h);
1107 while (node != end) {
1110 qDumpInnerValueHelper(d, keyType, addOffset(node, keyOffset), "key");
1111 qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
1112 if (isSimpleKey && isSimpleValue) {
1113 P(d, "type", valueType);
1114 P(d, "addr", addOffset(node, valueOffset));
1116 P(d, "exp", "*('"NS"QHashNode<" << keyType << ","
1117 << valueType << " >'*)" << node);
1118 P(d, "type", "'"NS"QHashNode<" << keyType << ","
1119 << valueType << " >'");
1123 node = QHashData::nextNode(node);
1130 static void qDumpQHashNode(QDumper &d)
1132 const QHashData *h = reinterpret_cast<const QHashData *>(d.data);
1133 const char *keyType = d.templateParameters[0];
1134 const char *valueType = d.templateParameters[1];
1136 unsigned keySize = d.extraInt[0];
1137 unsigned valueSize = d.extraInt[1];
1138 bool opt = isOptimizedIntKey(keyType);
1139 int keyOffset = hashOffset(opt, true, keySize, valueSize);
1140 int valueOffset = hashOffset(opt, false, keySize, valueSize);
1141 if (isSimpleType(valueType))
1142 qDumpInnerValueHelper(d, valueType, addOffset(h, valueOffset));
1146 P(d, "numchild", 2);
1147 if (d.dumpChildren) {
1148 // there is a hash specialization in cast the key are integers or shorts
1151 P(d, "name", "key");
1152 P(d, "type", keyType);
1153 P(d, "addr", addOffset(h, keyOffset));
1156 P(d, "name", "value");
1157 P(d, "type", valueType);
1158 P(d, "addr", addOffset(h, valueOffset));
1165 static void qDumpQImage(QDumper &d)
1168 const QImage &im = *reinterpret_cast<const QImage *>(d.data);
1169 P(d, "value", "(" << im.width() << "x" << im.height() << ")");
1170 P(d, "type", NS"QImage");
1171 P(d, "numchild", "0");
1178 static void qDumpQList(QDumper &d)
1180 // This uses the knowledge that QList<T> has only a single member
1181 // of type union { QListData p; QListData::Data *d; };
1182 const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
1183 const QListData::Data *pdata =
1184 *reinterpret_cast<const QListData::Data* const*>(d.data);
1185 int nn = ldata.size();
1189 qCheckAccess(ldata.d->array);
1190 //qCheckAccess(ldata.d->array[0]);
1191 //qCheckAccess(ldata.d->array[nn - 1]);
1192 #if QT_VERSION >= 0x040400
1193 if (ldata.d->ref._q_value <= 0)
1199 P(d, "value", "<" << n << " items>");
1200 P(d, "valuedisabled", "true");
1201 P(d, "numchild", n);
1202 P(d, "childtype", d.innertype);
1203 if (d.dumpChildren) {
1204 unsigned innerSize = d.extraInt[0];
1205 bool innerTypeIsPointer = isPointerType(d.innertype);
1206 QByteArray strippedInnerType = stripPointerType(d.innertype);
1208 // The exact condition here is:
1209 // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
1210 // but this data is available neither in the compiled binary nor
1212 // So as first approximation only do the 'isLarge' check:
1213 bool isInternal = innerSize <= int(sizeof(void*))
1214 && isMovableType(d.innertype);
1216 P(d, "internal", (int)isInternal);
1217 P(d, "childtype", d.innertype);
1221 for (int i = 0; i != n; ++i) {
1224 if (innerTypeIsPointer) {
1225 void *p = ldata.d->array + i + pdata->begin;
1227 //P(d, "value","@" << p);
1228 qDumpInnerValue(d, strippedInnerType.data(), deref(p));
1230 P(d, "value", "<null>");
1231 P(d, "numchild", "0");
1234 void *p = ldata.d->array + i + pdata->begin;
1236 //qDumpInnerValue(d, d.innertype, p);
1238 qDumpInnerValueHelper(d, d.innertype, p);
1240 //qDumpInnerValue(d, d.innertype, deref(p));
1241 P(d, "addr", deref(p));
1242 qDumpInnerValueHelper(d, d.innertype, deref(p));
1254 static void qDumpQLinkedList(QDumper &d)
1256 // This uses the knowledge that QLinkedList<T> has only a single member
1257 // of type union { QLinkedListData *d; QLinkedListNode<T> *e; };
1258 const QLinkedListData *ldata =
1259 reinterpret_cast<const QLinkedListData*>(deref(d.data));
1260 int nn = ldata->size;
1265 P(d, "value", "<" << n << " items>");
1266 P(d, "valuedisabled", "true");
1267 P(d, "numchild", n);
1268 P(d, "childtype", d.innertype);
1269 if (d.dumpChildren) {
1270 //unsigned innerSize = d.extraInt[0];
1271 //bool innerTypeIsPointer = isPointerType(d.innertype);
1272 QByteArray strippedInnerType = stripPointerType(d.innertype);
1273 const char *stripped =
1274 isPointerType(d.innertype) ? strippedInnerType.data() : 0;
1276 P(d, "childtype", d.innertype);
1280 const void *p = deref(ldata);
1281 for (int i = 0; i != n; ++i) {
1284 const void *addr = addOffset(p, 2 * sizeof(void*));
1285 qDumpInnerValueOrPointer(d, d.innertype, stripped, addr);
1296 static void qDumpQLocale(QDumper &d)
1298 const QLocale &locale = *reinterpret_cast<const QLocale *>(d.data);
1299 P(d, "value", locale.name());
1300 P(d, "valueencoded", "1");
1301 P(d, "type", NS"QLocale");
1302 P(d, "numchild", "8");
1303 if (d.dumpChildren) {
1307 P(d, "name", "country");
1308 P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->country()");
1312 P(d, "name", "language");
1313 P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->language()");
1317 P(d, "name", "measurementSystem");
1318 P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->measurementSystem()");
1322 P(d, "name", "numberOptions");
1323 P(d, "exp", "(("NSX"QLocale"NSY"*)" << d.data << ")->numberOptions()");
1326 S(d, "timeFormat_(short)", locale.timeFormat(QLocale::ShortFormat));
1327 S(d, "timeFormat_(long)", locale.timeFormat(QLocale::LongFormat));
1329 QC(d, "decimalPoint", locale.decimalPoint());
1330 QC(d, "exponential", locale.exponential());
1331 QC(d, "percent", locale.percent());
1332 QC(d, "zeroDigit", locale.zeroDigit());
1333 QC(d, "groupSeparator", locale.groupSeparator());
1334 QC(d, "negativeSign", locale.negativeSign());
1341 static void qDumpQMapNode(QDumper &d)
1343 const QMapData *h = reinterpret_cast<const QMapData *>(d.data);
1344 const char *keyType = d.templateParameters[0];
1345 const char *valueType = d.templateParameters[1];
1347 qCheckAccess(h->backward);
1348 qCheckAccess(h->forward[0]);
1351 P(d, "numchild", 2);
1352 if (d.dumpChildren) {
1353 //unsigned keySize = d.extraInt[0];
1354 //unsigned valueSize = d.extraInt[1];
1355 unsigned mapnodesize = d.extraInt[2];
1356 unsigned valueOff = d.extraInt[3];
1358 unsigned keyOffset = 2 * sizeof(void*) - mapnodesize;
1359 unsigned valueOffset = 2 * sizeof(void*) - mapnodesize + valueOff;
1363 P(d, "name", "key");
1364 qDumpInnerValue(d, keyType, addOffset(h, keyOffset));
1368 P(d, "name", "value");
1369 qDumpInnerValue(d, valueType, addOffset(h, valueOffset));
1377 static void qDumpQMap(QDumper &d)
1379 QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
1380 const char *keyType = d.templateParameters[0];
1381 const char *valueType = d.templateParameters[1];
1388 qCheckAccess(h->backward);
1389 qCheckAccess(h->forward[0]);
1390 qCheckPointer(h->backward->backward);
1391 qCheckPointer(h->forward[0]->backward);
1394 P(d, "value", "<" << n << " items>");
1395 P(d, "numchild", n);
1396 if (d.dumpChildren) {
1400 //unsigned keySize = d.extraInt[0];
1401 //unsigned valueSize = d.extraInt[1];
1402 unsigned mapnodesize = d.extraInt[2];
1403 unsigned valueOff = d.extraInt[3];
1405 bool isSimpleKey = isSimpleType(keyType);
1406 bool isSimpleValue = isSimpleType(valueType);
1408 int keyOffset = 2 * sizeof(void*) - int(mapnodesize);
1409 int valueOffset = 2 * sizeof(void*) - int(mapnodesize) + valueOff;
1411 P(d, "extra", "simplekey: " << isSimpleKey << " isSimpleValue: " << isSimpleValue
1412 << " keyOffset: " << keyOffset << " valueOffset: " << valueOffset
1413 << " mapnodesize: " << mapnodesize);
1416 QMapData::Node *node = reinterpret_cast<QMapData::Node *>(h->forward[0]);
1417 QMapData::Node *end = reinterpret_cast<QMapData::Node *>(h);
1420 while (node != end) {
1423 qDumpInnerValueHelper(d, keyType, addOffset(node, keyOffset), "key");
1424 qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
1425 if (isSimpleKey && isSimpleValue) {
1426 P(d, "type", valueType);
1427 P(d, "addr", addOffset(node, valueOffset));
1429 #if QT_VERSION >= 0x040500
1430 // actually, any type (even 'char') will do...
1431 P(d, "type", NS"QMapNode<"
1432 << keyType << "," << valueType << " >");
1433 P(d, "exp", "*('"NS"QMapNode<"
1434 << keyType << "," << valueType << " >'*)" << node);
1436 //P(d, "exp", "*('"NS"QMapData'*)" << (void*)node);
1437 //P(d, "exp", "*(char*)" << (void*)node);
1438 // P(d, "addr", node); does not work as gdb fails to parse
1440 P(d, "type", NS"QMapData::Node<"
1441 << keyType << "," << valueType << " >");
1442 P(d, "exp", "*('"NS"QMapData::Node<"
1443 << keyType << "," << valueType << " >'*)" << node);
1449 node = node->forward[0];
1457 static void qDumpQMultiMap(QDumper &d)
1462 static void qDumpQModelIndex(QDumper &d)
1464 const QModelIndex *mi = reinterpret_cast<const QModelIndex *>(d.data);
1466 P(d, "type", NS"QModelIndex");
1467 if (mi->isValid()) {
1468 P(d, "value", "(" << mi->row() << ", " << mi->column() << ")");
1469 P(d, "numchild", 5);
1470 if (d.dumpChildren) {
1472 I(d, "row", mi->row());
1473 I(d, "column", mi->column());
1476 P(d, "name", "parent");
1477 const QModelIndex parent = mi->parent();
1478 if (parent.isValid())
1479 P(d, "value", "(" << mi->row() << ", " << mi->column() << ")");
1481 P(d, "value", "<invalid>");
1482 P(d, "exp", "(("NSX"QModelIndex"NSY"*)" << d.data << ")->parent()");
1483 P(d, "type", NS"QModelIndex");
1484 P(d, "numchild", "1");
1487 S(d, "internalId", QString::number(mi->internalId(), 10));
1490 P(d, "name", "model");
1491 P(d, "value", static_cast<const void *>(mi->model()));
1492 P(d, "type", NS"QAbstractItemModel*");
1493 P(d, "numchild", "1");
1499 P(d, "value", "<invalid>");
1500 P(d, "numchild", 0);
1506 static void qDumpQObject(QDumper &d)
1508 const QObject *ob = reinterpret_cast<const QObject *>(d.data);
1509 const QMetaObject *mo = ob->metaObject();
1510 unsigned childrenOffset = d.extraInt[0];
1511 P(d, "value", ob->objectName());
1512 P(d, "valueencoded", "1");
1513 P(d, "type", NS"QObject");
1514 P(d, "displayedtype", mo->className());
1515 P(d, "numchild", 4);
1516 if (d.dumpChildren) {
1517 const QObjectList &children = ob->children();
1519 int signalCount = 0;
1520 for (int i = mo->methodCount(); --i >= 0; ) {
1521 QMetaMethod::MethodType mt = mo->method(i).methodType();
1522 signalCount += (mt == QMetaMethod::Signal);
1523 slotCount += (mt == QMetaMethod::Slot);
1527 P(d, "name", "properties");
1528 // FIXME: Note that when simply using '(QObject*)'
1529 // in the cast below, Gdb/MI _sometimes_ misparses
1530 // expressions further down in the tree.
1531 P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
1532 P(d, "type", NS"QObjectPropertyList");
1533 P(d, "value", "<" << mo->propertyCount() << " items>");
1534 P(d, "numchild", mo->propertyCount());
1538 P(d, "name", "methods");
1539 P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
1540 P(d, "value", "<" << mo->methodCount() << " items>");
1541 P(d, "numchild", mo->methodCount());
1546 P(d, "name", "senders");
1547 P(d, "exp", "(*(class '"NS"QObjectPrivate'*)" << dfunc(ob) << ")->senders");
1548 P(d, "type", NS"QList<"NS"QObjectPrivateSender>");
1551 #if PRIVATE_OBJECT_ALLOWED
1553 P(d, "name", "signals");
1554 P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
1555 P(d, "type", NS"QObjectSignalList");
1556 P(d, "value", "<" << signalCount << " items>");
1557 P(d, "numchild", signalCount);
1560 P(d, "name", "slots");
1561 P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
1562 P(d, "type", NS"QObjectSlotList");
1563 P(d, "value", "<" << slotCount << " items>");
1564 P(d, "numchild", slotCount);
1568 P(d, "name", "children");
1569 // works always, but causes additional traffic on the list
1570 //P(d, "exp", "((class '"NS"QObject'*)" << d.data << ")->children()");
1572 //P(d, "addr", addOffset(dfunc(ob), childrenOffset));
1573 //P(d, "type", NS"QList<QObject *>");
1574 //P(d, "value", "<" << children.size() << " items>");
1575 qDumpInnerValue(d, NS"QList<"NS"QObject *>",
1576 addOffset(dfunc(ob), childrenOffset));
1577 P(d, "numchild", children.size());
1580 // Unneeded (and not working): Connections are listes as childen
1581 // of the signal or slot they are connected to.
1583 // P(d, "name", "connections");
1584 // P(d, "exp", "*(*(class "NS"QObjectPrivate*)" << dfunc(ob) << ")->connectionLists");
1585 // P(d, "type", NS"QVector<"NS"QList<"NS"QObjectPrivate::Connection> >");
1590 P(d, "name", "objectprivate");
1591 P(d, "type", NS"QObjectPrivate");
1592 P(d, "addr", dfunc(ob));
1594 P(d, "numchild", "1");
1598 P(d, "name", "parent");
1599 qDumpInnerValueHelper(d, NS"QObject *", ob->parent());
1603 P(d, "name", "className");
1604 P(d, "value",ob->metaObject()->className());
1606 P(d, "numchild", "0");
1614 static void qDumpQObjectPropertyList(QDumper &d)
1616 const QObject *ob = (const QObject *)d.data;
1617 const QMetaObject *mo = ob->metaObject();
1618 P(d, "addr", "<synthetic>");
1619 P(d, "type", NS"QObjectPropertyList");
1620 P(d, "numchild", mo->propertyCount());
1621 if (d.dumpChildren) {
1623 for (int i = mo->propertyCount(); --i >= 0; ) {
1624 const QMetaProperty & prop = mo->property(i);
1626 P(d, "name", prop.name());
1627 P(d, "exp", "((" << mo->className() << "*)" << ob
1628 << ")->" << prop.name() << "()");
1629 if (isEqual(prop.typeName(), "QString")) {
1630 P(d, "value", prop.read(ob).toString());
1631 P(d, "valueencoded", "1");
1632 P(d, "type", NS"QString");
1633 P(d, "numchild", "0");
1634 } else if (isEqual(prop.typeName(), "bool")) {
1635 P(d, "value", (prop.read(ob).toBool() ? "true" : "false"));
1636 P(d, "numchild", "0");
1637 } else if (isEqual(prop.typeName(), "int")) {
1638 P(d, "value", prop.read(ob).toInt());
1639 P(d, "numchild", "0");
1641 P(d, "type", prop.typeName());
1642 P(d, "numchild", "1");
1650 static void qDumpQObjectMethodList(QDumper &d)
1652 const QObject *ob = (const QObject *)d.data;
1653 const QMetaObject *mo = ob->metaObject();
1654 P(d, "addr", "<synthetic>");
1655 P(d, "type", NS"QObjectMethodList");
1656 P(d, "numchild", mo->methodCount());
1657 P(d, "childtype", "QMetaMethod::Method");
1658 P(d, "childnumchild", "0");
1659 if (d.dumpChildren) {
1661 for (int i = 0; i != mo->methodCount(); ++i) {
1662 const QMetaMethod & method = mo->method(i);
1663 int mt = method.methodType();
1665 P(d, "name", i << " " << mo->indexOfMethod(method.signature())
1666 << " " << method.signature());
1667 P(d, "value", (mt == QMetaMethod::Signal ? "<Signal>" : "<Slot>") << " (" << mt << ")");
1675 #if PRIVATE_OBJECT_ALLOWED
1676 const char * qConnectionTypes[] ={
1684 #if QT_VERSION >= 0x040400
1685 static const QObjectPrivate::ConnectionList &qConnectionList(const QObject *ob, int signalNumber)
1687 static const QObjectPrivate::ConnectionList emptyList;
1688 const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
1689 if (!p->connectionLists)
1691 typedef QVector<QObjectPrivate::ConnectionList> ConnLists;
1692 const ConnLists *lists = reinterpret_cast<const ConnLists *>(p->connectionLists);
1693 // there's an optimization making the lists only large enough to hold the
1694 // last non-empty item
1695 if (signalNumber >= lists->size())
1697 return lists->at(signalNumber);
1701 static void qDumpQObjectSignal(QDumper &d)
1703 unsigned signalNumber = d.extraInt[0];
1705 P(d, "addr", "<synthetic>");
1706 P(d, "numchild", "1");
1707 P(d, "type", NS"QObjectSignal");
1709 #if QT_VERSION >= 0x040400
1710 if (d.dumpChildren) {
1711 const QObject *ob = reinterpret_cast<const QObject *>(d.data);
1713 const QObjectPrivate::ConnectionList &connList = qConnectionList(ob, signalNumber);
1714 for (int i = 0; i != connList.size(); ++i) {
1715 const QObjectPrivate::Connection &conn = connList.at(i);
1717 P(d, "name", i << " receiver");
1718 qDumpInnerValueHelper(d, NS"QObject *", conn.receiver);
1721 P(d, "name", i << " slot");
1724 P(d, "value", conn.receiver->metaObject()->method(conn.method).signature());
1726 P(d, "value", "<invalid receiver>");
1727 P(d, "numchild", "0");
1730 P(d, "name", i << " type");
1732 P(d, "value", "<" << qConnectionTypes[conn.method] << " connection>");
1733 P(d, "numchild", "0");
1737 P(d, "numchild", connList.size());
1743 static void qDumpQObjectSignalList(QDumper &d)
1745 const QObject *ob = reinterpret_cast<const QObject *>(d.data);
1746 const QMetaObject *mo = ob->metaObject();
1748 for (int i = mo->methodCount(); --i >= 0; )
1749 count += (mo->method(i).methodType() == QMetaMethod::Signal);
1750 P(d, "addr", d.data);
1751 P(d, "numchild", count);
1752 #if QT_VERSION >= 0x040400
1753 if (d.dumpChildren) {
1755 for (int i = 0; i != mo->methodCount(); ++i) {
1756 const QMetaMethod & method = mo->method(i);
1757 if (method.methodType() == QMetaMethod::Signal) {
1758 int k = mo->indexOfSignal(method.signature());
1759 const QObjectPrivate::ConnectionList &connList = qConnectionList(ob, k);
1762 P(d, "value", method.signature());
1763 P(d, "numchild", connList.size());
1764 //P(d, "numchild", "1");
1765 P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
1766 P(d, "type", NS"QObjectSignal");
1776 static void qDumpQObjectSlot(QDumper &d)
1778 int slotNumber = d.extraInt[0];
1780 P(d, "addr", d.data);
1781 P(d, "numchild", "1");
1782 P(d, "type", NS"QObjectSlot");
1784 #if QT_VERSION >= 0x040400
1785 if (d.dumpChildren) {
1788 const QObject *ob = reinterpret_cast<const QObject *>(d.data);
1789 const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
1790 for (int s = 0; s != p->senders.size(); ++s) {
1791 const QObjectPrivate::Sender &sender = p->senders.at(s);
1792 const QObjectPrivate::ConnectionList &connList
1793 = qConnectionList(sender.sender, sender.signal);
1794 for (int i = 0; i != connList.size(); ++i) {
1795 const QObjectPrivate::Connection &conn = connList.at(i);
1796 if (conn.receiver == ob && conn.method == slotNumber) {
1798 const QMetaMethod & method =
1799 sender.sender->metaObject()->method(sender.signal);
1801 P(d, "name", s << " sender");
1802 qDumpInnerValueHelper(d, NS"QObject *", sender.sender);
1805 P(d, "name", s << " signal");
1807 P(d, "value", method.signature());
1808 P(d, "numchild", "0");
1811 P(d, "name", s << " type");
1813 P(d, "value", "<" << qConnectionTypes[conn.method] << " connection>");
1814 P(d, "numchild", "0");
1820 P(d, "numchild", numchild);
1826 static void qDumpQObjectSlotList(QDumper &d)
1828 const QObject *ob = reinterpret_cast<const QObject *>(d.data);
1829 #if QT_VERSION >= 0x040400
1830 const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
1832 const QMetaObject *mo = ob->metaObject();
1835 for (int i = mo->methodCount(); --i >= 0; )
1836 count += (mo->method(i).methodType() == QMetaMethod::Slot);
1838 P(d, "addr", d.data);
1839 P(d, "numchild", count);
1840 #if QT_VERSION >= 0x040400
1841 if (d.dumpChildren) {
1843 for (int i = 0; i != mo->methodCount(); ++i) {
1844 const QMetaMethod & method = mo->method(i);
1845 if (method.methodType() == QMetaMethod::Slot) {
1847 int k = mo->indexOfSlot(method.signature());
1849 P(d, "value", method.signature());
1851 // count senders. expensive...
1853 for (int s = 0; s != p->senders.size(); ++s) {
1854 const QObjectPrivate::Sender & sender = p->senders.at(s);
1855 const QObjectPrivate::ConnectionList &connList
1856 = qConnectionList(sender.sender, sender.signal);
1857 for (int c = 0; c != connList.size(); ++c) {
1858 const QObjectPrivate::Connection &conn = connList.at(c);
1859 if (conn.receiver == ob && conn.method == k)
1863 P(d, "numchild", numchild);
1864 P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
1865 P(d, "type", NS"QObjectSlot");
1874 #endif // PRIVATE_OBJECT_ALLOWED
1877 static void qDumpQPixmap(QDumper &d)
1880 const QPixmap &im = *reinterpret_cast<const QPixmap *>(d.data);
1881 P(d, "value", "(" << im.width() << "x" << im.height() << ")");
1882 P(d, "type", NS"QPixmap");
1883 P(d, "numchild", "0");
1890 static void qDumpQSet(QDumper &d)
1892 // This uses the knowledge that QHash<T> has only a single member
1893 // of union { QHashData *d; QHashNode<Key, T> *e; };
1894 QHashData *hd = *(QHashData**)d.data;
1895 QHashData::Node *node = hd->firstNode();
1902 qCheckPointer(node->next);
1905 P(d, "value", "<" << n << " items>");
1906 P(d, "valuedisabled", "true");
1907 P(d, "numchild", 2 * n);
1908 if (d.dumpChildren) {
1913 for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) {
1914 for (node = hd->buckets[bucket]; node->next; node = node->next) {
1917 P(d, "type", d.innertype);
1918 P(d, "exp", "(('"NS"QHashNode<" << d.innertype
1919 << ","NS"QHashDummyValue>'*)"
1920 << static_cast<const void*>(node) << ")->key"
1935 static void qDumpQString(QDumper &d)
1937 const QString &str = *reinterpret_cast<const QString *>(d.data);
1939 if (!str.isEmpty()) {
1940 qCheckAccess(str.unicode());
1941 qCheckAccess(str.unicode() + str.size());
1945 P(d, "valueencoded", "1");
1946 P(d, "type", NS"QString");
1947 //P(d, "editvalue", str); // handled generically below
1948 P(d, "numchild", "0");
1953 static void qDumpQStringList(QDumper &d)
1955 const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
1956 int n = list.size();
1960 qCheckAccess(&list.front());
1961 qCheckAccess(&list.back());
1964 P(d, "value", "<" << n << " items>");
1965 P(d, "valuedisabled", "true");
1966 P(d, "numchild", n);
1967 P(d, "childtype", NS"QString");
1968 P(d, "childnumchild", "0");
1969 if (d.dumpChildren) {
1973 for (int i = 0; i != n; ++i) {
1976 P(d, "value", list[i]);
1977 P(d, "valueencoded", "1");
1980 if (n < list.size())
1987 static void qDumpQTextCodec(QDumper &d)
1989 const QTextCodec &codec = *reinterpret_cast<const QTextCodec *>(d.data);
1990 P(d, "value", codec.name());
1991 P(d, "valueencoded", "1");
1992 P(d, "type", NS"QTextCodec");
1993 P(d, "numchild", "2");
1994 if (d.dumpChildren) {
1996 S(d, "name", codec.name());
1997 I(d, "mibEnum", codec.mibEnum());
2003 static void qDumpQVariantHelper(const void *data, QString *value,
2004 QString *exp, int *numchild)
2006 const QVariant &v = *reinterpret_cast<const QVariant *>(data);
2008 case QVariant::Invalid:
2009 *value = QLatin1String("<invalid>");
2012 case QVariant::String:
2013 *value = QLatin1Char('"') + v.toString() + QLatin1Char('"');
2016 case QVariant::StringList:
2017 *exp = QString(QLatin1String("((QVariant*)%1)->d.data.c"))
2018 .arg((quintptr)data);
2019 *numchild = v.toStringList().size();
2022 *value = QString::number(v.toInt());
2025 case QVariant::Double:
2026 *value = QString::number(v.toDouble());
2031 const char *format = (v.typeName()[0] == 'Q')
2032 ? "'"NS"%s "NS"qVariantValue<"NS"%s >'(*('"NS"QVariant'*)%p)"
2033 : "'%s "NS"qVariantValue<%s >'(*('"NS"QVariant'*)%p)";
2034 qsnprintf(buf, sizeof(buf) - 1, format, v.typeName(), v.typeName(), data);
2035 *exp = QLatin1String(buf);
2042 static void qDumpQVariant(QDumper &d)
2044 const QVariant &v = *reinterpret_cast<const QVariant *>(d.data);
2048 qDumpQVariantHelper(d.data, &value, &exp, &numchild);
2049 bool isInvalid = (v.typeName() == 0);
2051 P(d, "value", "(invalid)");
2052 } else if (value.isEmpty()) {
2053 P(d, "value", "(" << v.typeName() << ") " << qPrintable(value));
2059 ba += qPrintable(value);
2061 P(d, "valueencoded", "1");
2063 P(d, "type", NS"QVariant");
2064 P(d, "numchild", (isInvalid ? "0" : "1"));
2065 if (d.dumpChildren) {
2068 P(d, "name", "value");
2070 P(d, "exp", qPrintable(exp));
2071 if (!value.isEmpty()) {
2072 P(d, "value", value);
2073 P(d, "valueencoded", "1");
2075 P(d, "type", v.typeName());
2076 P(d, "numchild", numchild);
2083 static void qDumpQVector(QDumper &d)
2085 QVectorData *v = *reinterpret_cast<QVectorData *const*>(d.data);
2087 // Try to provoke segfaults early to prevent the frontend
2088 // from asking for unavailable child details
2093 //qCheckAccess(&vec.front());
2094 //qCheckAccess(&vec.back());
2097 unsigned innersize = d.extraInt[0];
2098 unsigned typeddatasize = d.extraInt[1];
2101 P(d, "value", "<" << n << " items>");
2102 P(d, "valuedisabled", "true");
2103 P(d, "numchild", n);
2104 if (d.dumpChildren) {
2105 QByteArray strippedInnerType = stripPointerType(d.innertype);
2106 const char *stripped =
2107 isPointerType(d.innertype) ? strippedInnerType.data() : 0;
2111 for (int i = 0; i != n; ++i) {
2114 qDumpInnerValueOrPointer(d, d.innertype, stripped,
2115 addOffset(v, i * innersize + typeddatasize));
2125 static void qDumpStdList(QDumper &d)
2127 const std::list<int> &list = *reinterpret_cast<const std::list<int> *>(d.data);
2128 const void *p = d.data;
2134 p = deref(addOffset(d.data, sizeof(void*)));
2136 p = deref(addOffset(p, sizeof(void*)));
2138 p = deref(addOffset(p, sizeof(void*)));
2142 std::list<int>::const_iterator it = list.begin();
2143 for (; nn < 101 && it != list.end(); ++nn, ++it)
2144 qCheckAccess(it.operator->());
2147 P(d, "value", "<more than 100 items>");
2149 P(d, "value", "<" << nn << " items>");
2150 P(d, "numchild", nn);
2152 P(d, "valuedisabled", "true");
2153 if (d.dumpChildren) {
2154 QByteArray strippedInnerType = stripPointerType(d.innertype);
2155 const char *stripped =
2156 isPointerType(d.innertype) ? strippedInnerType.data() : 0;
2159 for (int i = 0; i < 1000 && it != list.end(); ++i, ++it) {
2162 qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->());
2165 if (it != list.end())
2172 static void qDumpStdMap(QDumper &d)
2174 typedef std::map<int, int> DummyType;
2175 const DummyType &map = *reinterpret_cast<const DummyType*>(d.data);
2176 const char *keyType = d.templateParameters[0];
2177 const char *valueType = d.templateParameters[1];
2178 const void *p = d.data;
2182 int nn = map.size();
2184 DummyType::const_iterator it = map.begin();
2185 for (int i = 0; i < nn && i < 10 && it != map.end(); ++i, ++it)
2186 qCheckAccess(it.operator->());
2188 QByteArray strippedInnerType = stripPointerType(d.innertype);
2189 P(d, "numchild", nn);
2190 P(d, "value", "<" << nn << " items>");
2191 P(d, "valuedisabled", "true");
2192 P(d, "valueoffset", d.extraInt[2]);
2194 // HACK: we need a properly const qualified version of the
2195 // std::pair used. We extract it from the allocator parameter
2196 // (#4, "std::allocator<std::pair<key, value> >")
2197 // as it is there, and, equally importantly, in an order that
2198 // gdb accepts when fed with it.
2199 char *pairType = (char *)(d.templateParameters[3]) + 15;
2200 pairType[strlen(pairType) - 2] = 0;
2201 P(d, "pairtype", pairType);
2203 if (d.dumpChildren) {
2204 bool isSimpleKey = isSimpleType(keyType);
2205 bool isSimpleValue = isSimpleType(valueType);
2206 int valueOffset = d.extraInt[2];
2208 P(d, "extra", "isSimpleKey: " << isSimpleKey
2209 << " isSimpleValue: " << isSimpleValue
2210 << " valueType: '" << valueType
2211 << " valueOffset: " << valueOffset);
2215 for (int i = 0; i < 1000 && it != map.end(); ++i, ++it) {
2217 const void *node = it.operator->();
2219 qDumpInnerValueHelper(d, keyType, node, "key");
2220 qDumpInnerValueHelper(d, valueType, addOffset(node, valueOffset));
2221 if (isSimpleKey && isSimpleValue) {
2222 P(d, "type", valueType);
2223 P(d, "addr", addOffset(node, valueOffset));
2224 P(d, "numchild", 0);
2227 P(d, "type", pairType);
2228 P(d, "numchild", 2);
2232 if (it != map.end())
2239 static void qDumpStdString(QDumper &d)
2241 const std::string &str = *reinterpret_cast<const std::string *>(d.data);
2244 qCheckAccess(str.c_str());
2245 qCheckAccess(str.c_str() + str.size() - 1);
2249 d.putBase64Encoded(str.c_str(), str.size());
2251 P(d, "valueencoded", "1");
2252 P(d, "type", "std::string");
2253 P(d, "numchild", "0");
2258 static void qDumpStdWString(QDumper &d)
2260 const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data);
2263 qCheckAccess(str.c_str());
2264 qCheckAccess(str.c_str() + str.size() - 1);
2268 d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t));
2270 P(d, "valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3"));
2271 P(d, "type", "std::wstring");
2272 P(d, "numchild", "0");
2277 static void qDumpStdVector(QDumper &d)
2279 // Correct type would be something like:
2280 // std::_Vector_base<int,std::allocator<int, std::allocator<int> >>::_Vector_impl
2284 char *end_of_storage;
2286 const VectorImpl *v = static_cast<const VectorImpl *>(d.data);
2288 // Try to provoke segfaults early to prevent the frontend
2289 // from asking for unavailable child details
2290 int nn = (v->finish - v->start) / d.extraInt[0];
2294 qCheckAccess(v->start);
2295 qCheckAccess(v->finish);
2296 qCheckAccess(v->end_of_storage);
2300 P(d, "value", "<" << n << " items>");
2301 P(d, "valuedisabled", "true");
2302 P(d, "numchild", n);
2303 if (d.dumpChildren) {
2304 unsigned innersize = d.extraInt[0];
2305 QByteArray strippedInnerType = stripPointerType(d.innertype);
2306 const char *stripped =
2307 isPointerType(d.innertype) ? strippedInnerType.data() : 0;
2311 for (int i = 0; i != n; ++i) {
2314 qDumpInnerValueOrPointer(d, d.innertype, stripped,
2315 addOffset(v->start, i * innersize));
2325 static void qDumpStdVectorBool(QDumper &d)
2328 return qDumpStdVector(d);
2331 static void handleProtocolVersion2and3(QDumper & d)
2333 if (!d.outertype[0]) {
2338 d.setupTemplateParameters();
2339 P(d, "iname", d.iname);
2340 P(d, "addr", d.data);
2342 #ifdef QT_NO_QDATASTREAM
2343 if (d.protocolVersion == 3) {
2344 QVariant::Type type = QVariant::nameToType(d.outertype);
2345 if (type != QVariant::Invalid) {
2346 QVariant v(type, d.data);
2348 QDataStream ds(&ba, QIODevice::WriteOnly);
2350 P(d, "editvalue", ba);
2355 const char *type = stripNamespace(d.outertype);
2356 // type[0] is usally 'Q', so don't use it
2359 if (isEqual(type, "QByteArray"))
2363 if (isEqual(type, "QDateTime"))
2365 else if (isEqual(type, "QDir"))
2369 if (isEqual(type, "QFile"))
2371 else if (isEqual(type, "QFileInfo"))
2375 if (isEqual(type, "QHash"))
2377 else if (isEqual(type, "QHashNode"))
2381 if (isEqual(type, "QImage"))
2385 if (isEqual(type, "QList"))
2387 else if (isEqual(type, "QLinkedList"))
2388 qDumpQLinkedList(d);
2389 else if (isEqual(type, "QLocale"))
2393 if (isEqual(type, "QMap"))
2395 else if (isEqual(type, "QMapNode"))
2397 else if (isEqual(type, "QModelIndex"))
2398 qDumpQModelIndex(d);
2399 else if (isEqual(type, "QMultiMap"))
2403 if (isEqual(type, "QObject"))
2405 else if (isEqual(type, "QObjectPropertyList"))
2406 qDumpQObjectPropertyList(d);
2407 else if (isEqual(type, "QObjectMethodList"))
2408 qDumpQObjectMethodList(d);
2409 #if PRIVATE_OBJECT_ALLOWED
2410 else if (isEqual(type, "QObjectSignal"))
2411 qDumpQObjectSignal(d);
2412 else if (isEqual(type, "QObjectSignalList"))
2413 qDumpQObjectSignalList(d);
2414 else if (isEqual(type, "QObjectSlot"))
2415 qDumpQObjectSlot(d);
2416 else if (isEqual(type, "QObjectSlotList"))
2417 qDumpQObjectSlotList(d);
2421 if (isEqual(type, "QPixmap"))
2425 if (isEqual(type, "QSet"))
2427 else if (isEqual(type, "QString"))
2429 else if (isEqual(type, "QStringList"))
2430 qDumpQStringList(d);
2433 if (isEqual(type, "QTextCodec"))
2437 if (isEqual(type, "QVariant"))
2439 else if (isEqual(type, "QVector"))
2443 if (isEqual(type, "wstring"))
2447 if (isEqual(type, "std::vector"))
2449 else if (isEqual(type, "std::vector::bool"))
2450 qDumpStdVectorBool(d);
2451 else if (isEqual(type, "std::list"))
2453 else if (isEqual(type, "std::map"))
2455 else if (isEqual(type, "std::string") || isEqual(type, "string"))
2457 else if (isEqual(type, "std::wstring"))
2466 } // anonymous namespace
2469 extern "C" Q_DECL_EXPORT
2470 void qDumpObjectData440(
2471 int protocolVersion,
2481 if (protocolVersion == 1) {
2483 d.protocolVersion = protocolVersion;
2486 // This is a list of all available dumpers. Note that some templates
2487 // currently require special hardcoded handling in the debugger plugin.
2488 // They are mentioned here nevertheless. For types that not listed
2489 // here, dumpers won't be used.
2491 "\""NS"QByteArray\","
2492 "\""NS"QDateTime\","
2495 "\""NS"QFileInfo\","
2497 "\""NS"QHashNode\","
2499 "\""NS"QLinkedList\","
2504 "\""NS"QModelIndex\","
2505 #if QT_VERSION >= 0x040500
2506 "\""NS"QMultiMap\","
2509 "\""NS"QObjectMethodList\"," // hack to get nested properties display
2510 "\""NS"QObjectPropertyList\","
2511 #if PRIVATE_OBJECT_ALLOWED
2512 "\""NS"QObjectSignal\","
2513 "\""NS"QObjectSignalList\","
2514 "\""NS"QObjectSlot\","
2515 "\""NS"QObjectSlotList\","
2516 #endif // PRIVATE_OBJECT_ALLOWED
2517 // << "\""NS"QRegion\","
2520 "\""NS"QStringList\","
2521 "\""NS"QTextCodec\","
2527 "\"std::basic_string\","
2535 "\"" << ((QT_VERSION >> 16) & 255) << "\","
2536 "\"" << ((QT_VERSION >> 8) & 255) << "\","
2537 "\"" << ((QT_VERSION) & 255) << "\"]";
2538 d << ",namespace=\""NS"\"";
2542 else if (protocolVersion == 2 || protocolVersion == 3) {
2545 d.protocolVersion = protocolVersion;
2548 d.dumpChildren = dumpChildren;
2549 d.extraInt[0] = extraInt0;
2550 d.extraInt[1] = extraInt1;
2551 d.extraInt[2] = extraInt2;
2552 d.extraInt[3] = extraInt3;
2554 const char *inbuffer = qDumpInBuffer;
2555 d.outertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
2556 d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
2557 d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
2558 d.innertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
2559 d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer;
2561 handleProtocolVersion2and3(d);
2565 qDebug() << "Unsupported protocol version" << protocolVersion;