diff --git a/src/plugins/debugger/cdb/coreengine.cpp b/src/plugins/debugger/cdb/coreengine.cpp index 324d470831f96c312bf8eceebc780f8b74c446f5..f00c4bf317583361ee6efb1f7f1a97d4069df484 100644 --- a/src/plugins/debugger/cdb/coreengine.cpp +++ b/src/plugins/debugger/cdb/coreengine.cpp @@ -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 */) { diff --git a/src/plugins/debugger/cdb/coreengine.h b/src/plugins/debugger/cdb/coreengine.h index c73fc7e72da3aa97297f7dea895ff62025bd1aac..c6e25e9cedeb2ffc71e092388721534c6def82eb 100644 --- a/src/plugins/debugger/cdb/coreengine.h +++ b/src/plugins/debugger/cdb/coreengine.h @@ -168,6 +168,9 @@ signals: // feature of the engine. void modulesLoaded(); +public slots: + void outputVersion(); + protected: virtual void timerEvent(QTimerEvent* te); diff --git a/tests/manual/ccdb/cdbapplication.cpp b/tests/manual/ccdb/cdbapplication.cpp index 8a2ad87451c72a5132ea4d59a288cb26a8bbe4d4..9e2d0e180472b0b35b2758521b325dd05c38426a 100644 --- a/tests/manual/ccdb/cdbapplication.cpp +++ b/tests/manual/ccdb/cdbapplication.cpp @@ -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)); diff --git a/tests/manual/ccdb/cdbapplication.h b/tests/manual/ccdb/cdbapplication.h index 11063795d8ae1819a8a343d09279bc4ef474e8e6..8d68e6414e6f8fc76812a6382b336f56e6587e95 100644 --- a/tests/manual/ccdb/cdbapplication.h +++ b/tests/manual/ccdb/cdbapplication.h @@ -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; diff --git a/tests/manual/ccdb/cdbpromptthread.cpp b/tests/manual/ccdb/cdbpromptthread.cpp index 1ade3331d7f9b4127c12671b26cc810e79d7592c..c0b01c47891c4d38883ac19aad063f18f0c18826 100644 --- a/tests/manual/ccdb/cdbpromptthread.cpp +++ b/tests/manual/ccdb/cdbpromptthread.cpp @@ -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; diff --git a/tests/manual/ccdb/cdbpromptthread.h b/tests/manual/ccdb/cdbpromptthread.h index 295f26e07f1173a4a63f89e50f754ad894d4de39..4851f079bcac309c57d9059f5e8ccd88a2f4777b 100644 --- a/tests/manual/ccdb/cdbpromptthread.h +++ b/tests/manual/ccdb/cdbpromptthread.h @@ -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