forked from qt-creator/qt-creator
debugger: work on autotests
This commit is contained in:
@@ -252,6 +252,7 @@ void GdbEngine::initializeVariables()
|
|||||||
m_debuggingHelperState = DebuggingHelperUninitialized;
|
m_debuggingHelperState = DebuggingHelperUninitialized;
|
||||||
m_gdbVersion = 100;
|
m_gdbVersion = 100;
|
||||||
m_gdbBuildVersion = -1;
|
m_gdbBuildVersion = -1;
|
||||||
|
m_isSynchroneous = false;
|
||||||
|
|
||||||
m_fullToShortName.clear();
|
m_fullToShortName.clear();
|
||||||
m_shortToFullName.clear();
|
m_shortToFullName.clear();
|
||||||
@@ -1310,6 +1311,16 @@ void GdbEngine::handleShowVersion(const GdbResponse &response)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GdbEngine::handleIsSynchroneous(const GdbResponse &response)
|
||||||
|
{
|
||||||
|
Q_UNUSED(response);
|
||||||
|
if (response.resultClass == GdbResultDone) {
|
||||||
|
m_isSynchroneous = true;
|
||||||
|
} else {
|
||||||
|
m_isSynchroneous = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GdbEngine::handleExecContinue(const GdbResponse &response)
|
void GdbEngine::handleExecContinue(const GdbResponse &response)
|
||||||
{
|
{
|
||||||
if (response.resultClass == GdbResultRunning) {
|
if (response.resultClass == GdbResultRunning) {
|
||||||
@@ -3247,7 +3258,7 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item,
|
|||||||
item.findChild("valuetooltipencoded").data().toInt());
|
item.findChild("valuetooltipencoded").data().toInt());
|
||||||
setWatchDataValueEnabled(data, item.findChild("valueenabled"));
|
setWatchDataValueEnabled(data, item.findChild("valueenabled"));
|
||||||
setWatchDataValueEditable(data, item.findChild("valueeditable"));
|
setWatchDataValueEditable(data, item.findChild("valueeditable"));
|
||||||
//qDebug() << "HANDLE CHILDREN: " << data.toString();
|
//qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n";
|
||||||
list->append(data);
|
list->append(data);
|
||||||
|
|
||||||
// try not to repeat data too often
|
// try not to repeat data too often
|
||||||
@@ -3370,7 +3381,6 @@ void GdbEngine::updateLocals()
|
|||||||
|
|
||||||
if (isSynchroneous()) {
|
if (isSynchroneous()) {
|
||||||
QStringList expanded = m_manager->watchHandler()->expandedINames().toList();
|
QStringList expanded = m_manager->watchHandler()->expandedINames().toList();
|
||||||
qDebug() << "EXPANDED: " << expanded;
|
|
||||||
postCommand(_("bb %1").arg(expanded.join(_(","))),
|
postCommand(_("bb %1").arg(expanded.join(_(","))),
|
||||||
WatchUpdate, CB(handleStackFrame1));
|
WatchUpdate, CB(handleStackFrame1));
|
||||||
postCommand(_("p 0"), WatchUpdate, CB(handleStackFrame2));
|
postCommand(_("p 0"), WatchUpdate, CB(handleStackFrame2));
|
||||||
@@ -3393,7 +3403,7 @@ void GdbEngine::handleStackFrame1(const GdbResponse &response)
|
|||||||
out.chop(1);
|
out.chop(1);
|
||||||
//qDebug() << "FIRST CHUNK: " << out;
|
//qDebug() << "FIRST CHUNK: " << out;
|
||||||
m_firstChunk = out;
|
m_firstChunk = out;
|
||||||
} else if (response.resultClass == GdbResultError) {
|
} else {
|
||||||
QTC_ASSERT(false, /**/);
|
QTC_ASSERT(false, /**/);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3406,24 +3416,25 @@ void GdbEngine::handleStackFrame2(const GdbResponse &response)
|
|||||||
out.chop(1);
|
out.chop(1);
|
||||||
//qDebug() << "SECOND CHUNK: " << out;
|
//qDebug() << "SECOND CHUNK: " << out;
|
||||||
out = m_firstChunk + out;
|
out = m_firstChunk + out;
|
||||||
// FIXME: Hack, make sure dumper does not return "{}"
|
|
||||||
out.replace(",{}", "");
|
|
||||||
GdbMi all("[" + out + "]");
|
GdbMi all("[" + out + "]");
|
||||||
qDebug() << "ALL: " << all.toString();
|
//GdbMi all(out);
|
||||||
QList<GdbMi> locals = all.children();
|
|
||||||
//manager()->watchHandler()->insertBulkData(locals);
|
//qDebug() << "\n\n\nALL: " << all.toString() << "\n";
|
||||||
//setLocals(locals);
|
GdbMi locals = all.findChild("locals");
|
||||||
|
//qDebug() << "\n\n\nLOCALS: " << locals.toString() << "\n";
|
||||||
WatchData *data = manager()->watchHandler()->findItem(_("local"));
|
WatchData *data = manager()->watchHandler()->findItem(_("local"));
|
||||||
QTC_ASSERT(data, return);
|
QTC_ASSERT(data, return);
|
||||||
|
|
||||||
QList<WatchData> list;
|
QList<WatchData> list;
|
||||||
foreach (const GdbMi &local, locals)
|
//foreach (const GdbMi &local, locals.children)
|
||||||
handleChildren(*data, local, &list);
|
// handleChildren(*data, local, &list);
|
||||||
|
handleChildren(*data, locals, &list);
|
||||||
|
//for (int i = 0; i != list.size(); ++i)
|
||||||
|
// qDebug() << "READ: " << list.at(i).toString();
|
||||||
manager()->watchHandler()->insertBulkData(list);
|
manager()->watchHandler()->insertBulkData(list);
|
||||||
|
|
||||||
manager()->watchHandler()->updateWatchers();
|
manager()->watchHandler()->updateWatchers();
|
||||||
} else if (response.resultClass == GdbResultError) {
|
} else {
|
||||||
QTC_ASSERT(false, /**/);
|
QTC_ASSERT(false, /**/);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4094,6 +4105,7 @@ void GdbEngine::handleAdapterStarted()
|
|||||||
debugMessage(_("ADAPTER SUCCESSFULLY STARTED, INITIALIZING GDB"));
|
debugMessage(_("ADAPTER SUCCESSFULLY STARTED, INITIALIZING GDB"));
|
||||||
|
|
||||||
postCommand(_("show version"), CB(handleShowVersion));
|
postCommand(_("show version"), CB(handleShowVersion));
|
||||||
|
postCommand(_("help bb"), CB(handleIsSynchroneous));
|
||||||
//postCommand(_("-enable-timings");
|
//postCommand(_("-enable-timings");
|
||||||
postCommand(_("set print static-members off")); // Seemingly doesn't work.
|
postCommand(_("set print static-members off")); // Seemingly doesn't work.
|
||||||
//postCommand(_("set debug infrun 1"));
|
//postCommand(_("set debug infrun 1"));
|
||||||
@@ -4253,7 +4265,7 @@ void GdbEngine::showMessageBox(int icon, const QString &title, const QString &te
|
|||||||
|
|
||||||
bool GdbEngine::isSynchroneous() const
|
bool GdbEngine::isSynchroneous() const
|
||||||
{
|
{
|
||||||
return false;
|
return m_isSynchroneous;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ private:
|
|||||||
void handleShowVersion(const GdbResponse &response);
|
void handleShowVersion(const GdbResponse &response);
|
||||||
void handleQuerySources(const GdbResponse &response);
|
void handleQuerySources(const GdbResponse &response);
|
||||||
void handleWatchPoint(const GdbResponse &response);
|
void handleWatchPoint(const GdbResponse &response);
|
||||||
|
void handleIsSynchroneous(const GdbResponse &response);
|
||||||
bool showToolTip();
|
bool showToolTip();
|
||||||
|
|
||||||
// Convenience
|
// Convenience
|
||||||
@@ -299,6 +300,7 @@ private:
|
|||||||
|
|
||||||
int m_gdbVersion; // 6.8.0 is 680
|
int m_gdbVersion; // 6.8.0 is 680
|
||||||
int m_gdbBuildVersion; // MAC only?
|
int m_gdbBuildVersion; // MAC only?
|
||||||
|
bool m_isSynchroneous; // Can act synchroneously?
|
||||||
|
|
||||||
// awful hack to keep track of used files
|
// awful hack to keep track of used files
|
||||||
QMap<QString, QString> m_shortToFullName;
|
QMap<QString, QString> m_shortToFullName;
|
||||||
|
|||||||
@@ -868,16 +868,21 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
|
|||||||
|
|
||||||
void WatchModel::insertData(const WatchData &data)
|
void WatchModel::insertData(const WatchData &data)
|
||||||
{
|
{
|
||||||
// qDebug() << "WMI:" << data.toString();
|
//qDebug() << "WMI:" << data.toString();
|
||||||
//static int bulk = 0;
|
//static int bulk = 0;
|
||||||
//qDebug() << "SINGLE: " << ++bulk << data.toString();
|
//qDebug() << "SINGLE: " << ++bulk << data.toString();
|
||||||
QTC_ASSERT(!data.iname.isEmpty(), return);
|
if (data.iname.isEmpty()) {
|
||||||
|
int x;
|
||||||
|
x = 1;
|
||||||
|
}
|
||||||
|
QTC_ASSERT(!data.iname.isEmpty(), qDebug() << data.toString(); return);
|
||||||
WatchItem *parent = findItem(parentName(data.iname), m_root);
|
WatchItem *parent = findItem(parentName(data.iname), m_root);
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
WatchData parent;
|
WatchData parent;
|
||||||
parent.iname = parentName(data.iname);
|
parent.iname = parentName(data.iname);
|
||||||
insertData(parent);
|
MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
|
||||||
//MODEL_DEBUG("\nFIXING MISSING PARENT FOR\n" << data.iname);
|
if (!parent.iname.isEmpty())
|
||||||
|
insertData(parent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QModelIndex index = watchIndex(parent);
|
QModelIndex index = watchIndex(parent);
|
||||||
@@ -1098,10 +1103,12 @@ void WatchHandler::insertData(const WatchData &data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data.isSomethingNeeded()) {
|
if (data.isSomethingNeeded()) {
|
||||||
|
MODEL_DEBUG("SOMETHING NEEDED: " << data.toString());
|
||||||
m_manager->updateWatchData(data);
|
m_manager->updateWatchData(data);
|
||||||
} else {
|
} else {
|
||||||
WatchModel *model = modelForIName(data.iname);
|
WatchModel *model = modelForIName(data.iname);
|
||||||
QTC_ASSERT(model, return);
|
QTC_ASSERT(model, return);
|
||||||
|
MODEL_DEBUG("NOTHING NEEDED: " << data.toString());
|
||||||
model->insertData(data);
|
model->insertData(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1372,7 +1379,7 @@ WatchModel *WatchHandler::modelForIName(const QString &iname) const
|
|||||||
return m_watchers;
|
return m_watchers;
|
||||||
if (iname.startsWith(QLatin1String("tooltip")))
|
if (iname.startsWith(QLatin1String("tooltip")))
|
||||||
return m_tooltips;
|
return m_tooltips;
|
||||||
QTC_ASSERT(false, /**/);
|
QTC_ASSERT(false, qDebug() << "INAME: " << iname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
#include <QtCore/private/qobject_p.h>
|
#include <QtCore/private/qobject_p.h>
|
||||||
|
|
||||||
#include <QtGui/QStandardItemModel>
|
//#include <QtGui/QStandardItemModel>
|
||||||
#include <QtGui/QStringListModel>
|
//#include <QtGui/QStringListModel>
|
||||||
|
|
||||||
#include <QtTest/QtTest>
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
@@ -29,6 +29,15 @@
|
|||||||
# define NSY ""
|
# define NSY ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//#define DO_DEBUG 1
|
||||||
|
#undef DEBUG
|
||||||
|
#if DO_DEBUG
|
||||||
|
# define DEBUG(s) qDebug() << s
|
||||||
|
#else
|
||||||
|
# define DEBUG(s)
|
||||||
|
#endif
|
||||||
|
#define DEBUGX(s) qDebug() << s
|
||||||
|
|
||||||
#define gettid() QString("0x%1").arg((qulonglong)(void *)currentThread(), 0, 16)
|
#define gettid() QString("0x%1").arg((qulonglong)(void *)currentThread(), 0, 16)
|
||||||
|
|
||||||
using namespace Debugger;
|
using namespace Debugger;
|
||||||
@@ -36,6 +45,7 @@ using namespace Debugger::Internal;
|
|||||||
|
|
||||||
typedef QList<QByteArray> QByteArrayList;
|
typedef QList<QByteArray> QByteArrayList;
|
||||||
|
|
||||||
|
#if 0
|
||||||
static QByteArray operator<<(QByteArray ba, const QByteArray &replacement)
|
static QByteArray operator<<(QByteArray ba, const QByteArray &replacement)
|
||||||
{
|
{
|
||||||
int pos = ba.indexOf('%');
|
int pos = ba.indexOf('%');
|
||||||
@@ -53,6 +63,7 @@ static QByteArray &operator<<=(QByteArray &ba, const QByteArray &replacement)
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline QByteArray N(T t) { return QByteArray::number(t); }
|
inline QByteArray N(T t) { return QByteArray::number(t); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -84,7 +95,7 @@ public slots:
|
|||||||
void handleGdbFinished(int, QProcess::ExitStatus);
|
void handleGdbFinished(int, QProcess::ExitStatus);
|
||||||
void writeToGdbRequested(const QByteArray &ba)
|
void writeToGdbRequested(const QByteArray &ba)
|
||||||
{
|
{
|
||||||
//qDebug() << "THREAD GDB IN: " << ba;
|
DEBUG("THREAD GDB IN: " << ba);
|
||||||
m_proc->write(ba);
|
m_proc->write(ba);
|
||||||
m_proc->write("\n");
|
m_proc->write("\n");
|
||||||
}
|
}
|
||||||
@@ -92,7 +103,8 @@ public slots:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
QByteArray m_output;
|
QByteArray m_output;
|
||||||
QByteArray m_error;
|
QByteArray m_lastStopped; // last seen "*stopped" message
|
||||||
|
int m_line; // line extracted from last "*stopped" message
|
||||||
QProcess *m_proc; // owned
|
QProcess *m_proc; // owned
|
||||||
tst_Gdb *m_test; // not owned
|
tst_Gdb *m_test; // not owned
|
||||||
};
|
};
|
||||||
@@ -102,10 +114,25 @@ class tst_Gdb : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tst_Gdb() : m_thread(this) {}
|
tst_Gdb();
|
||||||
|
|
||||||
|
void initTestCase() {}
|
||||||
|
void cleanupTestCase();
|
||||||
|
void prepare(const QByteArray &function);
|
||||||
|
void run(const QByteArray &label, const QByteArray &expected,
|
||||||
|
const QByteArray &expanded = QByteArray());
|
||||||
|
void next(int n = 1);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void writeToGdb(const QByteArray &ba);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void dumpQString();
|
||||||
|
void dumpQStringList();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void dumperCompatibility();
|
void dumperCompatibility();
|
||||||
|
#if 0
|
||||||
void dumpQAbstractItemAndModelIndex();
|
void dumpQAbstractItemAndModelIndex();
|
||||||
void dumpQAbstractItemModel();
|
void dumpQAbstractItemModel();
|
||||||
void dumpQByteArray();
|
void dumpQByteArray();
|
||||||
@@ -143,20 +170,10 @@ public slots:
|
|||||||
void dumpQVariant_QStringList();
|
void dumpQVariant_QStringList();
|
||||||
void dumpStdVector();
|
void dumpStdVector();
|
||||||
void dumpQWeakPointer();
|
void dumpQWeakPointer();
|
||||||
void initTestCase();
|
#endif
|
||||||
void cleanupTestCase();
|
|
||||||
void runTestCase(const QByteArray &name,
|
|
||||||
const QByteArray &type,
|
|
||||||
const QByteArrayList &expexted);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void writeToGdb(const QByteArray &ba);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void dumpQString();
|
|
||||||
void dumpQStringList();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#if 0
|
||||||
void dumpQAbstractItemHelper(QModelIndex &index);
|
void dumpQAbstractItemHelper(QModelIndex &index);
|
||||||
void dumpQAbstractItemModelHelper(QAbstractItemModel &m);
|
void dumpQAbstractItemModelHelper(QAbstractItemModel &m);
|
||||||
void dumpQDateTimeHelper(const QDateTime &d);
|
void dumpQDateTimeHelper(const QDateTime &d);
|
||||||
@@ -177,8 +194,11 @@ private:
|
|||||||
void dumpQWeakPointerHelper(QWeakPointer<T> &ptr);
|
void dumpQWeakPointerHelper(QWeakPointer<T> &ptr);
|
||||||
#endif
|
#endif
|
||||||
void dumpQTextCodecHelper(QTextCodec *codec);
|
void dumpQTextCodecHelper(QTextCodec *codec);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QHash<QByteArray, int> m_lineForLabel;
|
||||||
|
QByteArray m_function;
|
||||||
Thread m_thread;
|
Thread m_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -189,37 +209,6 @@ QWaitCondition m_waitCondition;
|
|||||||
// Dumpers
|
// Dumpers
|
||||||
//
|
//
|
||||||
|
|
||||||
static void testDumper(QByteArray expected, const void *data, QByteArray outertype,
|
|
||||||
bool dumpChildren, QByteArray actual____ = QByteArray(),
|
|
||||||
QByteArray = QByteArray(), int = 0, int = 0, int = 0, int = 0)
|
|
||||||
{
|
|
||||||
Q_UNUSED(dumpChildren);
|
|
||||||
expected = "locals={iname='local',name='Locals',value=' ',type=' ',"
|
|
||||||
"children=[" + expected + "],arg=''}";
|
|
||||||
char buf[100];
|
|
||||||
sprintf(buf, "%p", data);
|
|
||||||
//if ((!expected.startsWith('t') && !expected.startsWith('f'))
|
|
||||||
// || expected.startsWith("type"))
|
|
||||||
// expected = "tiname='$I',addr='$A'," + expected;
|
|
||||||
expected.replace("$I", "iname");
|
|
||||||
expected.replace("$T", QByteArray(outertype));
|
|
||||||
expected.replace("$A", QByteArray(buf));
|
|
||||||
if (actual____ != expected) {
|
|
||||||
QByteArrayList l1 = actual____.split(',');
|
|
||||||
QByteArrayList l2 = expected.split(',');
|
|
||||||
for (int i = 0; i < l1.size() && i < l2.size(); ++i) {
|
|
||||||
if (l1.at(i) == l2.at(i))
|
|
||||||
qWarning() << "== " << l1.at(i);
|
|
||||||
else
|
|
||||||
//qWarning() << "!= " << l1.at(i).right(30) << l2.at(i).right(30);
|
|
||||||
qWarning() << "!= " << l1.at(i) << l2.at(i);
|
|
||||||
}
|
|
||||||
if (l1.size() != l2.size())
|
|
||||||
qWarning() << "!= size: " << l1.size() << l2.size();
|
|
||||||
}
|
|
||||||
QCOMPARE(actual____, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray str(const void *p)
|
QByteArray str(const void *p)
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100];
|
||||||
@@ -227,10 +216,12 @@ QByteArray str(const void *p)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static const void *deref(const void *p)
|
static const void *deref(const void *p)
|
||||||
{
|
{
|
||||||
return *reinterpret_cast<const char* const*>(p);
|
return *reinterpret_cast<const char* const*>(p);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void tst_Gdb::dumperCompatibility()
|
void tst_Gdb::dumperCompatibility()
|
||||||
{
|
{
|
||||||
@@ -241,6 +232,7 @@ void tst_Gdb::dumperCompatibility()
|
|||||||
QCOMPARE(size_t(&v->array), qVectorDataSize);
|
QCOMPARE(size_t(&v->array), qVectorDataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static const QByteArray utfToBase64(const QString &string)
|
static const QByteArray utfToBase64(const QString &string)
|
||||||
{
|
{
|
||||||
return QByteArray(reinterpret_cast<const char *>(string.utf16()), 2 * string.size()).toBase64();
|
return QByteArray(reinterpret_cast<const char *>(string.utf16()), 2 * string.size()).toBase64();
|
||||||
@@ -396,6 +388,8 @@ void getMapNodeParams(size_t &nodeSize, size_t &valOffset)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
void tst_Gdb::dumpQAbstractItemHelper(QModelIndex &index)
|
void tst_Gdb::dumpQAbstractItemHelper(QModelIndex &index)
|
||||||
{
|
{
|
||||||
const QAbstractItemModel *model = index.model();
|
const QAbstractItemModel *model = index.model();
|
||||||
@@ -2134,6 +2128,7 @@ void tst_Gdb::dumpQWeakPointer()
|
|||||||
dumpQWeakPointerHelper(wpS);
|
dumpQWeakPointerHelper(wpS);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif // #if 0
|
||||||
|
|
||||||
#define VERIFY_OFFSETOF(member) \
|
#define VERIFY_OFFSETOF(member) \
|
||||||
do { \
|
do { \
|
||||||
@@ -2179,16 +2174,40 @@ void Thread::handleGdbFinished(int, QProcess::ExitStatus)
|
|||||||
void Thread::readStandardOutput()
|
void Thread::readStandardOutput()
|
||||||
{
|
{
|
||||||
QByteArray ba = m_proc->readAllStandardOutput();
|
QByteArray ba = m_proc->readAllStandardOutput();
|
||||||
if (ba.isEmpty())
|
//DEBUGX("THREAD GDB OUT: " << ba);
|
||||||
return;
|
|
||||||
// =library-loaded...
|
// =library-loaded...
|
||||||
if (ba.startsWith("="))
|
if (ba.startsWith("="))
|
||||||
return;
|
return;
|
||||||
//if (ba.startsWith("~"))
|
if (ba.startsWith("*stopped")) {
|
||||||
// return;
|
m_lastStopped = ba;
|
||||||
|
//qDebug() << "THREAD GDB OUT: " << ba;
|
||||||
|
if (!ba.contains("func=\"main\"")) {
|
||||||
|
int pos1 = ba.indexOf(",line=\"") + 7;
|
||||||
|
int pos2 = ba.indexOf("\"", pos1);
|
||||||
|
m_line = ba.mid(pos1, pos2 - pos1).toInt();
|
||||||
|
DEBUG(" LINE 1: " << m_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "call" is always aborted with a message like:
|
||||||
|
// "~"2321\t /* A */ QString s;\n" "
|
||||||
|
// "&"The program being debugged stopped while in a function called ..."
|
||||||
|
// "^error,msg="The program being debugged stopped ..."
|
||||||
|
// Extract the "2321" from this
|
||||||
|
static QByteArray lastText;
|
||||||
|
if (ba.startsWith("~"))
|
||||||
|
lastText = ba;
|
||||||
|
if (ba.startsWith("&\"The program being debugged")) {
|
||||||
|
int pos1 = 2;
|
||||||
|
int pos2 = lastText.indexOf("\\", pos1);
|
||||||
|
m_line = lastText.mid(pos1, pos2 - pos1).toInt();
|
||||||
|
DEBUG(" LINE 2: " << m_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ba.startsWith("~\"XXX: "))
|
||||||
|
qWarning() << "MESSAGE: " << ba.mid(7, ba.size() - 11);
|
||||||
if (!ba.startsWith("~\"locals="))
|
if (!ba.startsWith("~\"locals="))
|
||||||
return;
|
return;
|
||||||
//qDebug() << "THREAD GDB OUT: " << ba;
|
|
||||||
//m_output += ba;
|
//m_output += ba;
|
||||||
ba = ba.mid(2, ba.size() - 4);
|
ba = ba.mid(2, ba.size() - 4);
|
||||||
ba = ba.replace("\\\"", "\"");
|
ba = ba.replace("\\\"", "\"");
|
||||||
@@ -2198,11 +2217,8 @@ void Thread::readStandardOutput()
|
|||||||
|
|
||||||
void Thread::readStandardError()
|
void Thread::readStandardError()
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
QByteArray ba = m_proc->readAllStandardOutput();
|
QByteArray ba = m_proc->readAllStandardOutput();
|
||||||
qDebug() << "THREAD GDB ERR: " << ba;
|
qDebug() << "THREAD GDB ERR: " << ba;
|
||||||
m_error += ba;
|
|
||||||
m_waitCondition.wakeAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::handleGdbStarted()
|
void Thread::handleGdbStarted()
|
||||||
@@ -2215,44 +2231,98 @@ void Thread::run()
|
|||||||
//qDebug() << "\nTHREAD RUN" << getpid() << gettid();
|
//qDebug() << "\nTHREAD RUN" << getpid() << gettid();
|
||||||
m_proc->start("./gdb -i mi --args ./tst_gdb run");
|
m_proc->start("./gdb -i mi --args ./tst_gdb run");
|
||||||
m_proc->waitForStarted();
|
m_proc->waitForStarted();
|
||||||
m_proc->write("b main\n");
|
m_proc->write("break main\n");
|
||||||
m_proc->write("run\n");
|
m_proc->write("run\n");
|
||||||
m_proc->write("handle SIGSTOP stop pass\n");
|
m_proc->write("handle SIGSTOP stop pass\n");
|
||||||
//qDebug() << "\nTHREAD RUNNING";
|
//qDebug() << "\nTHREAD RUNNING";
|
||||||
exec();
|
exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Gdb::initTestCase()
|
tst_Gdb::tst_Gdb()
|
||||||
|
: m_thread(this)
|
||||||
{
|
{
|
||||||
// FIXME: Wait until gdb proc is running.
|
// FIXME: Wait until gdb proc is running.
|
||||||
QTest::qWait(1000);
|
QTest::qWait(300);
|
||||||
|
QFile file("tst_gdb.cpp");
|
||||||
|
Q_ASSERT(file.open(QIODevice::ReadOnly));
|
||||||
|
QByteArray funcName;
|
||||||
|
const QByteArrayList bal = file.readAll().split('\n');
|
||||||
|
Q_ASSERT(bal.size() > 100);
|
||||||
|
for (int i = 0; i != bal.size(); ++i) {
|
||||||
|
const QByteArray &ba = bal.at(i);
|
||||||
|
if (ba.startsWith("void dump")) {
|
||||||
|
int pos = ba.indexOf('(');
|
||||||
|
funcName = ba.mid(5, pos - 5) + '@';
|
||||||
|
} else if (ba.startsWith(" /*")) {
|
||||||
|
int pos = ba.indexOf('*', 7);
|
||||||
|
m_lineForLabel[funcName + ba.mid(7, pos - 8)] = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qWarning() << m_lineForLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void tst_Gdb::runTestCase(const QByteArray &name, const QByteArray &type,
|
void tst_Gdb::prepare(const QByteArray &function)
|
||||||
const QByteArrayList &expected)
|
|
||||||
{
|
{
|
||||||
//qDebug() << "\nABOUT TO RUN TEST: " << name << m_thread.m_proc;
|
m_function = function;
|
||||||
|
writeToGdb("b " + function);
|
||||||
|
writeToGdb("call " + function + "()");
|
||||||
|
}
|
||||||
|
|
||||||
writeToGdb("b " + name);
|
void tst_Gdb::run(const QByteArray &label,
|
||||||
|
const QByteArray &expected0, const QByteArray &expanded)
|
||||||
|
{
|
||||||
|
//qDebug() << "\nABOUT TO RUN TEST: " << function << m_thread.m_proc;
|
||||||
|
writeToGdb("bb " + expanded);
|
||||||
|
m_mutex.lock();
|
||||||
|
m_waitCondition.wait(&m_mutex);
|
||||||
|
QByteArray ba = m_thread.m_output;
|
||||||
|
m_mutex.unlock();
|
||||||
|
//GdbMi locals;
|
||||||
|
//locals.fromString("{" + ba + "}");
|
||||||
|
QByteArray received = ba.replace("\"", "'");
|
||||||
|
//qDebug() << "OUTPUT: " << ba << "\n\n";
|
||||||
|
//qDebug() << "OUTPUT: " << locals.toString() << "\n\n";
|
||||||
|
|
||||||
for (int i = 0; i != expected.size(); ++i) {
|
QByteArray actual____ = received;
|
||||||
if (i == 0)
|
QByteArray expected = "locals={iname='local',name='Locals',value=' ',type=' ',"
|
||||||
writeToGdb("call " + name + "()");
|
"children=[" + expected0 + "]}";
|
||||||
else
|
int line = m_thread.m_line;
|
||||||
writeToGdb("next");
|
if (actual____ != expected) {
|
||||||
writeToGdb("bb");
|
qWarning() << "LINE: " << line << "ACT/EXP";
|
||||||
m_mutex.lock();
|
QByteArrayList l1 = actual____.split(',');
|
||||||
m_waitCondition.wait(&m_mutex);
|
QByteArrayList l2 = expected.split(',');
|
||||||
QByteArray ba = m_thread.m_output;
|
int i = 0;
|
||||||
m_mutex.unlock();
|
for ( ; i < l1.size() && i < l2.size(); ++i) {
|
||||||
//GdbMi locals;
|
if (l1.at(i) == l2.at(i))
|
||||||
//locals.fromString("{" + ba + "}");
|
qWarning() << "== " << l1.at(i);
|
||||||
QByteArray received = ba.replace("\"", "'");
|
else
|
||||||
//qDebug() << "OUTPUT: " << ba << "\n\n";
|
//qWarning() << "!= " << l1.at(i).right(30) << l2.at(i).right(30);
|
||||||
//qDebug() << "OUTPUT: " << locals.toString() << "\n\n";
|
qWarning() << "!= " << l1.at(i) << l2.at(i);
|
||||||
testDumper(expected.at(i), 0, type, false, received);
|
}
|
||||||
|
for ( ; i < l2.size(); ++i)
|
||||||
|
qWarning() << "!= " << "-----" << l2.at(i);
|
||||||
|
for ( ; i < l1.size(); ++i)
|
||||||
|
qWarning() << "!= " << l1.at(i) << "-----";
|
||||||
|
if (l1.size() != l2.size())
|
||||||
|
qWarning() << "!= size: " << l1.size() << l2.size();
|
||||||
}
|
}
|
||||||
|
//qDebug() << "LABEL: " << m_function + '@' + label;
|
||||||
|
QCOMPARE(actual____, expected);
|
||||||
|
|
||||||
|
|
||||||
|
int expline = m_lineForLabel.value(m_function + '@' + label);
|
||||||
|
int actline = line;
|
||||||
|
if (actline != expline) {
|
||||||
|
qWarning() << "LAST STOPPED: " << m_thread.m_lastStopped;
|
||||||
|
}
|
||||||
|
QCOMPARE(actline, expline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_Gdb::next(int n)
|
||||||
|
{
|
||||||
|
for (int i = 0; i != n; ++i)
|
||||||
|
writeToGdb("next");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Gdb::cleanupTestCase()
|
void tst_Gdb::cleanupTestCase()
|
||||||
@@ -2264,47 +2334,44 @@ void tst_Gdb::cleanupTestCase()
|
|||||||
|
|
||||||
void dumpQStringTest()
|
void dumpQStringTest()
|
||||||
{
|
{
|
||||||
QString s;
|
/* A */ QString s;
|
||||||
s = "hallo";
|
/* B */ s = "hallo";
|
||||||
s += "x";
|
/* C */ s += "x";
|
||||||
s += "y";
|
/* D */ }
|
||||||
}
|
|
||||||
|
|
||||||
void tst_Gdb::dumpQString()
|
void tst_Gdb::dumpQString()
|
||||||
{
|
{
|
||||||
QByteArrayList bal;
|
prepare("dumpQStringTest");
|
||||||
|
run("A", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
|
||||||
bal.append("{iname='local.s',addr='0xbffff19c',name='S',"
|
"value='<not in scope>',numchild='0'}");
|
||||||
"type='"NS"QString',value='<not in scope>',numchild='0'}");
|
next();
|
||||||
|
run("B", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
|
||||||
//bal.append("xxx");
|
"valueencoded='7',value='',numchild='0'}");
|
||||||
//bal.append("xxx");
|
next();
|
||||||
runTestCase("dumpQStringTest", NS"QString", bal);
|
run("C", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
|
||||||
/*
|
"valueencoded='7',value='680061006c006c006f00',numchild='0'}");
|
||||||
testDumper("value='',valueencoded='2',type='$T',numchild='0'",
|
next();
|
||||||
&s, NS"QString", false);
|
run("D", "{iname='local.s',addr='0xbffff19c',name='s',type='"NS"QString',"
|
||||||
s = "abc";
|
"valueencoded='7',value='680061006c006c006f007800',numchild='0'}");
|
||||||
testDumper("value='YQBiAGMA',valueencoded='2',type='$T',numchild='0'",
|
|
||||||
&s, NS"QString", false);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpQStringListTest()
|
void dumpQStringListTest()
|
||||||
{
|
{
|
||||||
QStringList s;
|
/* A */ QStringList s;
|
||||||
|
/* B */ s.append("hello");
|
||||||
|
/* C */ s.append("world");
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_Gdb::dumpQStringList()
|
void tst_Gdb::dumpQStringList()
|
||||||
{
|
{
|
||||||
QByteArrayList bal;
|
prepare("dumpQStringListTest");
|
||||||
//bal.append("xxx");
|
run("A", "xxx");
|
||||||
runTestCase("dumpQStringListTest", NS"QStringList", bal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int runit(int &argc, char *argv[])
|
int runit(int &argc, char *argv[])
|
||||||
{
|
{
|
||||||
// Plain call. Start the testing.
|
// Plain call. Start the testing.
|
||||||
QApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
tst_Gdb test;
|
tst_Gdb test;
|
||||||
return QTest::qExec(&test, argc, argv);
|
return QTest::qExec(&test, argc, argv);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user