Commit 72a18377 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Initial work on dumpers for CDB.

Add dumper calls, parser etc. Catch crashes
in the dumper functions.
parent 3cb783f7
...@@ -60,6 +60,10 @@ int qtGhVersion = QT_VERSION; ...@@ -60,6 +60,10 @@ int qtGhVersion = QT_VERSION;
# include <QtGui/QImage> # include <QtGui/QImage>
#endif #endif
#ifdef Q_OS_WIN
# include <windows.h>
#endif
#include <list> #include <list>
#include <map> #include <map>
#include <string> #include <string>
...@@ -231,11 +235,17 @@ static QByteArray stripPointerType(QByteArray type) ...@@ -231,11 +235,17 @@ static QByteArray stripPointerType(QByteArray type)
} }
// This is used to abort evaluation of custom data dumpers in a "coordinated" // This is used to abort evaluation of custom data dumpers in a "coordinated"
// way. Abortion will happen anyway when we try to access a non-initialized // way. Abortion will happen at the latest when we try to access a non-initialized
// non-trivial object, so there is no way to prevent this from occuring at all // non-trivial object, so there is no way to prevent this from occuring at all
// conceptionally. Gdb will catch SIGSEGV and return to the calling frame. // conceptionally. Ideally, if there is API to check memory access, it should
// This is just fine provided we only _read_ memory in the custom handlers // be used to terminate nicely, especially with CDB.
// below. // 1) Gdb will catch SIGSEGV and return to the calling frame.
// This is just fine provided we only _read_ memory in the custom handlers
// below.
// 2) For MSVC/CDB, exceptions must be handled in the dumper, which is
// achieved using __try/__except. The exception will be reported in the
// debugger, which will then execute a 'gN' command, passing handling back
// to the __except clause.
volatile int qProvokeSegFaultHelper; volatile int qProvokeSegFaultHelper;
...@@ -269,11 +279,16 @@ static bool startsWith(const char *s, const char *t) ...@@ -269,11 +279,16 @@ static bool startsWith(const char *s, const char *t)
return qstrncmp(s, t, qstrlen(t)) == 0; return qstrncmp(s, t, qstrlen(t)) == 0;
} }
// provoke segfault when address is not readable // Check memory for read access and provoke segfault if nothing else helps.
#define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0) // On Windows, try to be less crash-prone by checking memory using WinAPI
#define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
// provoke segfault unconditionally #ifdef Q_OS_WIN
#define qCheck(b) do { if (!(b)) qProvokeSegFaultHelper = *(char*)0; } while (0) # define qCheckAccess(d) if (IsBadReadPtr(d, 1)) return false; do { qProvokeSegFaultHelper = *(char*)d; } while (0)
# define qCheckPointer(d) if (d && IsBadReadPtr(d, 1)) return false; do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
#else
# define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0)
# define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
#endif
const char *stripNamespace(const char *type) const char *stripNamespace(const char *type)
{ {
...@@ -692,11 +707,14 @@ void QDumper::putEllipsis() ...@@ -692,11 +707,14 @@ void QDumper::putEllipsis()
#define TT(type, value) \ #define TT(type, value) \
"<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>" "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>"
static void qDumpUnknown(QDumper &d) #define DUMPUNKNOWN_MESSAGE "<internal error>"
static void qDumpUnknown(QDumper &d, const char *why = 0)
{ {
P(d, "iname", d.iname); P(d, "iname", d.iname);
P(d, "addr", d.data); P(d, "addr", d.data);
P(d, "value", "<internal error>"); if (!why)
why = DUMPUNKNOWN_MESSAGE;
P(d, "value", why);
P(d, "type", d.outertype); P(d, "type", d.outertype);
P(d, "numchild", "0"); P(d, "numchild", "0");
d.disarm(); d.disarm();
...@@ -815,7 +833,7 @@ static void qDumpInnerValueOrPointer(QDumper &d, ...@@ -815,7 +833,7 @@ static void qDumpInnerValueOrPointer(QDumper &d,
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static void qDumpQByteArray(QDumper &d) static bool qDumpQByteArray(QDumper &d)
{ {
const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data); const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data);
...@@ -848,6 +866,7 @@ static void qDumpQByteArray(QDumper &d) ...@@ -848,6 +866,7 @@ static void qDumpQByteArray(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQDateTime(QDumper &d) static void qDumpQDateTime(QDumper &d)
...@@ -1063,7 +1082,7 @@ int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned val ...@@ -1063,7 +1082,7 @@ int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned val
} }
static void qDumpQHash(QDumper &d) static bool qDumpQHash(QDumper &d)
{ {
QHashData *h = *reinterpret_cast<QHashData *const*>(d.data); QHashData *h = *reinterpret_cast<QHashData *const*>(d.data);
const char *keyType = d.templateParameters[0]; const char *keyType = d.templateParameters[0];
...@@ -1078,7 +1097,7 @@ static void qDumpQHash(QDumper &d) ...@@ -1078,7 +1097,7 @@ static void qDumpQHash(QDumper &d)
int n = h->size; int n = h->size;
if (n < 0) if (n < 0)
qCheck(false); return false;
if (n > 0) { if (n > 0) {
qCheckPointer(h->fakeNext); qCheckPointer(h->fakeNext);
qCheckPointer(*h->buckets); qCheckPointer(*h->buckets);
...@@ -1127,6 +1146,7 @@ static void qDumpQHash(QDumper &d) ...@@ -1127,6 +1146,7 @@ static void qDumpQHash(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQHashNode(QDumper &d) static void qDumpQHashNode(QDumper &d)
...@@ -1177,23 +1197,25 @@ static void qDumpQImage(QDumper &d) ...@@ -1177,23 +1197,25 @@ static void qDumpQImage(QDumper &d)
#endif #endif
} }
static void qDumpQList(QDumper &d) static bool qDumpQList(QDumper &d)
{ {
// This uses the knowledge that QList<T> has only a single member // This uses the knowledge that QList<T> has only a single member
// of type union { QListData p; QListData::Data *d; }; // of type union { QListData p; QListData::Data *d; };
const QListData &ldata = *reinterpret_cast<const QListData*>(d.data); const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
const QListData::Data *pdata = const QListData::Data *pdata =
*reinterpret_cast<const QListData::Data* const*>(d.data); *reinterpret_cast<const QListData::Data* const*>(d.data);
qCheckAccess(pdata);
int nn = ldata.size(); int nn = ldata.size();
if (nn < 0) if (nn < 0)
qCheck(false); return false;
if (nn > 0) { if (nn > 0) {
qCheckAccess(ldata.d->array); qCheckAccess(ldata.d->array);
//qCheckAccess(ldata.d->array[0]); //qCheckAccess(ldata.d->array[0]);
//qCheckAccess(ldata.d->array[nn - 1]); //qCheckAccess(ldata.d->array[nn - 1]);
#if QT_VERSION >= 0x040400 #if QT_VERSION >= 0x040400
if (ldata.d->ref._q_value <= 0) if (ldata.d->ref._q_value <= 0)
qCheck(false); return false;
#endif #endif
} }
...@@ -1252,9 +1274,10 @@ static void qDumpQList(QDumper &d) ...@@ -1252,9 +1274,10 @@ static void qDumpQList(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQLinkedList(QDumper &d) static bool qDumpQLinkedList(QDumper &d)
{ {
// This uses the knowledge that QLinkedList<T> has only a single member // This uses the knowledge that QLinkedList<T> has only a single member
// of type union { QLinkedListData *d; QLinkedListNode<T> *e; }; // of type union { QLinkedListData *d; QLinkedListNode<T> *e; };
...@@ -1262,7 +1285,7 @@ static void qDumpQLinkedList(QDumper &d) ...@@ -1262,7 +1285,7 @@ static void qDumpQLinkedList(QDumper &d)
reinterpret_cast<const QLinkedListData*>(deref(d.data)); reinterpret_cast<const QLinkedListData*>(deref(d.data));
int nn = ldata->size; int nn = ldata->size;
if (nn < 0) if (nn < 0)
qCheck(false); return false;
int n = nn; int n = nn;
P(d, "value", "<" << n << " items>"); P(d, "value", "<" << n << " items>");
...@@ -1294,6 +1317,7 @@ static void qDumpQLinkedList(QDumper &d) ...@@ -1294,6 +1317,7 @@ static void qDumpQLinkedList(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQLocale(QDumper &d) static void qDumpQLocale(QDumper &d)
...@@ -1341,7 +1365,7 @@ static void qDumpQLocale(QDumper &d) ...@@ -1341,7 +1365,7 @@ static void qDumpQLocale(QDumper &d)
d.disarm(); d.disarm();
} }
static void qDumpQMapNode(QDumper &d) static bool qDumpQMapNode(QDumper &d)
{ {
const QMapData *h = reinterpret_cast<const QMapData *>(d.data); const QMapData *h = reinterpret_cast<const QMapData *>(d.data);
const char *keyType = d.templateParameters[0]; const char *keyType = d.templateParameters[0];
...@@ -1375,9 +1399,10 @@ static void qDumpQMapNode(QDumper &d) ...@@ -1375,9 +1399,10 @@ static void qDumpQMapNode(QDumper &d)
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQMap(QDumper &d) static bool qDumpQMap(QDumper &d)
{ {
QMapData *h = *reinterpret_cast<QMapData *const*>(d.data); QMapData *h = *reinterpret_cast<QMapData *const*>(d.data);
const char *keyType = d.templateParameters[0]; const char *keyType = d.templateParameters[0];
...@@ -1386,7 +1411,7 @@ static void qDumpQMap(QDumper &d) ...@@ -1386,7 +1411,7 @@ static void qDumpQMap(QDumper &d)
int n = h->size; int n = h->size;
if (n < 0) if (n < 0)
qCheck(false); return false;
if (n > 0) { if (n > 0) {
qCheckAccess(h->backward); qCheckAccess(h->backward);
qCheckAccess(h->forward[0]); qCheckAccess(h->forward[0]);
...@@ -1455,11 +1480,12 @@ static void qDumpQMap(QDumper &d) ...@@ -1455,11 +1480,12 @@ static void qDumpQMap(QDumper &d)
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQMultiMap(QDumper &d) static bool qDumpQMultiMap(QDumper &d)
{ {
qDumpQMap(d); return qDumpQMap(d);
} }
static void qDumpQModelIndex(QDumper &d) static void qDumpQModelIndex(QDumper &d)
...@@ -1890,7 +1916,7 @@ static void qDumpQPixmap(QDumper &d) ...@@ -1890,7 +1916,7 @@ static void qDumpQPixmap(QDumper &d)
#endif #endif
} }
static void qDumpQSet(QDumper &d) static bool qDumpQSet(QDumper &d)
{ {
// This uses the knowledge that QHash<T> has only a single member // This uses the knowledge that QHash<T> has only a single member
// of union { QHashData *d; QHashNode<Key, T> *e; }; // of union { QHashData *d; QHashNode<Key, T> *e; };
...@@ -1899,7 +1925,7 @@ static void qDumpQSet(QDumper &d) ...@@ -1899,7 +1925,7 @@ static void qDumpQSet(QDumper &d)
int n = hd->size; int n = hd->size;
if (n < 0) if (n < 0)
qCheck(false); return false;
if (n > 0) { if (n > 0) {
qCheckAccess(node); qCheckAccess(node);
qCheckPointer(node->next); qCheckPointer(node->next);
...@@ -1933,6 +1959,7 @@ static void qDumpQSet(QDumper &d) ...@@ -1933,6 +1959,7 @@ static void qDumpQSet(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQSharedPointer(QDumper &d) static void qDumpQSharedPointer(QDumper &d)
...@@ -1959,7 +1986,7 @@ static void qDumpQSharedPointer(QDumper &d) ...@@ -1959,7 +1986,7 @@ static void qDumpQSharedPointer(QDumper &d)
d.disarm(); d.disarm();
} }
static void qDumpQString(QDumper &d) static bool qDumpQString(QDumper &d)
{ {
const QString &str = *reinterpret_cast<const QString *>(d.data); const QString &str = *reinterpret_cast<const QString *>(d.data);
...@@ -1975,14 +2002,15 @@ static void qDumpQString(QDumper &d) ...@@ -1975,14 +2002,15 @@ static void qDumpQString(QDumper &d)
P(d, "numchild", "0"); P(d, "numchild", "0");
d.disarm(); d.disarm();
return true;
} }
static void qDumpQStringList(QDumper &d) static bool qDumpQStringList(QDumper &d)
{ {
const QStringList &list = *reinterpret_cast<const QStringList *>(d.data); const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
int n = list.size(); int n = list.size();
if (n < 0) if (n < 0)
qCheck(false); return false;
if (n > 0) { if (n > 0) {
qCheckAccess(&list.front()); qCheckAccess(&list.front());
qCheckAccess(&list.back()); qCheckAccess(&list.back());
...@@ -2009,6 +2037,7 @@ static void qDumpQStringList(QDumper &d) ...@@ -2009,6 +2037,7 @@ static void qDumpQStringList(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpQTextCodec(QDumper &d) static void qDumpQTextCodec(QDumper &d)
...@@ -2109,7 +2138,7 @@ static void qDumpQVariant(QDumper &d) ...@@ -2109,7 +2138,7 @@ static void qDumpQVariant(QDumper &d)
d.disarm(); d.disarm();
} }
static void qDumpQVector(QDumper &d) static bool qDumpQVector(QDumper &d)
{ {
QVectorData *v = *reinterpret_cast<QVectorData *const*>(d.data); QVectorData *v = *reinterpret_cast<QVectorData *const*>(d.data);
...@@ -2117,7 +2146,7 @@ static void qDumpQVector(QDumper &d) ...@@ -2117,7 +2146,7 @@ static void qDumpQVector(QDumper &d)
// from asking for unavailable child details // from asking for unavailable child details
int nn = v->size; int nn = v->size;
if (nn < 0) if (nn < 0)
qCheck(false); return false;
if (nn > 0) { if (nn > 0) {
//qCheckAccess(&vec.front()); //qCheckAccess(&vec.front());
//qCheckAccess(&vec.back()); //qCheckAccess(&vec.back());
...@@ -2149,9 +2178,10 @@ static void qDumpQVector(QDumper &d) ...@@ -2149,9 +2178,10 @@ static void qDumpQVector(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpStdList(QDumper &d) static bool qDumpStdList(QDumper &d)
{ {
const std::list<int> &list = *reinterpret_cast<const std::list<int> *>(d.data); const std::list<int> &list = *reinterpret_cast<const std::list<int> *>(d.data);
const void *p = d.data; const void *p = d.data;
...@@ -2196,9 +2226,10 @@ static void qDumpStdList(QDumper &d) ...@@ -2196,9 +2226,10 @@ static void qDumpStdList(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpStdMap(QDumper &d) static bool qDumpStdMap(QDumper &d)
{ {
typedef std::map<int, int> DummyType; typedef std::map<int, int> DummyType;
const DummyType &map = *reinterpret_cast<const DummyType*>(d.data); const DummyType &map = *reinterpret_cast<const DummyType*>(d.data);
...@@ -2209,7 +2240,8 @@ static void qDumpStdMap(QDumper &d) ...@@ -2209,7 +2240,8 @@ static void qDumpStdMap(QDumper &d)
p = deref(p); p = deref(p);
int nn = map.size(); int nn = map.size();
qCheck(nn >= 0); if (nn < 0)
return false;
DummyType::const_iterator it = map.begin(); DummyType::const_iterator it = map.begin();
for (int i = 0; i < nn && i < 10 && it != map.end(); ++i, ++it) for (int i = 0; i < nn && i < 10 && it != map.end(); ++i, ++it)
qCheckAccess(it.operator->()); qCheckAccess(it.operator->());
...@@ -2263,9 +2295,10 @@ static void qDumpStdMap(QDumper &d) ...@@ -2263,9 +2295,10 @@ static void qDumpStdMap(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpStdSet(QDumper &d) static bool qDumpStdSet(QDumper &d)
{ {
typedef std::set<int> DummyType; typedef std::set<int> DummyType;
const DummyType &set = *reinterpret_cast<const DummyType*>(d.data); const DummyType &set = *reinterpret_cast<const DummyType*>(d.data);
...@@ -2274,7 +2307,8 @@ static void qDumpStdSet(QDumper &d) ...@@ -2274,7 +2307,8 @@ static void qDumpStdSet(QDumper &d)
p = deref(p); p = deref(p);
int nn = set.size(); int nn = set.size();
qCheck(nn >= 0); if (nn < 0)
return false;
DummyType::const_iterator it = set.begin(); DummyType::const_iterator it = set.begin();
for (int i = 0; i < nn && i < 10 && it != set.end(); ++i, ++it) for (int i = 0; i < nn && i < 10 && it != set.end(); ++i, ++it)
qCheckAccess(it.operator->()); qCheckAccess(it.operator->());
...@@ -2306,9 +2340,10 @@ static void qDumpStdSet(QDumper &d) ...@@ -2306,9 +2340,10 @@ static void qDumpStdSet(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpStdString(QDumper &d) static bool qDumpStdString(QDumper &d)
{ {
const std::string &str = *reinterpret_cast<const std::string *>(d.data); const std::string &str = *reinterpret_cast<const std::string *>(d.data);
...@@ -2325,9 +2360,10 @@ static void qDumpStdString(QDumper &d) ...@@ -2325,9 +2360,10 @@ static void qDumpStdString(QDumper &d)
P(d, "numchild", "0"); P(d, "numchild", "0");
d.disarm(); d.disarm();
return true;
} }
static void qDumpStdWString(QDumper &d) static bool qDumpStdWString(QDumper &d)
{ {
const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data); const std::wstring &str = *reinterpret_cast<const std::wstring *>(d.data);
...@@ -2344,9 +2380,10 @@ static void qDumpStdWString(QDumper &d) ...@@ -2344,9 +2380,10 @@ static void qDumpStdWString(QDumper &d)
P(d, "numchild", "0"); P(d, "numchild", "0");
d.disarm(); d.disarm();
return true;
} }
static void qDumpStdVector(QDumper &d) static bool qDumpStdVector(QDumper &d)
{ {
// Correct type would be something like: // Correct type would be something like:
// std::_Vector_base<int,std::allocator<int, std::allocator<int> >>::_Vector_impl // std::_Vector_base<int,std::allocator<int, std::allocator<int> >>::_Vector_impl
...@@ -2361,7 +2398,7 @@ static void qDumpStdVector(QDumper &d) ...@@ -2361,7 +2398,7 @@ static void qDumpStdVector(QDumper &d)
// from asking for unavailable child details // from asking for unavailable child details
int nn = (v->finish - v->start) / d.extraInt[0]; int nn = (v->finish - v->start) / d.extraInt[0];
if (nn < 0) if (nn < 0)
qCheck(false); return false;
if (nn > 0) { if (nn > 0) {
qCheckAccess(v->start); qCheckAccess(v->start);
qCheckAccess(v->finish); qCheckAccess(v->finish);
...@@ -2392,9 +2429,10 @@ static void qDumpStdVector(QDumper &d) ...@@ -2392,9 +2429,10 @@ static void qDumpStdVector(QDumper &d)
d << "]"; d << "]";
} }
d.disarm(); d.disarm();
return true;
} }
static void qDumpStdVectorBool(QDumper &d) static bool qDumpStdVectorBool(QDumper &d)
{ {
// FIXME // FIXME
return qDumpStdVector(d); return qDumpStdVector(d);
...@@ -2402,10 +2440,14 @@ static void qDumpStdVectorBool(QDumper &d) ...@@ -2402,10 +2440,14 @@ static void qDumpStdVectorBool(QDumper &d)
static void handleProtocolVersion2and3(QDumper & d) static void handleProtocolVersion2and3(QDumper & d)
{ {
if (!d.outertype[0]) { if (!d.outertype[0]) {
qDumpUnknown(d); qDumpUnknown(d);