tpsession initial import
[tpsession] / tpsession-0.1 / tests / smstest / qtc-gdbmacros / gdbmacros.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact:  Qt Software Information (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
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.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at qt-sales@nokia.com.
27 **
28 **************************************************************************/
29
30 #include <qglobal.h>
31
32 // this relies on contents copied from qobject_p.h
33 #define PRIVATE_OBJECT_ALLOWED 1
34
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>
52
53 int qtGhVersion = QT_VERSION;
54
55 #ifdef QT_GUI_LIB
56 #   include <QtGui/QPixmap>
57 #   include <QtGui/QImage>
58 #endif
59
60 #include <list>
61 #include <map>
62 #include <string>
63 #include <vector>
64
65 #include <ctype.h>
66 #include <stdio.h>
67 #include <unistd.h>
68
69 /*!
70   \class QDumper
71   \brief Helper class for producing "nice" output in Qt Creator's debugger.
72
73   \internal
74
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.
78
79   Some hints:
80
81   New dumpers for non-templated classes should be mentioned in
82   \c{qDumpObjectData440()} in the  \c{protocolVersion == 1} branch.
83
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()}.
87
88   In any case, dumper processesing should end up in 
89   \c{handleProtocolVersion2and3()} and needs an entry in the bis switch there.
90
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:
93
94
95   \c{
96     const Foo &foo = *reinterpret_cast<const Foo *>(d.data);
97
98     P(d, "value", ...);
99     P(d, "type", "Foo");
100     P(d, "numchild", "0");
101   }
102
103
104   'P(d, name, value)' roughly expands to:
105         d << (name) << "=\"" << value << "\"";
106
107   Useful (i.e. understood by the IDE) names include:
108
109   \list
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.
119   \endlist
120
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
123
124   \c{
125     if (d.dumpChildren) {
126         d << ",children=[";
127    }
128
129   */
130
131 #undef NS
132 #ifdef QT_NAMESPACE
133 #   define STRINGIFY0(s) #s
134 #   define STRINGIFY1(s) STRINGIFY0(s)
135 #   define NS STRINGIFY1(QT_NAMESPACE) "::"
136 #   define NSX "'" STRINGIFY1(QT_NAMESPACE) "::"
137 #   define NSY "'"
138 #else
139 #   define NS ""
140 #   define NSX ""
141 #   define NSY ""
142 #endif
143
144
145 #if PRIVATE_OBJECT_ALLOWED
146
147 #if defined(QT_BEGIN_NAMESPACE)
148 QT_BEGIN_NAMESPACE
149 #endif
150
151 class QVariant;
152 class QThreadData;
153 class QObjectConnectionListVector;
154
155 class QObjectPrivate : public QObjectData
156 {
157     Q_DECLARE_PUBLIC(QObject)
158
159 public:
160     QObjectPrivate() {}
161     virtual ~QObjectPrivate() {}
162
163     // preserve binary compatibility with code compiled without Qt 3 support
164     QList<QObject *> pendingChildInsertedEvents; // unused
165
166     // id of the thread that owns the object
167     QThreadData *threadData;
168
169     struct Sender
170     {
171         QObject *sender;
172         int signal;
173         int ref;
174     };
175
176     Sender *currentSender; // object currently activating the object
177     QObject *currentChildBeingDeleted;
178
179     QList<QPointer<QObject> > eventFilters;
180
181     struct ExtraData;
182     ExtraData *extraData;
183     mutable quint32 connectedSignals;
184
185     QString objectName;
186
187     struct Connection
188     {
189         QObject *receiver;
190         int method;
191         uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
192         QBasicAtomicPointer<int> argumentTypes;
193     };
194     typedef QList<Connection> ConnectionList;
195
196     QObjectConnectionListVector *connectionLists;
197     QList<Sender> senders;
198     int *deleteWatch;
199 };
200
201 #if defined(QT_BEGIN_NAMESPACE)
202 QT_END_NAMESPACE
203 #endif
204
205 #endif // PRIVATE_OBJECT_ALLOWED
206
207
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];
213
214 namespace {
215
216 static bool isPointerType(const QByteArray &type)
217 {
218     return type.endsWith("*") || type.endsWith("* const");
219 }
220
221 static QByteArray stripPointerType(QByteArray type)
222 {
223     if (type.endsWith("*"))
224         type.chop(1);
225     if (type.endsWith("* const"))
226         type.chop(7);
227     if (type.endsWith(' '))
228         type.chop(1);
229     return type;
230 }
231
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
237 // below.
238
239 volatile int qProvokeSegFaultHelper;
240
241 static const void *addOffset(const void *p, int offset)
242 {
243     return offset + reinterpret_cast<const char *>(p);
244 }
245
246 static const void *skipvtable(const void *p)
247 {
248     return sizeof(void*) + reinterpret_cast<const char *>(p);
249 }
250
251 static const void *deref(const void *p)
252 {
253     return *reinterpret_cast<const char* const*>(p);
254 }
255
256 static const void *dfunc(const void *p)
257 {
258     return deref(skipvtable(p));
259 }
260
261 static bool isEqual(const char *s, const char *t)
262 {
263     return qstrcmp(s, t) == 0;
264 }
265
266 static bool startsWith(const char *s, const char *t)
267 {
268     return qstrncmp(s, t, strlen(t)) == 0;
269 }
270
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)
276
277 const char *stripNamespace(const char *type)
278 {
279     static const size_t nslen = strlen(NS);
280     return startsWith(type, NS) ? type + nslen : type;
281 }
282
283 static bool isSimpleType(const char *type)
284 {
285     switch (type[0]) {
286         case 'c':
287             return isEqual(type, "char");
288         case 'd':
289             return isEqual(type, "double");
290         case 'f':
291             return isEqual(type, "float");
292         case 'i':
293             return isEqual(type, "int");
294         case 'l':
295             return isEqual(type, "long") || startsWith(type, "long ");
296         case 's':
297             return isEqual(type, "short") || isEqual(type, "signed")
298                 || startsWith(type, "signed ");
299         case 'u':
300             return isEqual(type, "unsigned") || startsWith(type, "unsigned ");
301     }
302     return false;
303 }
304
305 #if 0
306 static bool isStringType(const char *type)
307 {
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");
313 }
314 #endif
315
316 static bool isMovableType(const char *type)
317 {
318     if (isPointerType(type))
319         return true;
320
321     if (isSimpleType(type))
322         return true;
323
324     type = stripNamespace(type);
325
326     switch (type[1]) {  
327         case 'B':
328             return isEqual(type, "QBrush")
329                 || isEqual(type, "QBitArray")
330                 || isEqual(type, "QByteArray") ;
331         case 'C':
332             return isEqual(type, "QCustomTypeInfo");
333         case 'D':
334             return isEqual(type, "QDate")
335                 || isEqual(type, "QDateTime");
336         case 'F':
337             return isEqual(type, "QFileInfo")
338                 || isEqual(type, "QFixed")
339                 || isEqual(type, "QFixedPoint")
340                 || isEqual(type, "QFixedSize");
341         case 'H':
342             return isEqual(type, "QHashDummyValue");
343         case 'I':
344             return isEqual(type, "QIcon")
345                 || isEqual(type, "QImage");
346         case 'L':
347             return isEqual(type, "QLine")
348                 || isEqual(type, "QLineF")
349                 || isEqual(type, "QLocal");
350         case 'M':
351             return isEqual(type, "QMatrix")
352                 || isEqual(type, "QModelIndex");
353         case 'P':
354             return isEqual(type, "QPoint")
355                 || isEqual(type, "QPointF")
356                 || isEqual(type, "QPen")
357                 || isEqual(type, "QPersistentModelIndex");
358         case 'R':
359             return isEqual(type, "QResourceRoot")
360                 || isEqual(type, "QRect")
361                 || isEqual(type, "QRectF")
362                 || isEqual(type, "QRegExp");
363         case 'S':
364             return isEqual(type, "QSize")
365                 || isEqual(type, "QSizeF")
366                 || isEqual(type, "QString");
367         case 'T':
368             return isEqual(type, "QTime")
369                 || isEqual(type, "QTextBlock");
370         case 'U':
371             return isEqual(type, "QUrl");
372         case 'V':
373             return isEqual(type, "QVariant");
374         case 'X':
375             return isEqual(type, "QXmlStreamAttribute")
376                 || isEqual(type, "QXmlStreamNamespaceDeclaration")
377                 || isEqual(type, "QXmlStreamNotationDeclaration")
378                 || isEqual(type, "QXmlStreamEntityDeclaration");
379     }
380     return false;
381 }
382
383 struct QDumper
384 {
385     explicit QDumper();
386     ~QDumper();
387     void checkFill();
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);
399     void put(char c);
400     void addCommaIfNeeded();
401     void putBase64Encoded(const char *buf, int n);
402     void putEllipsis();
403     void disarm();
404
405     void beginHash(); // start of data hash output
406     void endHash(); // start of data hash output
407
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?
417
418     // handling of nested templates
419     void setupTemplateParameters();
420     enum { maxTemplateParameters = 10 };
421     const char *templateParameters[maxTemplateParameters + 1];
422     int templateParametersCount;
423
424     // internal state
425     bool success;          // are we finished?
426     bool full;
427     int pos;
428
429     int extraInt[4];
430 };
431
432
433 QDumper::QDumper()
434 {
435     success = false;
436     full = false;
437     qDumpOutBuffer[0] = 'f'; // marks output as 'wrong' 
438     pos = 1;
439 }
440
441 QDumper::~QDumper()
442 {
443     qDumpOutBuffer[pos++] = '\0';
444     if (success)
445         qDumpOutBuffer[0] = (full ? '+' : 't');
446 }
447
448 void QDumper::setupTemplateParameters()
449 {
450     char *s = const_cast<char *>(innertype);
451
452     templateParametersCount = 1;
453     templateParameters[0] = s;
454     for (int i = 1; i != maxTemplateParameters + 1; ++i)
455         templateParameters[i] = 0;
456
457     while (*s) {
458         while (*s && *s != '@')
459             ++s;
460         if (*s) {
461             *s = '\0';
462             ++s;
463             templateParameters[templateParametersCount++] = s;
464         }
465     }
466 }
467
468 QDumper &QDumper::operator<<(unsigned long long c)
469 {
470     checkFill();
471     pos += sprintf(qDumpOutBuffer + pos, "%llu", c);
472     return *this;
473 }
474
475 QDumper &QDumper::operator<<(unsigned long c)
476 {
477     checkFill();
478     pos += sprintf(qDumpOutBuffer + pos, "%lu", c);
479     return *this;
480 }
481
482 QDumper &QDumper::operator<<(float d)
483 {
484     checkFill();
485     pos += sprintf(qDumpOutBuffer + pos, "%f", d);
486     return *this;
487 }
488
489 QDumper &QDumper::operator<<(double d)
490 {
491     checkFill();
492     pos += sprintf(qDumpOutBuffer + pos, "%f", d);
493     return *this;
494 }
495
496 QDumper &QDumper::operator<<(unsigned int i)
497 {
498     checkFill();
499     pos += sprintf(qDumpOutBuffer + pos, "%u", i);
500     return *this;
501 }
502
503 QDumper &QDumper::operator<<(long c)
504 {
505     checkFill();
506     pos += sprintf(qDumpOutBuffer + pos, "%ld", c);
507     return *this;
508 }
509
510 QDumper &QDumper::operator<<(int i)
511 {
512     checkFill();
513     pos += sprintf(qDumpOutBuffer + pos, "%d", i);
514     return *this;
515 }
516
517 QDumper &QDumper::operator<<(const void *p)
518 {
519     static char buf[100];
520     if (p) {
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.
524         if (buf[1] != 'x') {
525             put('0');
526             put('x');
527         }
528         *this << buf;
529     } else {
530         *this << "<null>";
531     }
532     return *this;
533 }
534
535 void QDumper::checkFill()
536 {
537     if (pos >= int(sizeof(qDumpOutBuffer)) - 100)
538         full = true;
539 }
540
541 void QDumper::put(char c)
542 {
543     checkFill();
544     if (!full)
545         qDumpOutBuffer[pos++] = c;
546 }
547
548 void QDumper::addCommaIfNeeded()
549 {
550     if (pos == 0)
551         return;
552     char c = qDumpOutBuffer[pos - 1];
553     if (c == '}' || c == '"' || c == ']')
554         put(',');
555 }
556
557 void QDumper::putBase64Encoded(const char *buf, int n)
558 {
559     const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
560                             "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
561     const char padchar = '=';
562     int padlen = 0;
563
564     //int tmpsize = ((n * 4) / 3) + 3;
565
566     int i = 0;
567     while (i < n) {
568         int chunk = 0;
569         chunk |= int(uchar(buf[i++])) << 16;
570         if (i == n) {
571             padlen = 2;
572         } else {
573             chunk |= int(uchar(buf[i++])) << 8;
574             if (i == n)
575                 padlen = 1;
576             else
577                 chunk |= int(uchar(buf[i++]));
578         }
579
580         int j = (chunk & 0x00fc0000) >> 18;
581         int k = (chunk & 0x0003f000) >> 12;
582         int l = (chunk & 0x00000fc0) >> 6;
583         int m = (chunk & 0x0000003f);
584         put(alphabet[j]);
585         put(alphabet[k]);
586         put(padlen > 1 ? padchar : alphabet[l]);
587         put(padlen > 0 ? padchar : alphabet[m]);
588     }
589 }
590
591 QDumper &QDumper::operator<<(const char *str)
592 {
593     if (!str)
594         return *this << "<null>";
595     while (*str)
596         put(*(str++));
597     return *this;
598 }
599
600 QDumper &QDumper::operator<<(const QByteArray &ba)
601 {
602     putBase64Encoded(ba.constData(), ba.size());
603     return *this;
604 }
605
606 QDumper &QDumper::operator<<(const QString &str)
607 {
608     QByteArray ba = str.toUtf8();
609     putBase64Encoded(ba.constData(), ba.size());
610     return *this;
611 }
612
613 void QDumper::disarm()
614 {
615     success = true;
616 }
617
618 void QDumper::beginHash()
619 {
620     addCommaIfNeeded();
621     put('{');
622 }
623
624 void QDumper::endHash()
625 {
626     put('}');
627 }
628
629 void QDumper::putEllipsis()
630 {
631     addCommaIfNeeded();
632     *this << "{name=\"<incomplete>\",value=\"\",type=\"" << innertype << "\"}";
633 }
634
635 //
636 // Some helpers to keep the dumper code short
637 //
638
639 // dump property=value pair
640 #undef P
641 #define P(dumper,name,value) \
642     do { \
643         dumper.addCommaIfNeeded(); \
644         dumper << (name) << "=\"" << value << "\""; \
645     } while (0)
646
647 // simple string property
648 #undef S
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"); \
656     dumper.endHash();
657
658 // simple integer property
659 #undef I
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"); \
666     dumper.endHash();
667
668 // simple boolean property
669 #undef BL
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"); \
676     dumper.endHash();
677
678
679 // a single QChar
680 #undef QC
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"); \
689     dumper.endHash();
690
691 #undef TT
692 #define TT(type, value) \
693     "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>"
694
695 static void qDumpUnknown(QDumper &d)
696 {
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");
702     d.disarm();
703 }
704
705 static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
706     const char *field = "value")
707 {
708     type = stripNamespace(type);
709     switch (type[1]) {
710         case 'l':
711             if (isEqual(type, "float"))
712                 P(d, field, *(float*)addr);
713             return;
714         case 'n':
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);
725             return;
726         case 'o':
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;
732                 }
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);
739             return;
740         case 'B':
741             if (isEqual(type, "QByteArray")) {
742                 d.addCommaIfNeeded();
743                 d << field << "encoded=\"1\",";
744                 P(d, field, *(QByteArray*)addr);
745             }
746             return;
747         case 'L':
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());
753             }
754             return;
755         case 'O':
756             if (isEqual(type, "QObject *")) {
757                 if (addr) {
758                     const QObject *ob = reinterpret_cast<const QObject *>(addr);
759                     P(d, "addr", ob);
760                     P(d, "value", ob->objectName());
761                     P(d, "valueencoded", "1");
762                     P(d, "type", NS"QObject");
763                     P(d, "displayedtype", ob->metaObject()->className());
764                 } else {
765                     P(d, "value", "0x0");
766                     P(d, "type", NS"QObject *");
767                 }
768             }
769             return;
770         case 'S':
771             if (isEqual(type, "QString")) {
772                 d.addCommaIfNeeded();
773                 d << field << "encoded=\"1\",";
774                 P(d, field, *(QString*)addr);
775             }
776             return;
777         default:
778             return;
779     }
780 }
781
782 static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
783 {
784     P(d, "addr", addr);
785     P(d, "type", type);
786
787     if (!type[0])
788         return;
789
790     qDumpInnerValueHelper(d, type, addr);
791 }
792
793
794 static void qDumpInnerValueOrPointer(QDumper &d,
795     const char *type, const char *strippedtype, const void *addr)
796 {
797     if (strippedtype) {
798         if (deref(addr)) {
799             P(d, "addr", deref(addr));
800             P(d, "type", strippedtype);
801             qDumpInnerValueHelper(d, strippedtype, deref(addr));
802         } else {
803             P(d, "addr", addr);
804             P(d, "type", strippedtype);
805             P(d, "value", "<null>");
806             P(d, "numchild", "0");
807         }
808     } else {
809         P(d, "addr", addr);
810         P(d, "type", type);
811         qDumpInnerValueHelper(d, type, addr);
812     }
813 }
814
815 //////////////////////////////////////////////////////////////////////////////
816
817 static void qDumpQByteArray(QDumper &d)
818 {
819     const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
820
821     if (!ba.isEmpty()) {
822         qCheckAccess(ba.constData());
823         qCheckAccess(ba.constData() + ba.size());
824     }
825
826     if (ba.size() <= 100)
827         P(d, "value", ba);
828     else
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) {
836         d << ",children=[";
837         char buf[20];
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);
842             d.beginHash();
843             P(d, "name", i);
844             P(d, "value", buf);
845             d.endHash();
846         }
847         d << "]";
848     }
849     d.disarm();
850 }
851
852 static void qDumpQDateTime(QDumper &d)
853 {
854 #ifdef QT_NO_DATESTRING
855     qDumpUnknown(d);
856 #else
857     const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data);
858     if (date.isNull()) {
859         P(d, "value", "(null)");
860     } else {
861         P(d, "value", date.toString());
862         P(d, "valueencoded", "1");
863     }
864     P(d, "type", NS"QDateTime");
865     P(d, "numchild", "3");
866     if (d.dumpChildren) {
867         d << ",children=[";
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());
875
876         #if 0
877         d.beginHash();
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");
883         d.endHash();
884         #endif
885
886         #if 0
887         d.beginHash();
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");
893         d.endHash();
894         #endif
895
896         d << "]";
897     }
898     d.disarm();
899 #endif // ifdef QT_NO_DATESTRING
900 }
901
902 static void qDumpQDir(QDumper &d)
903 {
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) {
910         d << ",children=[";
911         S(d, "absolutePath", dir.absolutePath());
912         S(d, "canonicalPath", dir.canonicalPath());
913         d << "]";
914     }
915     d.disarm();
916 }
917
918 static void qDumpQFile(QDumper &d)
919 {
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) {
926         d << ",children=[";
927         S(d, "fileName", file.fileName());
928         BL(d, "exists", file.exists());
929         d << "]";
930     }
931     d.disarm();
932 }
933
934 static void qDumpQFileInfo(QDumper &d)
935 {
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) {
942         d << ",children=[";
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());
950 #ifdef Q_OS_MACX
951         BL(d, "isBundle", info.isBundle());
952         S(d, "bundleName", info.bundleName());
953 #endif
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());
960
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());
965
966         //QDir absoluteDir () const
967         //QDir dir () const
968
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());
981
982         d.beginHash();
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");
989         d.endHash();
990
991         d.beginHash();
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");
998         d.endHash();
999
1000         d.beginHash();
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");
1007         d.endHash();
1008
1009         d << "]";
1010     }
1011     d.disarm();
1012 }
1013
1014 bool isOptimizedIntKey(const char *keyType)
1015 {
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")
1020 #endif
1021         || isEqual(keyType, "uint");
1022 }
1023
1024 int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned valueSize)
1025 {
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;
1034     // complex key
1035     struct NodeL  { void *next; uint h; void *k; void *v; } nodeL;
1036
1037     if (forKey) {
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))
1047             return nodeLk;
1048         return valueSize > sizeof(int) ? nodeNLk : nodeNSk;
1049     } else {
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))
1058             return nodeLv;
1059         return valueSize > sizeof(int) ? nodeNLv : nodeNSv;
1060     }
1061 }
1062
1063
1064 static void qDumpQHash(QDumper &d)
1065 {
1066     QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
1067     const char *keyType   = d.templateParameters[0];
1068     const char *valueType = d.templateParameters[1];
1069
1070     qCheckPointer(h->fakeNext);
1071     qCheckPointer(h->buckets);
1072
1073     unsigned keySize = d.extraInt[0];
1074     unsigned valueSize = d.extraInt[1];
1075
1076     int n = h->size;
1077
1078     if (n < 0)
1079         qCheck(false);
1080     if (n > 0) {
1081         qCheckPointer(h->fakeNext);
1082         qCheckPointer(*h->buckets);
1083     }
1084
1085     P(d, "value", "<" << n << " items>");
1086     P(d, "numchild", n);
1087     if (d.dumpChildren) {
1088         if (n > 1000)
1089             n = 1000;
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);
1095
1096         P(d, "extra", "isSimpleKey: " << isSimpleKey
1097             << " isSimpleValue: " << isSimpleValue
1098             << " valueType: '" << isSimpleValue
1099             << " keySize: " << keyOffset << " valueOffset: " << valueOffset
1100             << " opt: " << opt);
1101
1102         QHashData::Node *node = h->firstNode();
1103         QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h);
1104         int i = 0;
1105
1106         d << ",children=[";
1107         while (node != end) {
1108             d.beginHash();
1109                 P(d, "name", i);
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));
1115                 } else {
1116                     P(d, "exp", "*('"NS"QHashNode<" << keyType << ","
1117                         << valueType << " >'*)" << node);
1118                     P(d, "type", "'"NS"QHashNode<" << keyType << ","
1119                         << valueType << " >'");
1120                 }
1121             d.endHash();
1122             ++i;
1123             node = QHashData::nextNode(node);
1124         }
1125         d << "]";
1126     }
1127     d.disarm();
1128 }
1129
1130 static void qDumpQHashNode(QDumper &d)
1131 {
1132     const QHashData *h = reinterpret_cast<const QHashData *>(d.data);
1133     const char *keyType   = d.templateParameters[0];
1134     const char *valueType = d.templateParameters[1];
1135
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));
1143     else
1144         P(d, "value", "");
1145
1146     P(d, "numchild", 2);
1147     if (d.dumpChildren) {
1148         // there is a hash specialization in cast the key are integers or shorts
1149         d << ",children=[";
1150         d.beginHash();
1151             P(d, "name", "key");
1152             P(d, "type", keyType);
1153             P(d, "addr", addOffset(h, keyOffset));
1154         d.endHash();
1155         d.beginHash();
1156             P(d, "name", "value");
1157             P(d, "type", valueType);
1158             P(d, "addr", addOffset(h, valueOffset));
1159         d.endHash();
1160         d << "]";
1161     }
1162     d.disarm();
1163 }
1164
1165 static void qDumpQImage(QDumper &d)
1166 {
1167 #ifdef QT_GUI_LIB
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");
1172     d.disarm();
1173 #else
1174     Q_UNUSED(d);
1175 #endif
1176 }
1177
1178 static void qDumpQList(QDumper &d)
1179 {
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();
1186     if (nn < 0)
1187         qCheck(false);
1188     if (nn > 0) {
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)
1194             qCheck(false);
1195 #endif
1196     }
1197
1198     int n = nn;
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);
1207
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
1211         // in the frontend.
1212         // So as first approximation only do the 'isLarge' check:
1213         bool isInternal = innerSize <= int(sizeof(void*))
1214             && isMovableType(d.innertype);
1215
1216         P(d, "internal", (int)isInternal);
1217         P(d, "childtype", d.innertype);
1218         if (n > 1000)
1219             n = 1000;
1220         d << ",children=[";
1221         for (int i = 0; i != n; ++i) {
1222             d.beginHash();
1223             P(d, "name", i);
1224             if (innerTypeIsPointer) {
1225                 void *p = ldata.d->array + i + pdata->begin;
1226                 if (p) {
1227                     //P(d, "value","@" << p);
1228                     qDumpInnerValue(d, strippedInnerType.data(), deref(p));
1229                 } else {
1230                     P(d, "value", "<null>");
1231                     P(d, "numchild", "0");
1232                 }
1233             } else {
1234                 void *p = ldata.d->array + i + pdata->begin;
1235                 if (isInternal) {
1236                     //qDumpInnerValue(d, d.innertype, p);
1237                     P(d, "addr", p);
1238                     qDumpInnerValueHelper(d, d.innertype, p);
1239                 } else {
1240                     //qDumpInnerValue(d, d.innertype, deref(p));
1241                     P(d, "addr", deref(p));
1242                     qDumpInnerValueHelper(d, d.innertype, deref(p));
1243                 }
1244             }
1245             d.endHash();
1246         }
1247         if (n < nn)
1248             d.putEllipsis();
1249         d << "]";
1250     }
1251     d.disarm();
1252 }
1253
1254 static void qDumpQLinkedList(QDumper &d)
1255 {
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;
1261     if (nn < 0)
1262         qCheck(false);
1263
1264     int n = nn;
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;
1275
1276         P(d, "childtype", d.innertype);
1277         if (n > 1000)
1278             n = 1000;
1279         d << ",children=[";
1280         const void *p = deref(ldata);
1281         for (int i = 0; i != n; ++i) {
1282             d.beginHash();
1283             P(d, "name", i);
1284             const void *addr = addOffset(p, 2 * sizeof(void*));
1285             qDumpInnerValueOrPointer(d, d.innertype, stripped, addr);
1286             p = deref(p);
1287             d.endHash();
1288         }
1289         if (n < nn)
1290             d.putEllipsis();
1291         d << "]";
1292     }
1293     d.disarm();
1294 }
1295
1296 static void qDumpQLocale(QDumper &d)
1297 {
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) {
1304         d << ",children=[";
1305
1306         d.beginHash();
1307         P(d, "name", "country");
1308         P(d, "exp",  "(("NSX"QLocale"NSY"*)" << d.data << ")->country()");
1309         d.endHash();
1310
1311         d.beginHash();
1312         P(d, "name", "language");
1313         P(d, "exp",  "(("NSX"QLocale"NSY"*)" << d.data << ")->language()");
1314         d.endHash();
1315
1316         d.beginHash();
1317         P(d, "name", "measurementSystem");
1318         P(d, "exp",  "(("NSX"QLocale"NSY"*)" << d.data << ")->measurementSystem()");
1319         d.endHash();
1320
1321         d.beginHash();
1322         P(d, "name", "numberOptions");
1323         P(d, "exp",  "(("NSX"QLocale"NSY"*)" << d.data << ")->numberOptions()");
1324         d.endHash();
1325
1326         S(d, "timeFormat_(short)", locale.timeFormat(QLocale::ShortFormat));
1327         S(d, "timeFormat_(long)", locale.timeFormat(QLocale::LongFormat));
1328
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());
1335
1336         d << "]";
1337     }
1338     d.disarm();
1339 }
1340
1341 static void qDumpQMapNode(QDumper &d)
1342 {
1343     const QMapData *h = reinterpret_cast<const QMapData *>(d.data);
1344     const char *keyType   = d.templateParameters[0];
1345     const char *valueType = d.templateParameters[1];
1346
1347     qCheckAccess(h->backward);
1348     qCheckAccess(h->forward[0]);
1349
1350     P(d, "value", "");
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];
1357
1358         unsigned keyOffset = 2 * sizeof(void*) - mapnodesize;
1359         unsigned valueOffset = 2 * sizeof(void*) - mapnodesize + valueOff;
1360
1361         d << ",children=[";
1362         d.beginHash();
1363         P(d, "name", "key");
1364         qDumpInnerValue(d, keyType, addOffset(h, keyOffset));
1365
1366         d.endHash();
1367         d.beginHash();
1368         P(d, "name", "value");
1369         qDumpInnerValue(d, valueType, addOffset(h, valueOffset));
1370         d.endHash();
1371         d << "]";
1372     }
1373
1374     d.disarm();
1375 }
1376
1377 static void qDumpQMap(QDumper &d)
1378 {
1379     QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
1380     const char *keyType   = d.templateParameters[0];
1381     const char *valueType = d.templateParameters[1];
1382
1383     int n = h->size;
1384
1385     if (n < 0)
1386         qCheck(false);
1387     if (n > 0) {
1388         qCheckAccess(h->backward);
1389         qCheckAccess(h->forward[0]);
1390         qCheckPointer(h->backward->backward);
1391         qCheckPointer(h->forward[0]->backward);
1392     }
1393
1394     P(d, "value", "<" << n << " items>");
1395     P(d, "numchild", n);
1396     if (d.dumpChildren) {
1397         if (n > 1000)
1398             n = 1000;
1399
1400         //unsigned keySize = d.extraInt[0];
1401         //unsigned valueSize = d.extraInt[1];
1402         unsigned mapnodesize = d.extraInt[2];
1403         unsigned valueOff = d.extraInt[3];
1404
1405         bool isSimpleKey = isSimpleType(keyType);
1406         bool isSimpleValue = isSimpleType(valueType);
1407         // both negative:
1408         int keyOffset = 2 * sizeof(void*) - int(mapnodesize);
1409         int valueOffset = 2 * sizeof(void*) - int(mapnodesize) + valueOff;
1410
1411         P(d, "extra", "simplekey: " << isSimpleKey << " isSimpleValue: " << isSimpleValue
1412             << " keyOffset: " << keyOffset << " valueOffset: " << valueOffset
1413             << " mapnodesize: " << mapnodesize);
1414         d << ",children=[";
1415
1416         QMapData::Node *node = reinterpret_cast<QMapData::Node *>(h->forward[0]);
1417         QMapData::Node *end = reinterpret_cast<QMapData::Node *>(h);
1418         int i = 0;
1419
1420         while (node != end) {
1421             d.beginHash();
1422                 P(d, "name", i);
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));
1428                 } else {
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);
1435
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
1439 #else 
1440                     P(d, "type", NS"QMapData::Node<"
1441                         << keyType << "," << valueType << " >");
1442                     P(d, "exp", "*('"NS"QMapData::Node<"
1443                         << keyType << "," << valueType << " >'*)" << node);
1444 #endif
1445                 }
1446             d.endHash();
1447
1448             ++i;
1449             node = node->forward[0];
1450         }
1451         d << "]";
1452     }
1453
1454     d.disarm();
1455 }
1456
1457 static void qDumpQMultiMap(QDumper &d)
1458 {
1459     qDumpQMap(d);
1460 }
1461
1462 static void qDumpQModelIndex(QDumper &d)
1463 {
1464     const QModelIndex *mi = reinterpret_cast<const QModelIndex *>(d.data);
1465
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) {
1471             d << ",children=[";
1472             I(d, "row", mi->row());
1473             I(d, "column", mi->column());
1474
1475             d.beginHash();
1476             P(d, "name", "parent");
1477             const QModelIndex parent = mi->parent();
1478             if (parent.isValid())
1479                 P(d, "value", "(" << mi->row() << ", " << mi->column() << ")");
1480             else
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");
1485             d.endHash();
1486
1487             S(d, "internalId", QString::number(mi->internalId(), 10));
1488
1489             d.beginHash();
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");
1494             d.endHash();
1495
1496             d << "]";
1497         }
1498     } else {
1499         P(d, "value", "<invalid>");
1500         P(d, "numchild", 0);
1501     }
1502
1503     d.disarm();
1504 }
1505
1506 static void qDumpQObject(QDumper &d)
1507 {
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();
1518         int slotCount = 0;
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);
1524         }
1525         d << ",children=[";
1526         d.beginHash();
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());
1535         d.endHash();
1536 #if 0
1537         d.beginHash();
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());
1542         d.endHash();
1543 #endif
1544 #if 0
1545         d.beginHash();
1546             P(d, "name", "senders");
1547             P(d, "exp", "(*(class '"NS"QObjectPrivate'*)" << dfunc(ob) << ")->senders");
1548             P(d, "type", NS"QList<"NS"QObjectPrivateSender>");
1549         d.endHash();
1550 #endif
1551 #if PRIVATE_OBJECT_ALLOWED
1552         d.beginHash();
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);
1558         d.endHash();
1559         d.beginHash();
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);
1565         d.endHash();
1566 #endif
1567         d.beginHash();
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()");
1571             //
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());
1578         d.endHash();
1579 #if 0
1580         // Unneeded (and not working): Connections are listes as childen
1581         // of the signal or slot they are connected to.
1582         // d.beginHash();
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> >");
1586         // d.endHash();
1587 #endif
1588 #if 0
1589         d.beginHash();
1590             P(d, "name", "objectprivate");
1591             P(d, "type", NS"QObjectPrivate");
1592             P(d, "addr", dfunc(ob));
1593             P(d, "value", "");
1594             P(d, "numchild", "1");
1595         d.endHash();
1596 #endif
1597         d.beginHash();
1598             P(d, "name", "parent");
1599             qDumpInnerValueHelper(d, NS"QObject *", ob->parent());
1600         d.endHash();
1601 #if 1
1602         d.beginHash();
1603             P(d, "name", "className");
1604             P(d, "value",ob->metaObject()->className());
1605             P(d, "type", "");
1606             P(d, "numchild", "0");
1607         d.endHash();
1608 #endif
1609         d << "]";
1610     }
1611     d.disarm();
1612 }
1613
1614 static void qDumpQObjectPropertyList(QDumper &d)
1615 {
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) {
1622         d << ",children=[";
1623         for (int i = mo->propertyCount(); --i >= 0; ) {
1624             const QMetaProperty & prop = mo->property(i);
1625             d.beginHash();
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");
1640             }
1641             P(d, "type", prop.typeName());
1642             P(d, "numchild", "1");
1643             d.endHash();
1644         }
1645         d << "]";
1646     }
1647     d.disarm();
1648 }
1649
1650 static void qDumpQObjectMethodList(QDumper &d)
1651 {
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) {
1660         d << ",children=[";
1661         for (int i = 0; i != mo->methodCount(); ++i) {
1662             const QMetaMethod & method = mo->method(i);
1663             int mt = method.methodType();
1664             d.beginHash();
1665             P(d, "name", i << " " << mo->indexOfMethod(method.signature())
1666                 << " " << method.signature());
1667             P(d, "value", (mt == QMetaMethod::Signal ? "<Signal>" : "<Slot>") << " (" << mt << ")");
1668             d.endHash();
1669         }
1670         d << "]";
1671     }
1672     d.disarm();
1673 }
1674
1675 #if PRIVATE_OBJECT_ALLOWED
1676 const char * qConnectionTypes[] ={
1677     "auto",
1678     "direct",
1679     "queued",
1680     "autocompat",
1681     "blockingqueued"
1682 };
1683
1684 #if QT_VERSION >= 0x040400
1685 static const QObjectPrivate::ConnectionList &qConnectionList(const QObject *ob, int signalNumber)
1686 {
1687     static const QObjectPrivate::ConnectionList emptyList;
1688     const QObjectPrivate *p = reinterpret_cast<const QObjectPrivate *>(dfunc(ob));
1689     if (!p->connectionLists)
1690         return emptyList;
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())
1696         return emptyList;
1697     return lists->at(signalNumber);
1698 }
1699 #endif
1700
1701 static void qDumpQObjectSignal(QDumper &d)
1702 {
1703     unsigned signalNumber = d.extraInt[0];
1704
1705     P(d, "addr", "<synthetic>");
1706     P(d, "numchild", "1");
1707     P(d, "type", NS"QObjectSignal");
1708
1709 #if QT_VERSION >= 0x040400
1710     if (d.dumpChildren) {
1711         const QObject *ob = reinterpret_cast<const QObject *>(d.data);
1712         d << ",children=[";
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);
1716             d.beginHash();
1717                 P(d, "name", i << " receiver");
1718                 qDumpInnerValueHelper(d, NS"QObject *", conn.receiver);
1719             d.endHash();
1720             d.beginHash();
1721                 P(d, "name", i << " slot");
1722                 P(d, "type", "");
1723                 if (conn.receiver) 
1724                     P(d, "value", conn.receiver->metaObject()->method(conn.method).signature());
1725                 else
1726                     P(d, "value", "<invalid receiver>");
1727                 P(d, "numchild", "0");
1728             d.endHash();
1729             d.beginHash();
1730                 P(d, "name", i << " type");
1731                 P(d, "type", "");
1732                 P(d, "value", "<" << qConnectionTypes[conn.method] << " connection>");
1733                 P(d, "numchild", "0");
1734             d.endHash();
1735         }
1736         d << "]";
1737         P(d, "numchild", connList.size());
1738     }
1739 #endif
1740     d.disarm();
1741 }
1742
1743 static void qDumpQObjectSignalList(QDumper &d)
1744 {
1745     const QObject *ob = reinterpret_cast<const QObject *>(d.data);
1746     const QMetaObject *mo = ob->metaObject();
1747     int count = 0;
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) {
1754         d << ",children=[";
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);
1760                 d.beginHash();
1761                 P(d, "name", 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");
1767                 d.endHash();
1768             }
1769         }
1770         d << "]";
1771     }
1772 #endif
1773     d.disarm();
1774 }
1775
1776 static void qDumpQObjectSlot(QDumper &d)
1777 {
1778     int slotNumber = d.extraInt[0];
1779
1780     P(d, "addr", d.data);
1781     P(d, "numchild", "1");
1782     P(d, "type", NS"QObjectSlot");
1783
1784 #if QT_VERSION >= 0x040400
1785     if (d.dumpChildren) {
1786         d << ",children=[";
1787         int numchild = 0;
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) {
1797                     ++numchild;
1798                     const QMetaMethod & method =
1799                         sender.sender->metaObject()->method(sender.signal);
1800                     d.beginHash();
1801                         P(d, "name", s << " sender");
1802                         qDumpInnerValueHelper(d, NS"QObject *", sender.sender);
1803                     d.endHash();
1804                     d.beginHash();
1805                         P(d, "name", s << " signal");
1806                         P(d, "type", "");
1807                         P(d, "value", method.signature());
1808                         P(d, "numchild", "0");
1809                     d.endHash();
1810                     d.beginHash();
1811                         P(d, "name", s << " type");
1812                         P(d, "type", "");
1813                         P(d, "value", "<" << qConnectionTypes[conn.method] << " connection>");
1814                         P(d, "numchild", "0");
1815                     d.endHash();
1816                 }
1817             }
1818         }
1819         d << "]";
1820         P(d, "numchild", numchild);
1821     }
1822 #endif
1823     d.disarm();
1824 }
1825
1826 static void qDumpQObjectSlotList(QDumper &d)
1827 {
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));
1831 #endif
1832     const QMetaObject *mo = ob->metaObject();
1833
1834     int count = 0;
1835     for (int i = mo->methodCount(); --i >= 0; )
1836         count += (mo->method(i).methodType() == QMetaMethod::Slot);
1837
1838     P(d, "addr", d.data);
1839     P(d, "numchild", count);
1840 #if QT_VERSION >= 0x040400
1841     if (d.dumpChildren) {
1842         d << ",children=[";
1843         for (int i = 0; i != mo->methodCount(); ++i) {
1844             const QMetaMethod & method = mo->method(i);
1845             if (method.methodType() == QMetaMethod::Slot) {
1846                 d.beginHash();
1847                 int k = mo->indexOfSlot(method.signature());
1848                 P(d, "name", k);
1849                 P(d, "value", method.signature());
1850
1851                 // count senders. expensive...
1852                 int numchild = 0;
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)
1860                             ++numchild;
1861                     }
1862                 }
1863                 P(d, "numchild", numchild);
1864                 P(d, "exp", "*(class '"NS"QObject'*)" << d.data);
1865                 P(d, "type", NS"QObjectSlot");
1866                 d.endHash();
1867             }
1868         }
1869         d << "]";
1870     }
1871 #endif
1872     d.disarm();
1873 }
1874 #endif // PRIVATE_OBJECT_ALLOWED
1875
1876
1877 static void qDumpQPixmap(QDumper &d)
1878 {
1879 #ifdef QT_GUI_LIB
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");
1884     d.disarm();
1885 #else
1886     Q_UNUSED(d);
1887 #endif
1888 }
1889
1890 static void qDumpQSet(QDumper &d)
1891 {
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();
1896
1897     int n = hd->size;
1898     if (n < 0)
1899         qCheck(false);
1900     if (n > 0) {
1901         qCheckAccess(node);
1902         qCheckPointer(node->next);
1903     }
1904
1905     P(d, "value", "<" << n << " items>");
1906     P(d, "valuedisabled", "true");
1907     P(d, "numchild", 2 * n);
1908     if (d.dumpChildren) {
1909         if (n > 100)
1910             n = 100;
1911         d << ",children=[";
1912         int i = 0;
1913         for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) {
1914             for (node = hd->buckets[bucket]; node->next; node = node->next) {
1915                 d.beginHash();
1916                 P(d, "name", i);
1917                 P(d, "type", d.innertype);
1918                 P(d, "exp", "(('"NS"QHashNode<" << d.innertype
1919                     << ","NS"QHashDummyValue>'*)"
1920                     << static_cast<const void*>(node) << ")->key"
1921                 );
1922                 d.endHash();
1923                 ++i;
1924                 if (i > 10000) {
1925                     d.putEllipsis();
1926                     break;
1927                 }
1928             }
1929         }
1930         d << "]";
1931     }
1932     d.disarm();
1933 }
1934
1935 static void qDumpQString(QDumper &d)
1936 {
1937     const QString &str = *reinterpret_cast<const QString *>(d.data);
1938
1939     if (!str.isEmpty()) {
1940         qCheckAccess(str.unicode());
1941         qCheckAccess(str.unicode() + str.size());
1942     }
1943
1944     P(d, "value", str);
1945     P(d, "valueencoded", "1");
1946     P(d, "type", NS"QString");
1947     //P(d, "editvalue", str);  // handled generically below
1948     P(d, "numchild", "0");
1949
1950     d.disarm();
1951 }
1952
1953 static void qDumpQStringList(QDumper &d)
1954 {
1955     const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
1956     int n = list.size();
1957     if (n < 0)
1958         qCheck(false);
1959     if (n > 0) {
1960         qCheckAccess(&list.front());
1961         qCheckAccess(&list.back());
1962     }
1963
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) {
1970         if (n > 1000)
1971             n = 1000;
1972         d << ",children=[";
1973         for (int i = 0; i != n; ++i) {
1974             d.beginHash();
1975             P(d, "name", i);
1976             P(d, "value", list[i]);
1977             P(d, "valueencoded", "1");
1978             d.endHash();
1979         }
1980         if (n < list.size())
1981             d.putEllipsis();
1982         d << "]";
1983     }
1984     d.disarm();
1985 }
1986
1987 static void qDumpQTextCodec(QDumper &d)
1988 {
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) {
1995         d << ",children=[";
1996         S(d, "name", codec.name());
1997         I(d, "mibEnum", codec.mibEnum());
1998         d << "]";
1999     }
2000     d.disarm();
2001 }
2002
2003 static void qDumpQVariantHelper(const void *data, QString *value,
2004     QString *exp, int *numchild)
2005 {
2006     const QVariant &v = *reinterpret_cast<const QVariant *>(data);
2007     switch (v.type()) {
2008     case QVariant::Invalid:
2009         *value = QLatin1String("<invalid>");
2010         *numchild = 0;
2011         break;
2012     case QVariant::String:
2013         *value = QLatin1Char('"') + v.toString() + QLatin1Char('"');
2014         *numchild = 0;
2015         break;
2016     case QVariant::StringList:
2017         *exp = QString(QLatin1String("((QVariant*)%1)->d.data.c"))
2018                     .arg((quintptr)data);
2019         *numchild = v.toStringList().size();
2020         break;
2021     case QVariant::Int:
2022         *value = QString::number(v.toInt());
2023         *numchild= 0;
2024         break;
2025     case QVariant::Double:
2026         *value = QString::number(v.toDouble());
2027         *numchild = 0;
2028         break;
2029     default: {
2030         char buf[1000];
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);
2036         *numchild = 1;
2037         break;
2038         }
2039     }
2040 }
2041
2042 static void qDumpQVariant(QDumper &d)
2043 {
2044     const QVariant &v = *reinterpret_cast<const QVariant *>(d.data);
2045     QString value;
2046     QString exp;
2047     int numchild = 0;
2048     qDumpQVariantHelper(d.data, &value, &exp, &numchild);
2049     bool isInvalid = (v.typeName() == 0);
2050     if (isInvalid) {
2051         P(d, "value", "(invalid)");
2052     } else if (value.isEmpty()) {
2053         P(d, "value", "(" << v.typeName() << ") " << qPrintable(value));
2054     } else {
2055         QByteArray ba;
2056         ba += '(';
2057         ba += v.typeName();
2058         ba += ") ";
2059         ba += qPrintable(value);
2060         P(d, "value", ba);
2061         P(d, "valueencoded", "1");
2062     }
2063     P(d, "type", NS"QVariant");
2064     P(d, "numchild", (isInvalid ? "0" : "1"));
2065     if (d.dumpChildren) {
2066         d << ",children=[";
2067         d.beginHash();
2068         P(d, "name", "value");
2069         if (!exp.isEmpty())
2070             P(d, "exp", qPrintable(exp));
2071         if (!value.isEmpty()) {
2072             P(d, "value", value);
2073             P(d, "valueencoded", "1");
2074         }
2075         P(d, "type", v.typeName());
2076         P(d, "numchild", numchild);
2077         d.endHash();
2078         d << "]";
2079     }
2080     d.disarm();
2081 }
2082
2083 static void qDumpQVector(QDumper &d)
2084 {
2085     QVectorData *v = *reinterpret_cast<QVectorData *const*>(d.data);
2086
2087     // Try to provoke segfaults early to prevent the frontend
2088     // from asking for unavailable child details
2089     int nn = v->size;
2090     if (nn < 0)
2091         qCheck(false);
2092     if (nn > 0) {
2093         //qCheckAccess(&vec.front());
2094         //qCheckAccess(&vec.back());
2095     }
2096
2097     unsigned innersize = d.extraInt[0];
2098     unsigned typeddatasize = d.extraInt[1];
2099
2100     int n = nn;
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;
2108         if (n > 1000)
2109             n = 1000;
2110         d << ",children=[";
2111         for (int i = 0; i != n; ++i) {
2112             d.beginHash();
2113             P(d, "name", i);
2114             qDumpInnerValueOrPointer(d, d.innertype, stripped,
2115                 addOffset(v, i * innersize + typeddatasize));
2116             d.endHash();
2117         }
2118         if (n < nn)
2119             d.putEllipsis();
2120         d << "]";
2121     }
2122     d.disarm();
2123 }
2124
2125 static void qDumpStdList(QDumper &d)
2126 {
2127     const std::list<int> &list = *reinterpret_cast<const std::list<int> *>(d.data);
2128     const void *p = d.data;
2129     qCheckAccess(p);
2130     p = deref(p);
2131     qCheckAccess(p);
2132     p = deref(p);
2133     qCheckAccess(p);
2134     p = deref(addOffset(d.data, sizeof(void*)));
2135     qCheckAccess(p);
2136     p = deref(addOffset(p, sizeof(void*)));
2137     qCheckAccess(p);
2138     p = deref(addOffset(p, sizeof(void*)));
2139     qCheckAccess(p);
2140
2141     int nn = 0;
2142     std::list<int>::const_iterator it = list.begin();
2143     for (; nn < 101 && it != list.end(); ++nn, ++it)
2144         qCheckAccess(it.operator->());
2145
2146     if (nn > 100)
2147         P(d, "value", "<more than 100 items>");
2148     else
2149         P(d, "value", "<" << nn << " items>");
2150     P(d, "numchild", nn);
2151
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;
2157         d << ",children=[";
2158         it = list.begin();
2159         for (int i = 0; i < 1000 && it != list.end(); ++i, ++it) {
2160             d.beginHash();
2161             P(d, "name", i);
2162             qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->());
2163             d.endHash();
2164         }
2165         if (it != list.end())
2166             d.putEllipsis();
2167         d << "]";
2168     }
2169     d.disarm();
2170 }
2171
2172 static void qDumpStdMap(QDumper &d)
2173 {
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;
2179     qCheckAccess(p);
2180     p = deref(p);
2181
2182     int nn = map.size();
2183     qCheck(nn >= 0);
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->());
2187
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]);
2193
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);
2202     
2203     if (d.dumpChildren) {
2204         bool isSimpleKey = isSimpleType(keyType);
2205         bool isSimpleValue = isSimpleType(valueType);
2206         int valueOffset = d.extraInt[2];
2207
2208         P(d, "extra", "isSimpleKey: " << isSimpleKey
2209             << " isSimpleValue: " << isSimpleValue
2210             << " valueType: '" << valueType
2211             << " valueOffset: " << valueOffset);
2212
2213         d << ",children=[";
2214         it = map.begin();
2215         for (int i = 0; i < 1000 && it != map.end(); ++i, ++it) {
2216             d.beginHash();
2217                 const void *node = it.operator->();
2218                 P(d, "name", i);
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);
2225                 } else {
2226                     P(d, "addr", node);
2227                     P(d, "type", pairType);
2228                     P(d, "numchild", 2);
2229                 }
2230             d.endHash();
2231         }
2232         if (it != map.end())
2233             d.putEllipsis();
2234         d << "]";
2235     }
2236     d.disarm();
2237 }
2238
2239 static void qDumpStdString(QDumper &d)
2240 {
2241     const std::string &str = *reinterpret_cast<const std::string *>(d.data);
2242
2243     if (!str.empty()) {
2244         qCheckAccess(str.c_str());
2245         qCheckAccess(str.c_str() + str.size() - 1);
2246     }
2247
2248     d << ",value=\"";
2249     d.putBase64Encoded(str.c_str(), str.size());
2250     d << "\"";
2251     P(d, "valueencoded", "1");
2252     P(d, "type", "std::string");
2253     P(d, "numchild", "0");
2254
2255     d.disarm();
2256 }
2257
2258 static void qDumpStdWString(QDumper &d)
2259 {
2260     const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data);
2261
2262     if (!str.empty()) {
2263         qCheckAccess(str.c_str());
2264         qCheckAccess(str.c_str() + str.size() - 1);
2265     }
2266
2267     d << "value='";
2268     d.putBase64Encoded((const char *)str.c_str(), str.size() * sizeof(wchar_t));
2269     d << "'";
2270     P(d, "valueencoded", (sizeof(wchar_t) == 2 ? "2" : "3"));
2271     P(d, "type", "std::wstring");
2272     P(d, "numchild", "0");
2273
2274     d.disarm();
2275 }
2276
2277 static void qDumpStdVector(QDumper &d)
2278 {
2279     // Correct type would be something like:
2280     // std::_Vector_base<int,std::allocator<int, std::allocator<int> >>::_Vector_impl
2281     struct VectorImpl {
2282         char *start;
2283         char *finish;
2284         char *end_of_storage;
2285     };
2286     const VectorImpl *v = static_cast<const VectorImpl *>(d.data);
2287
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];
2291     if (nn < 0)
2292         qCheck(false);
2293     if (nn > 0) {
2294         qCheckAccess(v->start);
2295         qCheckAccess(v->finish);
2296         qCheckAccess(v->end_of_storage);
2297     }
2298
2299     int n = nn;
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;
2308         if (n > 1000)
2309             n = 1000;
2310         d << ",children=[";
2311         for (int i = 0; i != n; ++i) {
2312             d.beginHash();
2313             P(d, "name", i);
2314             qDumpInnerValueOrPointer(d, d.innertype, stripped,
2315                 addOffset(v->start, i * innersize));
2316             d.endHash();
2317         }
2318         if (n < nn)
2319             d.putEllipsis();
2320         d << "]";
2321     }
2322     d.disarm();
2323 }
2324
2325 static void qDumpStdVectorBool(QDumper &d)
2326 {
2327     // FIXME
2328     return qDumpStdVector(d);
2329 }
2330
2331 static void handleProtocolVersion2and3(QDumper & d)
2332 {
2333     if (!d.outertype[0]) {
2334         qDumpUnknown(d);
2335         return;
2336     }
2337
2338     d.setupTemplateParameters();
2339     P(d, "iname", d.iname);
2340     P(d, "addr", d.data);
2341
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);
2347             QByteArray ba;
2348             QDataStream ds(&ba, QIODevice::WriteOnly);
2349             ds << v;
2350             P(d, "editvalue", ba);
2351         }
2352     }
2353 #endif
2354
2355     const char *type = stripNamespace(d.outertype);
2356     // type[0] is usally 'Q', so don't use it
2357     switch (type[1]) {
2358         case 'B':
2359             if (isEqual(type, "QByteArray"))
2360                 qDumpQByteArray(d);
2361             break;
2362         case 'D':
2363             if (isEqual(type, "QDateTime"))
2364                 qDumpQDateTime(d);
2365             else if (isEqual(type, "QDir"))
2366                 qDumpQDir(d);
2367             break;
2368         case 'F':
2369             if (isEqual(type, "QFile"))
2370                 qDumpQFile(d);
2371             else if (isEqual(type, "QFileInfo"))
2372                 qDumpQFileInfo(d);
2373             break;
2374         case 'H':
2375             if (isEqual(type, "QHash"))
2376                 qDumpQHash(d);
2377             else if (isEqual(type, "QHashNode"))
2378                 qDumpQHashNode(d);
2379             break;
2380         case 'I':
2381             if (isEqual(type, "QImage"))
2382                 qDumpQImage(d);
2383             break;
2384         case 'L':
2385             if (isEqual(type, "QList"))
2386                 qDumpQList(d);
2387             else if (isEqual(type, "QLinkedList"))
2388                 qDumpQLinkedList(d);
2389             else if (isEqual(type, "QLocale"))
2390                 qDumpQLocale(d);
2391             break;
2392         case 'M':
2393             if (isEqual(type, "QMap"))
2394                 qDumpQMap(d);
2395             else if (isEqual(type, "QMapNode"))
2396                 qDumpQMapNode(d);
2397             else if (isEqual(type, "QModelIndex"))
2398                 qDumpQModelIndex(d);
2399             else if (isEqual(type, "QMultiMap"))
2400                 qDumpQMultiMap(d);
2401             break;
2402         case 'O':
2403             if (isEqual(type, "QObject"))
2404                 qDumpQObject(d);
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);
2418             #endif
2419             break;
2420         case 'P':
2421             if (isEqual(type, "QPixmap"))
2422                 qDumpQPixmap(d);
2423             break;
2424         case 'S':
2425             if (isEqual(type, "QSet"))
2426                 qDumpQSet(d);
2427             else if (isEqual(type, "QString"))
2428                 qDumpQString(d);
2429             else if (isEqual(type, "QStringList"))
2430                 qDumpQStringList(d);
2431             break;
2432         case 'T':
2433             if (isEqual(type, "QTextCodec"))
2434                 qDumpQTextCodec(d);
2435             break;
2436         case 'V':
2437             if (isEqual(type, "QVariant"))
2438                 qDumpQVariant(d);
2439             else if (isEqual(type, "QVector"))
2440                 qDumpQVector(d);
2441             break;
2442         case 's':
2443             if (isEqual(type, "wstring"))
2444                 qDumpStdWString(d);
2445             break;
2446         case 't':
2447             if (isEqual(type, "std::vector"))
2448                 qDumpStdVector(d);
2449             else if (isEqual(type, "std::vector::bool"))
2450                 qDumpStdVectorBool(d);
2451             else if (isEqual(type, "std::list"))
2452                 qDumpStdList(d);
2453             else if (isEqual(type, "std::map"))
2454                 qDumpStdMap(d);
2455             else if (isEqual(type, "std::string") || isEqual(type, "string"))
2456                 qDumpStdString(d);
2457             else if (isEqual(type, "std::wstring"))
2458                 qDumpStdWString(d);
2459             break;
2460     }
2461
2462     if (!d.success)
2463         qDumpUnknown(d);
2464 }
2465
2466 } // anonymous namespace
2467
2468
2469 extern "C" Q_DECL_EXPORT
2470 void qDumpObjectData440(
2471     int protocolVersion,
2472     int token,
2473     void *data,
2474     bool dumpChildren,
2475     int extraInt0,
2476     int extraInt1,
2477     int extraInt2,
2478     int extraInt3)
2479 {
2480     //sleep(20);
2481     if (protocolVersion == 1) {
2482         QDumper d;
2483         d.protocolVersion = protocolVersion;
2484         d.token           = token;
2485
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.
2490         d << "dumpers=["
2491             "\""NS"QByteArray\","
2492             "\""NS"QDateTime\","
2493             "\""NS"QDir\","
2494             "\""NS"QFile\","
2495             "\""NS"QFileInfo\","
2496             "\""NS"QHash\","
2497             "\""NS"QHashNode\","
2498             "\""NS"QImage\","
2499             "\""NS"QLinkedList\","
2500             "\""NS"QList\","
2501             "\""NS"QLocale\","
2502             "\""NS"QMap\","
2503             "\""NS"QMapNode\","
2504             "\""NS"QModelIndex\","
2505             #if QT_VERSION >= 0x040500
2506             "\""NS"QMultiMap\","
2507             #endif
2508             "\""NS"QObject\","
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\","
2518             "\""NS"QSet\","
2519             "\""NS"QString\","
2520             "\""NS"QStringList\","
2521             "\""NS"QTextCodec\","
2522             "\""NS"QVariant\","
2523             "\""NS"QVector\","
2524             "\""NS"QWidget\","
2525             "\"string\","
2526             "\"wstring\","
2527             "\"std::basic_string\","
2528             "\"std::list\","
2529             "\"std::map\","
2530             "\"std::string\","
2531             "\"std::vector\","
2532             "\"std::wstring\","
2533             "]";
2534         d << ",qtversion=["
2535             "\"" << ((QT_VERSION >> 16) & 255) << "\","
2536             "\"" << ((QT_VERSION >> 8)  & 255) << "\","
2537             "\"" << ((QT_VERSION)       & 255) << "\"]";
2538         d << ",namespace=\""NS"\"";
2539         d.disarm();
2540     }
2541
2542     else if (protocolVersion == 2 || protocolVersion == 3) {
2543         QDumper d;
2544
2545         d.protocolVersion = protocolVersion;
2546         d.token           = token;
2547         d.data            = data;
2548         d.dumpChildren    = dumpChildren;
2549         d.extraInt[0]     = extraInt0;
2550         d.extraInt[1]     = extraInt1;
2551         d.extraInt[2]     = extraInt2;
2552         d.extraInt[3]     = extraInt3;
2553
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;
2560
2561         handleProtocolVersion2and3(d);
2562     }
2563
2564     else {
2565         qDebug() << "Unsupported protocol version" << protocolVersion;
2566     }
2567 }