forked from qt-creator/qt-creator
Compile CCDB manual test.
This commit is contained in:
@@ -830,6 +830,11 @@ quint64 CoreEngine::getSourceLineAddress(const QString &file,
|
||||
return rc;
|
||||
}
|
||||
|
||||
void CoreEngine::outputVersion()
|
||||
{
|
||||
m_cif.debugControl->OutputVersionInformation(DEBUG_OUTCTL_ALL_CLIENTS);
|
||||
}
|
||||
|
||||
bool CoreEngine::autoDetectPath(QString *outPath,
|
||||
QStringList *checkedDirectories /* = 0 */)
|
||||
{
|
||||
|
||||
@@ -168,6 +168,9 @@ signals:
|
||||
// feature of the engine.
|
||||
void modulesLoaded();
|
||||
|
||||
public slots:
|
||||
void outputVersion();
|
||||
|
||||
protected:
|
||||
virtual void timerEvent(QTimerEvent* te);
|
||||
|
||||
|
||||
@@ -34,17 +34,18 @@
|
||||
#include "debugeventcallback.h"
|
||||
#include "symbolgroupcontext.h"
|
||||
#include "stacktracecontext.h"
|
||||
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
|
||||
const char usage[] =
|
||||
"CDB command line test tool\n\n"
|
||||
"ccdb <Options>\n"
|
||||
"Options: -p engine path\n";
|
||||
"Options: -p engine path\n"
|
||||
" -c initial_command_file\n";
|
||||
|
||||
class PrintfOutputHandler : public CdbCore::DebugOutputBase
|
||||
{
|
||||
@@ -72,7 +73,8 @@ CdbApplication::~CdbApplication()
|
||||
|
||||
CdbApplication::InitResult CdbApplication::init()
|
||||
{
|
||||
if (!parseOptions()) {
|
||||
FILE *inputFile;
|
||||
if (!parseOptions(&inputFile)) {
|
||||
printf(usage);
|
||||
return InitUsageShown;
|
||||
}
|
||||
@@ -91,7 +93,7 @@ CdbApplication::InitResult CdbApplication::init()
|
||||
connect(m_engine.data(), SIGNAL(watchTimerDebugEvent()), this, SLOT(debugEvent()));
|
||||
std::printf("Succeded.\n");
|
||||
// Prompt
|
||||
m_promptThread = new CdbPromptThread(this);
|
||||
m_promptThread = new CdbPromptThread(inputFile, this);
|
||||
connect(m_promptThread, SIGNAL(finished()), this, SLOT(promptThreadTerminated()));
|
||||
connect(m_promptThread, SIGNAL(asyncCommand(int,QString)),
|
||||
this, SLOT(asyncCommand(int,QString)), Qt::QueuedConnection);
|
||||
@@ -99,7 +101,8 @@ CdbApplication::InitResult CdbApplication::init()
|
||||
this, SLOT(syncCommand(int,QString)), Qt::BlockingQueuedConnection);
|
||||
connect(m_promptThread, SIGNAL(executionCommand(int,QString)),
|
||||
this, SLOT(executionCommand(int,QString)), Qt::BlockingQueuedConnection);
|
||||
|
||||
connect(m_engine.data(), SIGNAL(watchTimerDebugEvent()), m_promptThread, SLOT(notifyDebugEvent()),
|
||||
Qt::QueuedConnection);
|
||||
m_promptThread->start();
|
||||
return InitOk;
|
||||
}
|
||||
@@ -113,23 +116,41 @@ void CdbApplication::promptThreadTerminated()
|
||||
quit();
|
||||
}
|
||||
|
||||
bool CdbApplication::parseOptions()
|
||||
bool CdbApplication::parseOptions(FILE **inputFile)
|
||||
{
|
||||
*inputFile = NULL;
|
||||
const QStringList args = QCoreApplication::arguments();
|
||||
const QStringList::const_iterator cend = args.constEnd();
|
||||
QStringList::const_iterator it = args.constBegin();
|
||||
for (++it; it != cend ; ++it) {
|
||||
const QString &a = *it;
|
||||
if (a == QLatin1String("-p")) {
|
||||
++it;
|
||||
if (it == cend) {
|
||||
std::fprintf(stderr, "Option -p is missing an argument.\n");
|
||||
if (a.startsWith(QLatin1Char('-')) && a.size() >= 2) {
|
||||
switch (a.at(1).toAscii()) {
|
||||
case 'p':
|
||||
++it;
|
||||
if (it == cend) {
|
||||
std::fprintf(stderr, "Option -p is missing an argument.\n");
|
||||
return false;
|
||||
}
|
||||
m_engineDll = *it;
|
||||
break;
|
||||
case 'c':
|
||||
++it;
|
||||
if (it == cend) {
|
||||
std::fprintf(stderr, "Option -c is missing an argument.\n");
|
||||
return false;
|
||||
}
|
||||
*inputFile = std::fopen( it->toLocal8Bit().constData(), "r");
|
||||
if (*inputFile == NULL) {
|
||||
std::fprintf(stderr, "Cannot open %s: %s\n", qPrintable(*it), std::strerror(errno));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
std::fprintf(stderr, "Invalid option %s\n", qPrintable(a));
|
||||
return false;
|
||||
}
|
||||
m_engineDll = *it;
|
||||
} else {
|
||||
std::fprintf(stderr, "Invalid option %s\n", qPrintable(a));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -252,6 +273,11 @@ void CdbApplication::syncCommand(int command, const QString &arg)
|
||||
case Sync_PrintFrame:
|
||||
printFrame(arg);
|
||||
break;
|
||||
case Sync_OutputVersion:
|
||||
m_engine->outputVersion();
|
||||
break;
|
||||
case Sync_Python:
|
||||
break;
|
||||
case Unknown:
|
||||
std::printf("Executing '%s' in code level %d, syntax %d\n",
|
||||
qPrintable(arg), m_engine->codeLevel(), m_engine->expressionSyntax());
|
||||
@@ -286,7 +312,7 @@ void CdbApplication::executionCommand(int command, const QString &arg)
|
||||
}
|
||||
if (ok) {
|
||||
m_engine->startWatchTimer();
|
||||
m_stackTrace.reset();
|
||||
m_stackTrace = QSharedPointer<CdbCore::StackTraceContext>();
|
||||
} else {
|
||||
std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
|
||||
}
|
||||
@@ -297,11 +323,17 @@ void CdbApplication::debugEvent()
|
||||
QString errorMessage;
|
||||
std::printf("Debug event\n");
|
||||
|
||||
CdbCore::StackTraceContext::ThreadIdFrameMap threads;
|
||||
QVector<CdbCore::Thread> threads;
|
||||
QVector<CdbCore::StackFrame> threadFrames;
|
||||
ULONG currentThreadId;
|
||||
if (CdbCore::StackTraceContext::getThreads(m_engine->interfaces(), &threads,
|
||||
¤tThreadId, &errorMessage)) {
|
||||
printf("%s\n", qPrintable(CdbCore::StackTraceContext::formatThreads(threads)));
|
||||
|
||||
if (CdbCore::StackTraceContext::getThreadList(m_engine->interfaces(), &threads, ¤tThreadId, &errorMessage)
|
||||
&& CdbCore::StackTraceContext::getStoppedThreadFrames(m_engine->interfaces(), currentThreadId, threads, &threadFrames, &errorMessage)) {
|
||||
const int count = threadFrames.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
printf("Thread #%02d ID %10d SYSID %10d %s\n", i,
|
||||
threads.at(i).id, threads.at(i).systemId, qPrintable(threadFrames.at(i).toString()));
|
||||
}
|
||||
} else {
|
||||
std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
|
||||
}
|
||||
@@ -310,7 +342,7 @@ void CdbApplication::debugEvent()
|
||||
CdbCore::StackTraceContext::create(&m_engine->interfaces(),
|
||||
0xFFFF, &errorMessage);
|
||||
if (trace) {
|
||||
m_stackTrace.reset(trace);
|
||||
m_stackTrace = QSharedPointer<CdbCore::StackTraceContext>(trace);
|
||||
printf("%s\n", qPrintable(m_stackTrace->toString()));
|
||||
} else {
|
||||
std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#include <QtCore/QScopedPointer>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace CdbCore {
|
||||
class CoreEngine;
|
||||
class StackTraceContext;
|
||||
@@ -65,13 +67,13 @@ private slots:
|
||||
void processAttached(void *handle);
|
||||
|
||||
private:
|
||||
bool parseOptions();
|
||||
bool parseOptions(FILE **inputFile);
|
||||
void printFrame(const QString &arg);
|
||||
quint64 addQueuedBreakPoint(const QString &arg, QString *errorMessage);
|
||||
|
||||
QString m_engineDll;
|
||||
QSharedPointer<CdbCore::CoreEngine> m_engine;
|
||||
QScopedPointer<CdbCore::StackTraceContext> m_stackTrace;
|
||||
QSharedPointer<CdbCore::StackTraceContext> m_stackTrace;
|
||||
CdbPromptThread *m_promptThread;
|
||||
QStringList m_queuedCommands;
|
||||
QStringList m_queuedBreakPoints;
|
||||
|
||||
@@ -29,13 +29,12 @@
|
||||
|
||||
#include "cdbpromptthread.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
static const char help[] =
|
||||
"Special commands:\n\n"
|
||||
"H Display Help\n"
|
||||
"q Quit\n"
|
||||
"V Output version\n"
|
||||
"E expression Evaluate C++expression\n"
|
||||
"S binary args Start binary\n"
|
||||
"I Interrupt\n"
|
||||
@@ -46,11 +45,17 @@ static const char help[] =
|
||||
"B Clear breakpoint queue\n"
|
||||
"L List breakpoints\n"
|
||||
"F <n> Print stack frame <n>, 0 being top\n"
|
||||
"P <cmd> Run Python command\n"
|
||||
"W Synchronous wait for debug event\n"
|
||||
"\nThe remaining commands are passed to CDB.\n";
|
||||
|
||||
CdbPromptThread::CdbPromptThread(QObject *parent) :
|
||||
QThread(parent)
|
||||
CdbPromptThread::CdbPromptThread(FILE *file, QObject *parent) :
|
||||
QThread(parent),
|
||||
m_waitingForDebugEvent(false),
|
||||
m_inputFile(file)
|
||||
{
|
||||
if (!m_inputFile)
|
||||
m_inputFile = stdin;
|
||||
}
|
||||
|
||||
void CdbPromptThread::run()
|
||||
@@ -60,9 +65,17 @@ void CdbPromptThread::run()
|
||||
QString cmd;
|
||||
char buf[bufSize];
|
||||
std::putc('>', stdout);
|
||||
// When reading from an input file, switch to stdin after reading it out
|
||||
while (true) {
|
||||
if (std::fgets(buf, bufSize, stdin) == NULL)
|
||||
break;
|
||||
if (std::fgets(buf, bufSize, m_inputFile) == NULL) {
|
||||
if (m_inputFile == stdin) {
|
||||
break;
|
||||
} else {
|
||||
fclose(m_inputFile);
|
||||
m_inputFile = stdin;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cmd += QString::fromLatin1(buf);
|
||||
if (cmd.endsWith(QLatin1Char('\n'))) {
|
||||
cmd.truncate(cmd.size() - 1);
|
||||
@@ -72,6 +85,8 @@ void CdbPromptThread::run()
|
||||
}
|
||||
std::putc('>', stdout);
|
||||
}
|
||||
if (m_inputFile != stdin)
|
||||
fclose(m_inputFile);
|
||||
}
|
||||
|
||||
// Determine the command
|
||||
@@ -95,6 +110,12 @@ static Command evaluateCommand(const QString &cmdToken)
|
||||
return Execution_StartBinary;
|
||||
case 'F':
|
||||
return Sync_PrintFrame;
|
||||
case 'P':
|
||||
return Sync_Python;
|
||||
case 'V':
|
||||
return Sync_OutputVersion;
|
||||
case 'W':
|
||||
return WaitCommand;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -126,6 +147,12 @@ static Command parseCommand(QString *s)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void CdbPromptThread::notifyDebugEvent()
|
||||
{
|
||||
if (m_waitingForDebugEvent)
|
||||
m_debugEventWaitCondition.wakeAll();
|
||||
}
|
||||
|
||||
bool CdbPromptThread::handleCommand(QString cmd)
|
||||
{
|
||||
if (cmd == QLatin1String("q"))
|
||||
@@ -135,6 +162,16 @@ bool CdbPromptThread::handleCommand(QString cmd)
|
||||
return true;
|
||||
}
|
||||
const Command c = parseCommand(&cmd);
|
||||
if (c == WaitCommand) {
|
||||
std::fputs("Waiting for debug event\n", stdout);
|
||||
m_debugEventMutex.lock();
|
||||
m_waitingForDebugEvent = true;
|
||||
m_debugEventWaitCondition.wait(&m_debugEventMutex);
|
||||
m_debugEventMutex.unlock();
|
||||
std::fputs("Debug event received\n", stdout);
|
||||
m_waitingForDebugEvent = false;
|
||||
return true;
|
||||
}
|
||||
if (c & AsyncCommand) {
|
||||
emit asyncCommand(c, cmd);
|
||||
return true;
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#define PROMPTTHREAD_H
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QWaitCondition>
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
enum CommandTypeFlags {
|
||||
// Interrupt or something.
|
||||
@@ -51,18 +55,24 @@ enum Command {
|
||||
Sync_QueueBreakPoint = SyncCommand|3,
|
||||
Sync_ListBreakPoints = SyncCommand|4,
|
||||
Sync_PrintFrame = SyncCommand|5,
|
||||
Sync_OutputVersion = SyncCommand|6,
|
||||
Sync_Python = SyncCommand|7,
|
||||
Execution_Go = ExecutionCommand|1,
|
||||
Execution_StartBinary = ExecutionCommand|2
|
||||
Execution_StartBinary = ExecutionCommand|2,
|
||||
WaitCommand = 0xFFFF
|
||||
};
|
||||
|
||||
class CdbPromptThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CdbPromptThread(QObject *parent = 0);
|
||||
explicit CdbPromptThread(FILE *file, QObject *parent = 0);
|
||||
|
||||
virtual void run();
|
||||
|
||||
public slots:
|
||||
void notifyDebugEvent();
|
||||
|
||||
signals:
|
||||
void asyncCommand(int command, const QString &arg);
|
||||
void syncCommand(int command, const QString &arg);
|
||||
@@ -70,6 +80,10 @@ signals:
|
||||
|
||||
private:
|
||||
bool handleCommand(QString);
|
||||
QWaitCondition m_debugEventWaitCondition;
|
||||
QMutex m_debugEventMutex;
|
||||
bool m_waitingForDebugEvent;
|
||||
FILE *m_inputFile;
|
||||
};
|
||||
|
||||
#endif // PROMPTTHREAD_H
|
||||
|
||||
Reference in New Issue
Block a user