source: trunk/src/corelib/tools/qdumper.cpp@ 265

Last change on this file since 265 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 33.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <qdatetime.h>
43#include <qdebug.h>
44#include <qdir.h>
45#include <qfileinfo.h>
46#include <qhash.h>
47#include <qmap.h>
48#include <qmetaobject.h>
49#include <qobject.h>
50#include <qstring.h>
51#include <qvariant.h>
52#include <qvector.h>
53
54#if !defined(Q_OS_WINCE) && !defined(QT_NO_DUMPER)
55
56#include <stdlib.h>
57#include <stdio.h>
58
59#ifdef Q_OS_WIN
60# include <windows.h>
61#endif
62
63QT_BEGIN_NAMESPACE
64
65namespace {
66
67// This is used to abort evaluation of custom data dumpers in a "coordinated"
68// way. Abortion will happen anyway when we try to access a non-initialized
69// non-trivial object, so there is no way to prevent this from occuring at all
70// conceptionally. Gdb will catch SIGSEGV and return to the calling frame.
71// This is just fine provided we only _read_ memory in the custom handlers
72// below.
73
74volatile int qProvokeSegFaultHelper;
75
76static void qCheckAccess(const void *d)
77{
78 // provoke segfault when address is not readable
79 qProvokeSegFaultHelper = *(char*)d;
80}
81
82static void qCheckPointer(const void *d)
83{
84 if (!d)
85 return;
86 qProvokeSegFaultHelper = *(char*)d;
87}
88
89static void qProvokeSegFault()
90{
91 // provoke segfault unconditionally
92 qCheckAccess(0);
93}
94
95static char qDumpInBuffer[100];
96static char qDumpBuffer[1000];
97#ifdef Q_OS_WIN
98static char qDumpBuffer2[sizeof(qDumpBuffer) + 100];
99#endif
100
101static char toHex(int n)
102{
103 return n < 10 ? '0' + n : 'a' - 10 + n;
104}
105
106
107struct QDumper
108{
109 explicit QDumper();
110 ~QDumper();
111 void flush();
112 QDumper &operator<<(long c);
113 QDumper &operator<<(int i);
114 QDumper &operator<<(unsigned long c);
115 QDumper &operator<<(unsigned int i);
116 QDumper &operator<<(const void *p);
117 void put(char c);
118 void addCommaIfNeeded();
119 void putEncoded(unsigned c);
120 QDumper &operator<<(const char *str);
121 QDumper &operator<<(const QString &str);
122 void disarm();
123
124 void beginHash(); // start of data hash output
125 void endHash(); // start of data hash output
126
127 // the dumper arguments
128 int protocolVersion; // dumper protocol version
129 int token; // some token to show on success
130 const char *outertype; // object type
131 const char *iname; // object name used for display
132 const char *exp; // object expression
133 const char *innertype; // 'inner type' for class templates
134 const void *data; // pointer to raw data
135 bool dumpChildren; // do we want to see children?
136
137 // handling of nested templates
138 void setupTemplateParameters();
139 enum { maxTemplateParameters = 10 };
140 const char *templateParameters[maxTemplateParameters + 1];
141 int templateParametersCount;
142
143 // internal state
144 bool success; // are we finished?
145 size_t pos;
146};
147
148
149QDumper::QDumper()
150{
151 success = false;
152 pos = 0;
153}
154
155QDumper::~QDumper()
156{
157 flush();
158 put(0); // our end marker
159#ifdef Q_OS_WIN
160 sprintf(qDumpBuffer2, "@@CDD/%d/done\n", token);
161 OutputDebugStringA(qDumpBuffer2);
162#else
163 fprintf(stderr, "%d/done\n", token);
164#endif
165 qDumpInBuffer[0] = 0;
166}
167
168void QDumper::flush()
169{
170 qDumpBuffer[pos++] = 0;
171#ifdef Q_OS_WIN
172 sprintf(qDumpBuffer2, "@@CDD#%d#%d,%s\n", token, int(pos - 1), qDumpBuffer);
173 OutputDebugStringA(qDumpBuffer2);
174#else
175 fprintf(stderr, "%d#%d,%s\n", token, int(pos - 1), qDumpBuffer);
176#endif
177 pos = 0;
178}
179
180void QDumper::setupTemplateParameters()
181{
182 char *s = const_cast<char *>(innertype);
183
184 templateParametersCount = 1;
185 templateParameters[0] = s;
186 for (int i = 1; i != maxTemplateParameters + 1; ++i)
187 templateParameters[i] = 0;
188
189 while (*s) {
190 while (*s && *s != '@')
191 ++s;
192 if (*s) {
193 *s = '\0';
194 ++s;
195 templateParameters[templateParametersCount++] = s;
196 }
197 }
198}
199
200QDumper &QDumper::operator<<(unsigned long c)
201{
202 static char buf[100];
203 sprintf(buf, "%lu", c);
204 return (*this) << buf;
205}
206
207QDumper &QDumper::operator<<(unsigned int i)
208{
209 static char buf[100];
210 sprintf(buf, "%u", i);
211 return (*this) << buf;
212}
213
214QDumper &QDumper::operator<<(long c)
215{
216 static char buf[100];
217 sprintf(buf, "%ld", c);
218 return (*this) << buf;
219}
220
221QDumper &QDumper::operator<<(int i)
222{
223 static char buf[100];
224 sprintf(buf, "%d", i);
225 return (*this) << buf;
226}
227
228QDumper &QDumper::operator<<(const void *p)
229{
230 static char buf[100];
231 sprintf(buf, "%p", p);
232 // we get a '0x' prefix only on some implementations.
233 // if it isn't there, write it out manually.
234 if (buf[1] != 'x') {
235 put('0');
236 put('x');
237 }
238 return (*this) << buf;
239}
240
241void QDumper::put(char c)
242{
243 if (pos >= sizeof(qDumpBuffer) - 100)
244 flush();
245 qDumpBuffer[pos++] = c;
246}
247
248void QDumper::addCommaIfNeeded()
249{
250 if (pos == 0)
251 return;
252 if (qDumpBuffer[pos - 1] == '}' || qDumpBuffer[pos - 1] == '"')
253 put(',');
254}
255
256void QDumper::putEncoded(unsigned c)
257{
258 if (c >= 32 && c <= 126 && c != '"' && c != '\\') {
259 put(c);
260 } else {
261 put('\\');
262 put('u');
263 put(toHex((c >> 12) & 0xf));
264 put(toHex((c >> 8) & 0xf));
265 put(toHex((c >> 4) & 0xf));
266 put(toHex( c & 0xf));
267 }
268}
269
270QDumper &QDumper::operator<<(const char *str)
271{
272 while (*str)
273 put(*(str++));
274 return *this;
275}
276
277QDumper &QDumper::operator<<(const QString &str)
278{
279 int n = str.size();
280 if (n < 0) {
281 qProvokeSegFault();
282 } else {
283 //(*this) << "[" << n << "]";
284 if (n > 1000000)
285 n = 1000000;
286 //put(' ');
287 put('\\');
288 put('"');
289 for (int i = 0; i != n; ++i)
290 putEncoded(str[i].unicode());
291 put('\\');
292 put('"');
293 if (n < str.size())
294 (*this) << "<incomplete string>";
295 }
296 return *this;
297}
298
299void QDumper::disarm()
300{
301 flush();
302 success = true;
303}
304
305void QDumper::beginHash()
306{
307 addCommaIfNeeded();
308 put('{');
309}
310
311void QDumper::endHash()
312{
313 put('}');
314}
315
316
317//
318// Some helpers to keep the dumper code short
319//
320
321// dump property=value pair
322#undef P
323#define P(dumper,name,value) \
324 do { \
325 dumper.addCommaIfNeeded(); \
326 dumper << (name) << "=\"" << value << "\""; \
327 } while (0)
328
329// simple string property
330#undef S
331#define S(dumper, name, value) \
332 dumper.beginHash(); \
333 P(dumper, "name", name); \
334 P(dumper, "value", value); \
335 P(dumper, "type", "QString"); \
336 P(dumper, "numchild", "0"); \
337 dumper.endHash();
338
339// simple integer property
340#undef I
341#define I(dumper, name, value) \
342 dumper.beginHash(); \
343 P(dumper, "name", name); \
344 P(dumper, "value", value); \
345 P(dumper, "type", "int"); \
346 P(dumper, "numchild", "0"); \
347 dumper.endHash();
348
349// simple boolean property
350#undef BL
351#define BL(dumper, name, value) \
352 dumper.beginHash(); \
353 P(dumper, "name", name); \
354 P(dumper, "value", (value ? "true" : "false")); \
355 P(dumper, "type", "bool"); \
356 P(dumper, "numchild", "0"); \
357 dumper.endHash();
358
359#undef TT
360#define TT(type, value) \
361 "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>"
362
363static void qDumpUnknown(QDumper &d)
364{
365 P(d, "iname", d.iname);
366 P(d, "addr", d.data);
367 P(d, "value", "<internal error>");
368 P(d, "type", d.outertype);
369 P(d, "numchild", "0");
370 d.disarm();
371}
372
373static void qDumpQPropertyList(QDumper &d)
374{
375 const QObject *ob = (const QObject *)d.data;
376 const QMetaObject *mo = ob->metaObject();
377 P(d, "iname", d.iname);
378 P(d, "addr", "<synthetic>");
379 P(d, "type", "QObject");
380 P(d, "numchild", mo->propertyCount());
381 if (d.dumpChildren) {
382 d << ",children=[";
383 for (int i = mo->propertyCount(); --i >= 0; ) {
384 const QMetaProperty & prop = mo->property(i);
385 d.beginHash();
386 P(d, "name", prop.name());
387 if (QLatin1String(prop.typeName()) == QLatin1String("QString")) {
388 P(d, "value", prop.read(ob).toString());
389 P(d, "numchild", "0");
390 } else if (QLatin1String(prop.typeName()) == QLatin1String("bool")) {
391 P(d, "value", (prop.read(ob).toBool() ? "true" : "false"));
392 P(d, "numchild", "0");
393 } else if (QLatin1String(prop.typeName()) == QLatin1String("int")) {
394 P(d, "value", prop.read(ob).toInt());
395 P(d, "numchild", "0");
396 } else {
397 P(d, "exp", "((" << mo->className() << "*)" << ob
398 << ")->" << prop.name() << "()");
399 }
400 P(d, "type", prop.typeName());
401 P(d, "numchild", "1");
402 d.endHash();
403 }
404 d << "]";
405 }
406 d.disarm();
407}
408
409static void qDumpQObject(QDumper &d)
410{
411 const QObject *ob = reinterpret_cast<const QObject *>(d.data);
412 P(d, "iname", d.iname);
413 P(d, "addr", d.data);
414 P(d, "value", (void*)d.data);
415 P(d, "type", "QObject");
416 P(d, "numchild", 4);
417 if (d.dumpChildren) {
418 const QMetaObject *mo = ob->metaObject();
419 const QObjectList &children = ob->children();
420 d << ",children=[";
421 S(d, "objectName", ob->objectName());
422 d.beginHash();
423 P(d, "name", "properties");
424 // FIXME: Note that when simply using '(QObject*)'
425 // in the cast below, Gdb/MI _sometimes misparses
426 // expressions further down in the tree.
427 P(d, "exp", "*(class QObject*)" << d.data);
428 P(d, "type", "QPropertyList");
429 P(d, "value", "<" << mo->propertyCount() << " items>");
430 P(d, "numchild", mo->propertyCount());
431 d.endHash();
432 d.beginHash();
433 P(d, "name", "children");
434 P(d, "exp", "((class QObject*)" << d.data << ")->children()");
435 P(d, "type", "QList<QObject *>");
436 P(d, "value", "<" << children.size() << " items>");
437 P(d, "numchild", children.size());
438 d.endHash();
439 d.beginHash();
440 P(d, "name", "parent");
441 P(d, "exp", "((class QObject*)" << d.data << ")->parent()");
442 P(d, "type", "QObject *");
443 P(d, "numchild", (ob->parent() ? "1" : "0"));
444 d.endHash();
445 d << "]";
446 }
447 d.disarm();
448}
449
450static void qDumpQDir(QDumper &d)
451{
452 const QDir &dir = *reinterpret_cast<const QDir *>(d.data);
453 P(d, "iname", d.iname);
454 P(d, "addr", d.data);
455 P(d, "value", dir.path());
456 P(d, "type", "QDir");
457 P(d, "numchild", "3");
458 if (d.dumpChildren) {
459 d << ",children=[";
460 S(d, "absolutePath", dir.absolutePath());
461 S(d, "canonicalPath", dir.canonicalPath());
462 d << "]";
463 }
464 d.disarm();
465}
466
467static void qDumpQFileInfo(QDumper &d)
468{
469 const QFileInfo &info = *reinterpret_cast<const QFileInfo *>(d.data);
470 P(d, "iname", d.iname);
471 P(d, "addr", d.data);
472 P(d, "value", info.filePath());
473 P(d, "type", "QDir");
474 P(d, "numchild", "3");
475 if (d.dumpChildren) {
476 d << ",children=[";
477 S(d, "absolutePath", info.absolutePath());
478 S(d, "absoluteFilePath", info.absoluteFilePath());
479 S(d, "canonicalPath", info.canonicalPath());
480 S(d, "canonicalFilePath", info.canonicalFilePath());
481 S(d, "completeBaseName", info.completeBaseName());
482 S(d, "completeSuffix", info.completeSuffix());
483 S(d, "baseName", info.baseName());
484#ifdef Q_OS_MACX
485 BL(d, "isBundle", info.isBundle());
486 S(d, "bundleName", info.bundleName());
487#endif
488 S(d, "completeSuffix", info.completeSuffix());
489 S(d, "fileName", info.fileName());
490 S(d, "filePath", info.filePath());
491 S(d, "group", info.group());
492 S(d, "owner", info.owner());
493 S(d, "path", info.path());
494
495 I(d, "groupid", (long)info.groupId());
496 I(d, "ownerid", (long)info.ownerId());
497 //QFile::Permissions permissions () const
498 I(d, "permissions", info.permissions());
499
500 //QDir absoluteDir () const
501 //QDir dir () const
502
503 BL(d, "caching", info.caching());
504 BL(d, "exists", info.exists());
505 BL(d, "isAbsolute", info.isAbsolute());
506 BL(d, "isDir", info.isDir());
507 BL(d, "isExecutable", info.isExecutable());
508 BL(d, "isFile", info.isFile());
509 BL(d, "isHidden", info.isHidden());
510 BL(d, "isReadable", info.isReadable());
511 BL(d, "isRelative", info.isRelative());
512 BL(d, "isRoot", info.isRoot());
513 BL(d, "isSymLink", info.isSymLink());
514 BL(d, "isWritable", info.isWritable());
515
516#ifndef QT_NO_DATESTRING
517 d.beginHash();
518 P(d, "name", "created");
519 P(d, "value", info.created().toString());
520 P(d, "exp", "((QFileInfo*)" << d.data << ")->created()");
521 P(d, "type", "QDateTime");
522 P(d, "numchild", "1");
523 d.endHash();
524
525 d.beginHash();
526 P(d, "name", "lastModified");
527 P(d, "value", info.lastModified().toString());
528 P(d, "exp", "((QFileInfo*)" << d.data << ")->lastModified()");
529 P(d, "type", "QDateTime");
530 P(d, "numchild", "1");
531 d.endHash();
532
533 d.beginHash();
534 P(d, "name", "lastRead");
535 P(d, "value", info.lastRead().toString());
536 P(d, "exp", "((QFileInfo*)" << d.data << ")->lastRead()");
537 P(d, "type", "QDateTime");
538 P(d, "numchild", "1");
539 d.endHash();
540#endif
541
542 d << "]";
543 }
544 d.disarm();
545}
546
547static void qDumpQDateTime(QDumper &d)
548{
549#ifdef QT_NO_DATESTRING
550 qDumpUnknown(d);
551#else
552 const QDateTime &date = *reinterpret_cast<const QDateTime *>(d.data);
553 P(d, "iname", d.iname);
554 P(d, "addr", d.data);
555 P(d, "value", date.toString());
556 P(d, "type", "QDateTime");
557 P(d, "numchild", "3");
558 if (d.dumpChildren) {
559 d << ",children=[";
560 BL(d, "isNull", date.isNull());
561 I(d, "toTime_t", (long)date.toTime_t());
562 S(d, "toString", date.toString());
563 S(d, "toString_(ISO)", date.toString(Qt::ISODate));
564 S(d, "toString_(SystemLocale)", date.toString(Qt::SystemLocaleDate));
565 S(d, "toString_(Locale)", date.toString(Qt::LocaleDate));
566 S(d, "toString", date.toString());
567
568 d.beginHash();
569 P(d, "name", "toUTC");
570 P(d, "exp", "((QDateTime*)" << d.data << ")->toTimeSpec(Qt::UTC)");
571 P(d, "type", "QDateTime");
572 P(d, "numchild", "1");
573 d.endHash();
574
575 d.beginHash();
576 P(d, "name", "toLocalTime");
577 P(d, "exp", "((QDateTime*)" << d.data << ")->toTimeSpec(Qt::LocalTime)");
578 P(d, "type", "QDateTime");
579 P(d, "numchild", "1");
580 d.endHash();
581
582 d << "]";
583 }
584 d.disarm();
585#endif // ifdef QT_NO_DATESTRING
586}
587
588static void qDumpQString(QDumper &d)
589{
590 const QString &str = *reinterpret_cast<const QString *>(d.data);
591
592 // Try to provoke segfaults early to prevent the frontend
593 // from asking for unavailable child details
594 if (!str.isEmpty()) {
595 volatile ushort dummy = 0;
596 dummy += str.at(0).unicode();
597 dummy += str.at(str.size() - 1).unicode();
598 }
599
600 P(d, "iname", d.iname);
601 P(d, "addr", d.data);
602 P(d, "value", str);
603 P(d, "type", "QString");
604 P(d, "numchild", "0");
605 d.disarm();
606}
607
608static void qDumpQStringList(QDumper &d)
609{
610 const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
611 int n = list.size();
612 if (n < 0)
613 qProvokeSegFault();
614 if (n > 0) {
615 qCheckAccess(&list.front());
616 qCheckAccess(&list.back());
617 }
618
619 P(d, "iname", d.iname);
620 P(d, "addr", d.data);
621 P(d, "value", "<" << n << " items>");
622 P(d, "valuedisabled", "true");
623 P(d, "numchild", n);
624 if (d.dumpChildren) {
625 if (n > 100)
626 n = 100;
627 d << ",children=[";
628 for (int i = 0; i != n; ++i) {
629 S(d, "[" << i << "]", list[i]);
630 }
631 if (n < list.size()) {
632 d.beginHash();
633 P(d, "value", "<incomplete>");
634 P(d, "type", " ");
635 P(d, "numchild", "0");
636 d.endHash();
637 }
638 d << "]";
639 }
640 d.disarm();
641}
642
643static void qDumpQVariantHelper(const void *data, QString *value,
644 QString *exp, int *numchild)
645{
646 const QVariant &v = *reinterpret_cast<const QVariant *>(data);
647 switch (v.type()) {
648 case QVariant::Invalid:
649 *value = QLatin1String("<invalid>");
650 *numchild = 0;
651 break;
652 case QVariant::String:
653 *value = QLatin1Char('"') + v.toString() + QLatin1Char('"');
654 *numchild = 0;
655 break;
656 case QVariant::StringList:
657 *exp = QString(QLatin1String("((QVariant*)%1)->d.data.c"))
658 .arg((qulonglong)data);
659 *numchild = v.toStringList().size();
660 break;
661 case QVariant::Int:
662 *value = QString::number(v.toInt());
663 *numchild= 0;
664 break;
665 case QVariant::Double:
666 *value = QString::number(v.toDouble());
667 *numchild = 0;
668 break;
669 default:
670 // FIXME
671 //*exp = QString("qVariantValue<" << v.typeName() << ">"
672 // << "(*(QVariant*)" << data << ")");
673 break;
674 }
675}
676
677static void qDumpQVariant(QDumper &d)
678{
679 const QVariant &v = *reinterpret_cast<const QVariant *>(d.data);
680 QString value;
681 QString exp;
682 int numchild = 0;
683 qDumpQVariantHelper(d.data, &value, &exp, &numchild);
684 P(d, "iname", d.iname);
685 P(d, "addr", d.data);
686 P(d, "value", "(" << v.typeName() << ") " << qPrintable(value));
687 P(d, "type", "QVariant");
688 P(d, "numchild", 1);
689 if (d.dumpChildren) {
690 d << ",children=[";
691 d.beginHash();
692 P(d, "name", "value");
693 if (!exp.isEmpty())
694 P(d, "exp", qPrintable(exp));
695 if (!value.isEmpty())
696 P(d, "value", qPrintable(value));
697 P(d, "type", v.typeName());
698 P(d, "numchild", numchild);
699 d.endHash();
700 d << "]";
701 }
702 d.disarm();
703}
704
705static void qDumpQList(QDumper &d)
706{
707 // This uses the knowledge that QList<T> has only a single member
708 // of type union { QListData p; QListData::Data *d; };
709 const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
710 const QListData::Data *pdata = *reinterpret_cast<const QListData::Data* const*>(d.data);
711 int nn = ldata.size();
712 if (nn < 0)
713 qProvokeSegFault();
714 if (nn > 0) {
715 qCheckAccess(ldata.d->array);
716 //qCheckAccess(ldata.d->array[0]);
717 //qCheckAccess(ldata.d->array[nn - 1]);
718 }
719
720 int n = nn;
721 P(d, "iname", d.iname);
722 P(d, "value", "<" << n << " items>");
723 P(d, "valuedisabled", "true");
724 P(d, "numchild", n);
725 if (d.dumpChildren) {
726 if (n > 100)
727 n = 100;
728 d << ",children=[";
729 for (int i = 0; i != n; ++i) {
730 d.beginHash();
731 P(d, "name", "[" << i << "]");
732 // The exact condition here is:
733 // QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic
734 // but this data is not available in the compiled binary.
735 // So as first approximation only do the 'isLarge' check:
736 void *p = &(ldata.d->array[i + pdata->begin]);
737 unsigned long voidpsize = sizeof(void*);
738 P(d, "exp", "(sizeof(" << d.innertype << ")>" << voidpsize <<
739 "?(**(" << d.innertype << "**)(" << p << "))"
740 ":(*(" << d.innertype << "*)(" << p << ")))");
741 P(d, "type", d.innertype);
742 d.endHash();
743 }
744 if (n < nn) {
745 d << ",{";
746 P(d, "value", "<incomplete>");
747 d.endHash();
748 }
749 d << "]";
750 }
751 d.disarm();
752}
753
754static void qDumpQVector(QDumper &d)
755{
756 // Use 'int' as representative value. No way (and no need)
757 // to deduce proper type here.
758 const QVector<int> &vec = *reinterpret_cast<const QVector<int> *>(d.data);
759 const int nn = vec.size();
760
761 // Try to provoke segfaults early to prevent the frontend
762 // from asking for unavailable child details
763 if (nn < 0)
764 qProvokeSegFault();
765 if (nn > 0) {
766 qCheckAccess(&vec.front());
767 qCheckAccess(&vec.back());
768 }
769
770 //int innersize = 0;
771 //scanf(qDumpInBuffer, "%d", &innersize);
772
773 int n = nn;
774 P(d, "iname", d.iname);
775 P(d, "addr", d.data);
776 P(d, "value", "<" << n << " items>");
777 P(d, "valuedisabled", "true");
778 P(d, "numchild", n);
779 if (d.dumpChildren) {
780 if (n > 100)
781 n = 100;
782 d << ",children=[";
783 for (int i = 0; i != n; ++i) {
784 if (i)
785 d << ",";
786 d.beginHash();
787 P(d, "name", "[" << i << "]");
788 P(d, "exp", "(" << d.exp << ".d->array[" << i << "])");
789 P(d, "type", d.innertype);
790 d.endHash();
791 }
792 if (n < nn) {
793 d << ",{";
794 P(d, "value", "<incomplete>");
795 d.endHash();
796 }
797 d << "]";
798 }
799 d.disarm();
800}
801
802static void qDumpQHashNode(QDumper &d)
803{
804 struct NodeOS { void *next; uint k; uint v; } nodeOS; // int-key optimization, small value
805 struct NodeOL { void *next; uint k; void *v; } nodeOL; // int-key optimiatzion, large value
806 struct NodeNS { void *next; uint h; uint k; uint v; } nodeNS; // no optimization, small value
807 struct NodeNL { void *next; uint h; uint k; void *v; } nodeNL; // no optimization, large value
808 struct NodeL { void *next; uint h; void *k; void *v; } nodeL; // complex key
809
810 // offsetof(...,...) not yet in Standard C++
811 const ulong nodeOSk ( (char *)&nodeOS.k - (char *)&nodeOS );
812 const ulong nodeOSv ( (char *)&nodeOS.v - (char *)&nodeOS );
813 const ulong nodeOLk ( (char *)&nodeOL.k - (char *)&nodeOL );
814 const ulong nodeOLv ( (char *)&nodeOL.v - (char *)&nodeOL );
815 const ulong nodeNSk ( (char *)&nodeNS.k - (char *)&nodeNS );
816 const ulong nodeNSv ( (char *)&nodeNS.v - (char *)&nodeNS );
817 const ulong nodeNLk ( (char *)&nodeNL.k - (char *)&nodeNL );
818 const ulong nodeNLv ( (char *)&nodeNL.v - (char *)&nodeNL );
819 const ulong nodeLk ( (char *)&nodeL.k - (char *)&nodeL );
820 const ulong nodeLv ( (char *)&nodeL.v - (char *)&nodeL );
821
822 const QHashData *h = reinterpret_cast<const QHashData *>(d.data);
823 const char *keyType = d.templateParameters[0];
824 const char *valueType = d.templateParameters[1];
825
826 P(d, "iname", d.iname);
827 P(d, "addr", d.data);
828 P(d, "value", "");
829 P(d, "numchild", 2);
830 if (d.dumpChildren) {
831 // there is a hash specialization in cast the key are integers or shorts
832 bool isOptimizedIntKey = qstrcmp(keyType, "int") == 0
833#if defined(Q_BYTE_ORDER) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
834 || qstrcmp(keyType, "short") == 0
835 || qstrcmp(keyType, "ushort") == 0
836#endif
837 || qstrcmp(keyType, "uint") == 0;
838
839 d << ",children=[";
840 d.beginHash();
841 P(d, "name", "key");
842 P(d, "type", keyType);
843 unsigned long intsize = sizeof(int);
844 if (isOptimizedIntKey) {
845 P(d, "exp", "*(" << keyType << "*)"
846 "(((sizeof(" << valueType << ")>" << intsize << ")?"
847 << nodeOLk << ":" << nodeOSk <<
848 ")+(char*)" << h << ")");
849 } else {
850 P(d, "exp", "*(" << keyType << "*)"
851 "(((sizeof(" << keyType << ")>" << intsize << ")?"
852 << nodeLk << ":"
853 "((sizeof(" << valueType << ")>" << intsize << ")?"
854 << nodeNLk << ":" << nodeNSk << "))+(char*)" << h << ")");
855 }
856 d.endHash();
857 d.beginHash();
858 P(d, "name", "value");
859 P(d, "type", valueType);
860 if (isOptimizedIntKey) {
861 P(d, "exp", "*(" << valueType << "*)"
862 "(((sizeof(" << valueType << ")>" << intsize << ")?"
863 << nodeOLv << ":" << nodeOSv << ")+(char*)" << h << ")");
864 } else {
865 P(d, "exp", "*(" << valueType << "*)"
866 "(((sizeof(" << keyType << ")>" << intsize << ")?" << nodeLv << ":"
867 "((sizeof(" << valueType << ")>" << intsize << ")?"
868 << nodeNLv << ":" << nodeNSv << "))+(char*)" << h << ")");
869 }
870 d.endHash();
871 d << "]";
872 }
873 d.disarm();
874}
875
876static void qDumpQHash(QDumper &d)
877{
878 QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
879 const char *keyType = d.templateParameters[0];
880 const char *valueType = d.templateParameters[1];
881
882 qCheckPointer(h->fakeNext);
883 qCheckPointer(h->buckets);
884
885 int n = h->size;
886
887 if (n < 0)
888 qProvokeSegFault();
889 if (n > 0) {
890 qCheckPointer(h->fakeNext);
891 qCheckPointer(*h->buckets);
892 }
893
894 P(d, "iname", d.iname);
895 P(d, "addr", d.data);
896 P(d, "value", "<" << n << " items>");
897 P(d, "numchild", n);
898 if (d.dumpChildren) {
899 if (n > 100)
900 n = 100;
901 d << ",children=[";
902
903 QHashData::Node *node = h->firstNode();
904 QHashData::Node *end = reinterpret_cast<QHashData::Node *>(h);
905 int i = 0;
906
907 while (node != end) {
908 d.beginHash();
909 P(d, "name", "[" << i << "]");
910 P(d, "type", "QHashNode<" << keyType << "," << valueType << " >");
911 P(d, "exp", "*(QHashNode<" << keyType << "," << valueType << " >*)" << node);
912 d.endHash();
913
914 ++i;
915 node = QHashData::nextNode(node);
916 }
917 d << "]";
918 }
919 d.disarm();
920}
921
922static void qDumpQMapNode(QDumper &d)
923{
924 const QMapData *h = reinterpret_cast<const QMapData *>(d.data);
925 const char *keyType = d.templateParameters[0];
926 const char *valueType = d.templateParameters[1];
927
928 qCheckAccess(h->backward);
929 qCheckAccess(h->forward[0]);
930
931 P(d, "iname", d.iname);
932 P(d, "addr", d.data);
933 P(d, "value", "");
934 P(d, "numchild", 2);
935 if (d.dumpChildren) {
936 unsigned long voidpsize = sizeof(void*);
937 d << ",children=[";
938 d.beginHash();
939 P(d, "name", "key");
940 P(d, "type", keyType);
941 P(d, "exp", "*(" << keyType << "*)"
942 << "("
943 << 2 * voidpsize
944 << "-sizeof('QMap<" << keyType << "," << valueType << ">::Node')"
945 << "+(char*)" << h
946 << ")");
947 d.endHash();
948 d.beginHash();
949 P(d, "name", "value");
950 P(d, "type", valueType);
951 P(d, "exp", "*(" << valueType << "*)"
952 << "("
953 << "(size_t)&(('QMap<" << keyType << "," << valueType << ">::Node'*)0)->value"
954 << "+" << 2 * voidpsize
955 << "-sizeof('QMap<" << keyType << "," << valueType << ">::Node')"
956 << "+(char*)" << h
957 << ")");
958 d.endHash();
959 d << "]";
960 }
961
962 d.disarm();
963}
964
965static void qDumpQMap(QDumper &d)
966{
967 QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
968 const char *keyType = d.templateParameters[0];
969 const char *valueType = d.templateParameters[1];
970
971 int n = h->size;
972
973 if (n < 0)
974 qProvokeSegFault();
975 if (n > 0) {
976 qCheckAccess(h->backward);
977 qCheckAccess(h->forward[0]);
978 qCheckPointer(h->backward->backward);
979 qCheckPointer(h->forward[0]->backward);
980 }
981
982 P(d, "iname", d.iname);
983 P(d, "addr", d.data);
984 P(d, "value", "<" << n << " items>");
985 P(d, "numchild", n);
986 if (d.dumpChildren) {
987 if (n > 100)
988 n = 100;
989 d << ",children=[";
990
991 QMapData::Node *node = reinterpret_cast<QMapData::Node *>(h->forward[0]);
992 QMapData::Node *end = reinterpret_cast<QMapData::Node *>(h);
993 int i = 0;
994
995 while (node != end) {
996 d.beginHash();
997 P(d, "name", "[" << i << "]");
998 P(d, "type", "QMap<" << keyType << "," << valueType << ">::Node");
999 P(d, "exp", "*('QMap<" << keyType << "," << valueType << ">::Node'*)" << node);
1000 d.endHash();
1001
1002 ++i;
1003 node = node->forward[0];
1004 }
1005 d << "]";
1006 }
1007
1008 d.disarm();
1009}
1010
1011static void qDumpQSet(QDumper &d)
1012{
1013 // This uses the knowledge that QHash<T> has only a single member
1014 // of union { QHashData *d; QHashNode<Key, T> *e; };
1015 QHashData *hd = *(QHashData**)d.data;
1016 QHashData::Node *node = hd->firstNode();
1017
1018 int n = hd->size;
1019 if (n < 0)
1020 qProvokeSegFault();
1021 if (n > 0) {
1022 qCheckAccess(node);
1023 qCheckPointer(node->next);
1024 }
1025
1026 P(d, "iname", d.iname);
1027 P(d, "addr", d.data);
1028 P(d, "value", "<" << n << " items>");
1029 P(d, "valuedisabled", "true");
1030 P(d, "numchild", 2 * n);
1031 if (d.dumpChildren) {
1032 if (n > 100)
1033 n = 100;
1034 d << ",children=[";
1035 int i = 0;
1036 for (int bucket = 0; bucket != hd->numBuckets; ++bucket) {
1037 for (node = hd->buckets[bucket]; node->next; node = node->next) {
1038 d.beginHash();
1039 P(d, "name", "[" << i << "]");
1040 P(d, "type", d.innertype);
1041 P(d, "exp", "(('QHashNode<" << d.innertype
1042 << ",QHashDummyValue>'*)"
1043 << static_cast<const void*>(node) << ")->key"
1044 );
1045 d.endHash();
1046 ++i;
1047 }
1048 }
1049 d << "]";
1050 }
1051 d.disarm();
1052}
1053
1054static void handleProtocolVersion2(QDumper & d)
1055{
1056 if (!d.outertype[0]) {
1057 qDumpUnknown(d);
1058 return;
1059 }
1060
1061 d.setupTemplateParameters();
1062 // d.outertype[0] is usally 'Q', so don't use it
1063 switch (d.outertype[1]) {
1064 case 'D':
1065 if (qstrcmp(d.outertype, "QDateTime") == 0)
1066 qDumpQDateTime(d);
1067 else if (qstrcmp(d.outertype, "QDir") == 0)
1068 qDumpQDir(d);
1069 break;
1070 case 'F':
1071 if (qstrcmp(d.outertype, "QFileInfo") == 0)
1072 qDumpQFileInfo(d);
1073 break;
1074 case 'H':
1075 if (qstrcmp(d.outertype, "QHash") == 0)
1076 qDumpQHash(d);
1077 else if (qstrcmp(d.outertype, "QHashNode") == 0)
1078 qDumpQHashNode(d);
1079 break;
1080 case 'L':
1081 if (qstrcmp(d.outertype, "QList") == 0)
1082 qDumpQList(d);
1083 break;
1084 case 'M':
1085 if (qstrcmp(d.outertype, "QMap") == 0)
1086 qDumpQMap(d);
1087 else if (qstrcmp(d.outertype, "QMap::Node") == 0)
1088 qDumpQMapNode(d);
1089 break;
1090 case 'O':
1091 if (qstrcmp(d.outertype, "QObject") == 0)
1092 qDumpQObject(d);
1093 break;
1094 case 'P':
1095 if (qstrcmp(d.outertype, "QPropertyList") == 0)
1096 qDumpQPropertyList(d);
1097 break;
1098 case 'S':
1099 if (qstrcmp(d.outertype, "QSet") == 0)
1100 qDumpQSet(d);
1101 else if (qstrcmp(d.outertype, "QString") == 0)
1102 qDumpQString(d);
1103 else if (qstrcmp(d.outertype, "QStringList") == 0)
1104 qDumpQStringList(d);
1105 break;
1106 case 'V':
1107 if (qstrcmp(d.outertype, "QVariant") == 0)
1108 qDumpQVariant(d);
1109 else if (qstrcmp(d.outertype, "QVector") == 0)
1110 qDumpQVector(d);
1111 break;
1112 }
1113
1114 if (!d.success)
1115 qDumpUnknown(d);
1116}
1117
1118} // anonymous namespace
1119
1120
1121extern "C" Q_CORE_EXPORT void qDumpObjectData(
1122 int protocolVersion,
1123 int token,
1124 const char *outertype,
1125 const char *iname,
1126 const char *exp,
1127 const char *innertype,
1128 const void *data,
1129 bool dumpChildren)
1130{
1131 if (protocolVersion == 1) {
1132 // used to test whether error output gets through
1133 //fprintf(stderr, "using stderr, qDebug follows: %d\n", token);
1134 //qDebug() << "using qDebug, stderr already used: " << token;
1135 }
1136
1137 else if (protocolVersion == 2) {
1138 QDumper d;
1139 d.protocolVersion = protocolVersion;
1140 d.token = token;
1141 d.outertype = outertype ? outertype : "";
1142 d.iname = iname ? iname : "";
1143 d.exp = exp ? exp : "";
1144 d.innertype = innertype ? innertype : "";
1145 d.data = data ? data : "";
1146 d.dumpChildren = dumpChildren;
1147 handleProtocolVersion2(d);
1148 }
1149
1150 else {
1151 qDebug() << "Unsupported protocol version" << protocolVersion;
1152 }
1153}
1154
1155QT_END_NAMESPACE
1156
1157#endif // !Q_OS_WINCE && !QT_NO_QDUMPER
Note: See TracBrowser for help on using the repository browser.