diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index e05614029c31d7c6c09d8b73d0086222bbfd7aa4..455c6e87095ca562cfa470fe656728544a7c267f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -500,7 +500,7 @@ void CMakeProject::setUserEnvironmentChanges(const QString &buildConfig, const Q QStringList list = EnvironmentItem::toStringList(diff); if (list == value(buildConfig, "userEnvironmentChanges")) return; - setValue(buildConfig, "userEnvironmentChanges", EnvironmentItem::toStringList(diff)); + setValue(buildConfig, "userEnvironmentChanges", list); emit environmentChanged(buildConfig); } diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 5bea06a0453c49e1ff3ef337382fd972c7cde7fb..597a2769e8508e50056fb98351715c610021c168 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -527,8 +527,6 @@ CPPEditorEditable::CPPEditorEditable(CPPEditor *editor) CPPEditor::CPPEditor(QWidget *parent) : TextEditor::BaseTextEditor(parent) - , m_mouseNavigationEnabled(true) - , m_showingLink(false) , m_currentRenameSelection(-1) , m_inRename(false) { @@ -1073,7 +1071,7 @@ void CPPEditor::switchDeclarationDefinition() } CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, - bool lookupDefinition) + bool resolveTarget) { Link link; @@ -1153,7 +1151,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, if (Symbol *symbol = result.second) { Symbol *def = 0; - if (lookupDefinition && !lastSymbol->isFunction()) + if (resolveTarget && !lastSymbol->isFunction()) def = findDefinition(symbol); link = linkToSymbol(def ? def : symbol); @@ -1190,7 +1188,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, void CPPEditor::jumpToDefinition() { - openCppEditorAt(findLinkAt(textCursor())); + openLink(findLinkAt(textCursor())); } Symbol *CPPEditor::findDefinition(Symbol *symbol) @@ -1342,68 +1340,6 @@ void CPPEditor::contextMenuEvent(QContextMenuEvent *e) delete menu; } -void CPPEditor::mouseMoveEvent(QMouseEvent *e) -{ - bool linkFound = false; - - if (m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier) { - // Link emulation behaviour for 'go to definition' - const QTextCursor cursor = cursorForPosition(e->pos()); - - // Check that the mouse was actually on the text somewhere - bool onText = cursorRect(cursor).right() >= e->x(); - if (!onText) { - QTextCursor nextPos = cursor; - nextPos.movePosition(QTextCursor::Right); - onText = cursorRect(nextPos).right() >= e->x(); - } - - const Link link = findLinkAt(cursor, false); - - if (onText && !link.fileName.isEmpty()) { - showLink(link); - linkFound = true; - } - } - - if (!linkFound) - clearLink(); - - TextEditor::BaseTextEditor::mouseMoveEvent(e); -} - -void CPPEditor::mouseReleaseEvent(QMouseEvent *e) -{ - if (m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier - && !(e->modifiers() & Qt::ShiftModifier) - && e->button() == Qt::LeftButton) { - - const QTextCursor cursor = cursorForPosition(e->pos()); - if (openCppEditorAt(findLinkAt(cursor))) { - clearLink(); - e->accept(); - return; - } - } - - TextEditor::BaseTextEditor::mouseReleaseEvent(e); -} - -void CPPEditor::leaveEvent(QEvent *e) -{ - clearLink(); - TextEditor::BaseTextEditor::leaveEvent(e); -} - -void CPPEditor::keyReleaseEvent(QKeyEvent *e) -{ - // Clear link emulation when Ctrl is released - if (e->key() == Qt::Key_Control) - clearLink(); - - TextEditor::BaseTextEditor::keyReleaseEvent(e); -} - void CPPEditor::keyPressEvent(QKeyEvent *e) { if (m_currentRenameSelection == -1) { @@ -1491,29 +1427,6 @@ void CPPEditor::keyPressEvent(QKeyEvent *e) TextEditor::BaseTextEditor::keyPressEvent(e); } -void CPPEditor::showLink(const Link &link) -{ - QTextEdit::ExtraSelection sel; - sel.cursor = textCursor(); - sel.cursor.setPosition(link.pos); - sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); - sel.format = m_linkFormat; - sel.format.setFontUnderline(true); - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel); - viewport()->setCursor(Qt::PointingHandCursor); - m_showingLink = true; -} - -void CPPEditor::clearLink() -{ - if (!m_showingLink) - return; - - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); - viewport()->setCursor(Qt::IBeamCursor); - m_showingLink = false; -} - QList<int> CPPEditorEditable::context() const { return m_context; @@ -1557,17 +1470,10 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs) highlighter->setFormats(formats.constBegin(), formats.constEnd()); highlighter->rehighlight(); - m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK)); m_occurrencesFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES)); m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME)); } -void CPPEditor::setDisplaySettings(const TextEditor::DisplaySettings &ds) -{ - TextEditor::BaseTextEditor::setDisplaySettings(ds); - m_mouseNavigationEnabled = ds.m_mouseNavigation; -} - void CPPEditor::unCommentSelection() { Core::Utils::unCommentSelection(this); diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 27991a550f3831ab4fac9e4c59501398fbabca6e..40e2e71972f22517d492875c3892b727b66a76ae 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -193,7 +193,6 @@ public: public Q_SLOTS: virtual void setFontSettings(const TextEditor::FontSettings &); - virtual void setDisplaySettings(const TextEditor::DisplaySettings &); void setSortedMethodOverview(bool sort); void switchDeclarationDefinition(); void jumpToDefinition(); @@ -208,10 +207,6 @@ public Q_SLOTS: protected: bool event(QEvent *e); void contextMenuEvent(QContextMenuEvent *); - void mouseMoveEvent(QMouseEvent *); - void mouseReleaseEvent(QMouseEvent *); - void leaveEvent(QEvent *); - void keyReleaseEvent(QKeyEvent *); void keyPressEvent(QKeyEvent *); TextEditor::BaseTextEditorEditable *createEditableInterface(); @@ -261,36 +256,11 @@ private: const QString &text = QString()); void abortRename(); - struct Link - { - Link(const QString &fileName = QString(), - int line = 0, - int column = 0) - : pos(-1) - , length(-1) - , fileName(fileName) - , line(line) - , column(column) - {} - - int pos; // Link position - int length; // Link length - - QString fileName; // Target file - int line; // Target line - int column; // Target column - }; - - void showLink(const Link &); - void clearLink(); - - Link findLinkAt(const QTextCursor &, bool lookupDefinition = true); - static Link linkToSymbol(CPlusPlus::Symbol *symbol); + Link findLinkAt(const QTextCursor &, bool resolveTarget = true); + bool openLink(const Link &link) { return openCppEditorAt(link); } bool openCppEditorAt(const Link &); - bool m_mouseNavigationEnabled; - bool m_showingLink; - QTextCharFormat m_linkFormat; + static Link linkToSymbol(CPlusPlus::Symbol *symbol); CppTools::CppModelManagerInterface *m_modelManager; diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp index 95e25b4b2573db244b2d9b9ff21975939026ac7c..d2cda6f77df79a7287db641d0b8fed866b0b5aac 100644 --- a/src/plugins/cppeditor/cpphighlighter.cpp +++ b/src/plugins/cppeditor/cpphighlighter.cpp @@ -73,6 +73,8 @@ void CppHighlighter::highlightBlock(const QString &text) userData->setCollapseMode(TextBlockUserData::NoCollapse); } TextEditDocumentLayout::clearParentheses(currentBlock()); + if (text.length()) // the empty line can still contain whitespace + setFormat(0, text.length(), visualSpaceFormat); return; } @@ -171,7 +173,7 @@ void CppHighlighter::highlightBlock(const QString &text) } // mark the trailing white spaces - if (! tokens.isEmpty()) { + { const SimpleToken tk = tokens.last(); const int lastTokenEnd = tk.position() + tk.length(); if (text.length() > lastTokenEnd) diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 3cdc4f16f56a132d7c188422dc9d60c1b9b3b46f..c9be97b726063195c1588819f6bd03e4fa669681 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -87,5 +87,7 @@ include(cdb/cdb.pri) include(gdb/gdb.pri) include(script/script.pri) include(tcf/tcf.pri) +include(symbian/symbian.pri) include(shared/shared.pri) + OTHER_FILES += Debugger.pluginspec diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index a17056ec1f865ba66c2f5031ea9e06e5c01c69b2..b4a5c84a7ee71c28a106aa8b3e200471d4a9c7ca 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -103,6 +103,8 @@ namespace Internal { IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *); +IDebuggerEngine *createSymbianEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *); + QDebug operator<<(QDebug str, const DebuggerStartParameters &p) { QDebug nospace = str.nospace(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 89669c9df5e23c42708b513c2320475794f03220..055d8adfdf21238a0b5b7526eb645f7e5110218a 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -144,7 +144,7 @@ static QByteArray parsePlainConsoleStream(const GdbResultRecord &record) // /////////////////////////////////////////////////////////////////////// -GdbEngine::GdbEngine(DebuggerManager *parent) : +GdbEngine::GdbEngine(DebuggerManager *parent, GdbProcessBase *gdbProc) : #ifdef Q_OS_WIN // Do injection loading with MinGW (call loading does not work with 64bit) m_dumperInjectionLoad(true), #else @@ -153,6 +153,7 @@ GdbEngine::GdbEngine(DebuggerManager *parent) : q(parent), qq(parent->engineInterface()) { + m_gdbProc = gdbProc; m_stubProc.setMode(Core::Utils::ConsoleProcess::Debug); #ifdef Q_OS_UNIX m_stubProc.setSettings(Core::ICore::instance()->settings()); @@ -164,19 +165,20 @@ GdbEngine::GdbEngine(DebuggerManager *parent) : GdbEngine::~GdbEngine() { // prevent sending error messages afterwards - m_gdbProc.disconnect(this); + m_gdbProc->disconnect(this); + delete m_gdbProc; } void GdbEngine::initializeConnections() { // Gdb Process interaction - connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)), + connect(m_gdbProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(gdbProcError(QProcess::ProcessError))); - connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), + connect(m_gdbProc, SIGNAL(readyReadStandardOutput()), this, SLOT(readGdbStandardOutput())); - connect(&m_gdbProc, SIGNAL(readyReadStandardError()), + connect(m_gdbProc, SIGNAL(readyReadStandardError()), this, SLOT(readGdbStandardError())); - connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), + connect(m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)), q, SLOT(exitDebugger())); connect(&m_stubProc, SIGNAL(processError(QString)), @@ -614,7 +616,7 @@ void GdbEngine::stubError(const QString &msg) void GdbEngine::readGdbStandardError() { - qWarning() << "Unexpected gdb stderr:" << m_gdbProc.readAllStandardError(); + qWarning() << "Unexpected gdb stderr:" << m_gdbProc->readAllStandardError(); } void GdbEngine::readGdbStandardOutput() @@ -622,7 +624,7 @@ void GdbEngine::readGdbStandardOutput() int newstart = 0; int scan = m_inbuffer.size(); - m_inbuffer.append(m_gdbProc.readAllStandardOutput()); + m_inbuffer.append(m_gdbProc->readAllStandardOutput()); while (newstart < m_inbuffer.size()) { int start = newstart; @@ -651,7 +653,7 @@ void GdbEngine::interruptInferior() { qq->notifyInferiorStopRequested(); - if (m_gdbProc.state() == QProcess::NotRunning) { + if (m_gdbProc->state() == QProcess::NotRunning) { debugMessage(_("TRYING TO INTERRUPT INFERIOR WITHOUT RUNNING GDB")); qq->notifyInferiorExited(); return; @@ -698,7 +700,7 @@ void GdbEngine::postCommand(const QString &command, GdbCommandFlags flags, GdbCommandCallback callback, const char *callbackName, const QVariant &cookie) { - if (m_gdbProc.state() == QProcess::NotRunning) { + if (m_gdbProc->state() == QProcess::NotRunning) { debugMessage(_("NO GDB PROCESS RUNNING, CMD IGNORED: ") + command); return; } @@ -742,7 +744,7 @@ void GdbEngine::flushCommand(GdbCommand &cmd) if (cmd.flags & EmbedToken) cmd.command = cmd.command.arg(currentToken()); - m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); + m_gdbProc->write(cmd.command.toLatin1() + "\r\n"); //emit gdbInputAvailable(QString(), " " + currentTime()); //emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); emit gdbInputAvailable(LogInput, cmd.command); @@ -829,12 +831,12 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record) void GdbEngine::executeDebuggerCommand(const QString &command) { - if (m_gdbProc.state() == QProcess::NotRunning) { + if (m_gdbProc->state() == QProcess::NotRunning) { debugMessage(_("NO GDB PROCESS RUNNING, PLAIN CMD IGNORED: ") + command); return; } - m_gdbProc.write(command.toLocal8Bit() + "\r\n"); + m_gdbProc->write(command.toLocal8Bit() + "\r\n"); } void GdbEngine::handleTargetCore(const GdbResultRecord &, const QVariant &) @@ -1434,15 +1436,15 @@ void GdbEngine::detachDebugger() void GdbEngine::exitDebugger() { - debugMessage(_("GDBENGINE EXITDEBUGGER: %1").arg(m_gdbProc.state())); - if (m_gdbProc.state() == QProcess::Starting) { + debugMessage(_("GDBENGINE EXITDEBUGGER: %1").arg(m_gdbProc->state())); + if (m_gdbProc->state() == QProcess::Starting) { debugMessage(_("WAITING FOR GDB STARTUP TO SHUTDOWN: %1") - .arg(m_gdbProc.state())); - m_gdbProc.waitForStarted(); + .arg(m_gdbProc->state())); + m_gdbProc->waitForStarted(); } - if (m_gdbProc.state() == QProcess::Running) { + if (m_gdbProc->state() == QProcess::Running) { debugMessage(_("WAITING FOR RUNNING GDB TO SHUTDOWN: %1") - .arg(m_gdbProc.state())); + .arg(m_gdbProc->state())); if (q->status() != DebuggerInferiorStopped && q->status() != DebuggerProcessStartingUp) { QTC_ASSERT(q->status() == DebuggerInferiorRunning, @@ -1455,17 +1457,17 @@ void GdbEngine::exitDebugger() postCommand(_("kill")); postCommand(_("-gdb-exit"), CB(handleExit)); // 20s can easily happen when loading webkit debug information - if (!m_gdbProc.waitForFinished(20000)) { + if (!m_gdbProc->waitForFinished(20000)) { debugMessage(_("FORCING TERMINATION: %1") - .arg(m_gdbProc.state())); - m_gdbProc.terminate(); - m_gdbProc.waitForFinished(20000); + .arg(m_gdbProc->state())); + m_gdbProc->terminate(); + m_gdbProc->waitForFinished(20000); } } - if (m_gdbProc.state() != QProcess::NotRunning) { + if (m_gdbProc->state() != QProcess::NotRunning) { debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1") - .arg(m_gdbProc.state())); - m_gdbProc.kill(); + .arg(m_gdbProc->state())); + m_gdbProc->kill(); } m_outputCollector.shutdown(); @@ -1487,9 +1489,9 @@ bool GdbEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) QStringList gdbArgs; - if (m_gdbProc.state() != QProcess::NotRunning) { - debugMessage(_("GDB IS ALREADY RUNNING, STATE: %1").arg(m_gdbProc.state())); - m_gdbProc.kill(); + if (m_gdbProc->state() != QProcess::NotRunning) { + debugMessage(_("GDB IS ALREADY RUNNING, STATE: %1").arg(m_gdbProc->state())); + m_gdbProc->kill(); return false; } @@ -1529,16 +1531,16 @@ bool GdbEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) gdbArgs.prepend(_("--tty=") + m_outputCollector.serverName()); if (!sp->workingDir.isEmpty()) - m_gdbProc.setWorkingDirectory(sp->workingDir); + m_gdbProc->setWorkingDirectory(sp->workingDir); if (!sp->environment.isEmpty()) - m_gdbProc.setEnvironment(sp->environment); + m_gdbProc->setEnvironment(sp->environment); } #if 0 qDebug() << "Command:" << q->settings()->m_gdbCmd; - qDebug() << "WorkingDirectory:" << m_gdbProc.workingDirectory(); + qDebug() << "WorkingDirectory:" << m_gdbProc->workingDirectory(); qDebug() << "ScriptFile:" << q->settings()->m_scriptFile; - qDebug() << "Environment:" << m_gdbProc.environment(); + qDebug() << "Environment:" << m_gdbProc->environment(); qDebug() << "Arguments:" << gdbArgs; qDebug() << "BuildDir:" << sp->buildDir; qDebug() << "ExeFile:" << sp->executable; @@ -1546,10 +1548,10 @@ bool GdbEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp) QString loc = theDebuggerStringSetting(GdbLocation); q->showStatusMessage(tr("Starting Debugger: ") + loc + _c(' ') + gdbArgs.join(_(" "))); - m_gdbProc.start(loc, gdbArgs); - if (!m_gdbProc.waitForStarted()) { + m_gdbProc->start(loc, gdbArgs); + if (!m_gdbProc->waitForStarted()) { QMessageBox::critical(q->mainWindow(), tr("Debugger Startup Failure"), - tr("Cannot start debugger: %1").arg(m_gdbProc.errorString())); + tr("Cannot start debugger: %1").arg(m_gdbProc->errorString())); m_outputCollector.shutdown(); m_stubProc.blockSignals(true); m_stubProc.stop(); @@ -4198,7 +4200,7 @@ void GdbEngine::handleFetchDisassemblerByAddress0(const GdbResultRecord &record, IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *opts) { opts->push_back(new GdbOptionsPage); - return new GdbEngine(parent); + return new GdbEngine(parent, new GdbProcess); } } // namespace Internal diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 2694ec01fbd8b182d8b5f2665365084f6e800f40..88eadb4c0953065dec8b8b44543920e86e111702 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -32,6 +32,7 @@ #include "idebuggerengine.h" #include "gdbmi.h" +#include "gdbprocessbase.h" #include "outputcollector.h" #include "watchutils.h" @@ -56,6 +57,7 @@ QT_END_NAMESPACE namespace Debugger { namespace Internal { + class DebuggerManager; class IDebuggerManagerAccessForEngines; class GdbResultRecord; @@ -72,13 +74,46 @@ enum DebuggingHelperState DebuggingHelperUnavailable, }; +class GdbProcess : public GdbProcessBase +{ +public: + GdbProcess(QObject *parent = 0) + : GdbProcessBase(parent) + { + connect(&m_proc, SIGNAL(error(QProcess::ProcessError)), + this, SIGNAL(error(QProcess::ProcessError))); + connect(&m_proc, SIGNAL(readyReadStandardOutput()), + this, SIGNAL(readyReadStandardOutput())); + connect(&m_proc, SIGNAL(readyReadStandardError()), + this, SIGNAL(readyReadStandardError())); + connect(&m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SIGNAL(finished(int, QProcess::ExitStatus))); + } + + void start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode) { m_proc.start(program, args, mode); } + void kill() { m_proc.kill(); } + void terminate() { m_proc.terminate(); } + bool waitForStarted(int msecs) { return m_proc.waitForStarted(msecs); } + bool waitForFinished(int msecs) { return m_proc.waitForFinished(msecs); } + QProcess::ProcessState state() const { return m_proc.state(); } + QString errorString() const { return m_proc.errorString(); } + QByteArray readAllStandardError() { return m_proc.readAllStandardError(); } + QByteArray readAllStandardOutput() { return m_proc.readAllStandardOutput(); } + qint64 write(const char *data) { return m_proc.write(data); } + void setWorkingDirectory(const QString &dir) { m_proc.setWorkingDirectory(dir); } + void setEnvironment(const QStringList &env) { m_proc.setEnvironment(env); } + +private: + QProcess m_proc; +}; class GdbEngine : public IDebuggerEngine { Q_OBJECT public: - GdbEngine(DebuggerManager *parent); + GdbEngine(DebuggerManager *parent, GdbProcessBase *gdbProc); ~GdbEngine(); signals: @@ -251,7 +286,7 @@ private: QByteArray m_inbuffer; - QProcess m_gdbProc; + GdbProcessBase *m_gdbProc; QProcess m_uploadProc; Core::Utils::ConsoleProcess m_stubProc; diff --git a/src/plugins/debugger/gdb/gdbprocessbase.h b/src/plugins/debugger/gdb/gdbprocessbase.h new file mode 100644 index 0000000000000000000000000000000000000000..b6adfc763bb533731f3ba1f365db956a8731fd00 --- /dev/null +++ b/src/plugins/debugger/gdb/gdbprocessbase.h @@ -0,0 +1,74 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_PROCESSBASE_H +#define DEBUGGER_PROCESSBASE_H + +#include <QtCore/QObject> +#include <QtCore/QProcess> + +namespace Debugger { +namespace Internal { + +// GdbProcessBase is inherited by GdbProcess and the gdb/trk Adapter. +// In the GdbProcess case it's just a wrapper around a QProcess running +// gdb, in the Adapter case it's the interface to the gdb process in +// the whole rfomm/gdb/gdbserver combo. +class GdbProcessBase : public QObject +{ + Q_OBJECT + +public: + GdbProcessBase(QObject *parent = 0) : QObject(parent) {} + + virtual void start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode = QIODevice::ReadWrite) = 0; + virtual void kill() = 0; + virtual void terminate() = 0; + virtual bool waitForStarted(int msecs = 30000) = 0; + virtual bool waitForFinished(int msecs = 30000) = 0; + virtual QProcess::ProcessState state() const = 0; + virtual QString errorString() const = 0; + virtual QByteArray readAllStandardError() = 0; + virtual QByteArray readAllStandardOutput() = 0; + virtual qint64 write(const char *data) = 0; + virtual void setWorkingDirectory(const QString &dir) = 0; + virtual void setEnvironment(const QStringList &env) = 0; + +signals: + void error(QProcess::ProcessError); + void readyReadStandardOutput(); + void readyReadStandardError(); + void finished(int, QProcess::ExitStatus); +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_PROCESSBASE_H diff --git a/src/plugins/debugger/symbian/symbian.pri b/src/plugins/debugger/symbian/symbian.pri new file mode 100644 index 0000000000000000000000000000000000000000..1ffb8081d4f16b6706f1f4bbdccad970739b2bd7 --- /dev/null +++ b/src/plugins/debugger/symbian/symbian.pri @@ -0,0 +1,14 @@ +HEADERS += \ + $$PWD/trkclient.h \ + $$PWD/symbianadapter.h \ + #$$PWD/gdboptionspage.h \ + +SOURCES += \ + $$PWD/trkclient.cpp \ + $$PWD/symbianadapter.cpp \ + $$PWD/symbianengine.cpp \ + #$$PWD/gdboptionspage.cpp \ + +#FORMS += $$PWD/gdboptionspage.ui + +#RESOURCES += $$PWD/gdb.qrc diff --git a/src/plugins/debugger/symbian/symbianadapter.cpp b/src/plugins/debugger/symbian/symbianadapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f66b33124209e695259042b8b9900d0709ae9fd --- /dev/null +++ b/src/plugins/debugger/symbian/symbianadapter.cpp @@ -0,0 +1,1599 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "symbianadapter.h" + +#define TrkCB(s) TrkCallback(this, &SymbianAdapter::s) +#define GdbCB(s) GdbCallback(this, &SymbianAdapter::s) + + +/* +fetch-register p info registers +set-register P set +binary-download X load, set +read-aux-vector qXfer:auxv:read info auxv +symbol-lookup qSymbol Detecting multiple threads +attach vAttach attach +verbose-resume vCont Stepping or resuming multiple threads +run vRun run +software-breakpoint Z0 break +hardware-breakpoint Z1 hbreak +write-watchpoint Z2 watch +read-watchpoint Z3 rwatch +access-watchpoint Z4 awatch +target-features qXfer:features:read set architecture +library-info qXfer:libraries:read info sharedlibrary +memory-map qXfer:memory-map:read info mem +read-spu-object qXfer:spu:read info spu +write-spu-object qXfer:spu:write info spu +get-thread-local- +storage-address qGetTLSAddr Displaying __thread variables +supported-packets qSupported Remote communications parameters +pass-signals QPassSignals handle signal +hostio-close-packet vFile:close remote get, remote put +hostio-open-packet vFile:open remote get, remote put +hostio-pread-packet vFile:pread remote get, remote put +hostio-pwrite-packet vFile:pwrite remote get, remote put +hostio-unlink-packet vFile:unlink remote delete +*/ + +using namespace trk; + +enum { KnownRegisters = RegisterPSGdb + 1}; + +static const char *registerNames[KnownRegisters] = +{ + "A1", "A2", "A3", "A4", + 0, 0, 0, 0, + 0, 0, 0, "AP", + "IP", "SP", "LR", "PC", + "PSTrk", 0, 0, 0, + 0, 0, 0, 0, + 0, "PSGdb" +}; + +static QByteArray dumpRegister(int n, uint value) +{ + QByteArray ba; + ba += ' '; + if (n < KnownRegisters && registerNames[n]) { + ba += registerNames[n]; + } else { + ba += '#'; + ba += QByteArray::number(n); + } + ba += "=" + hexxNumber(value); + return ba; +} + +namespace Debugger { +namespace Internal { + +trk::Endianness m_registerEndianness = LittleEndian; + +SymbianAdapter::SymbianAdapter() +{ + m_running = false; + m_gdbAckMode = true; + m_verbose = 2; + m_serialFrame = false; + m_bufferedMemoryRead = true; + m_rfcommDevice = "/dev/rfcomm0"; + + uid_t userId = getuid(); + m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); + + m_gdbProc.setObjectName("GDB PROCESS"); + connectProcess(&m_gdbProc); + connect(&m_gdbProc, SIGNAL(readyReadStandardError()), + this, SLOT(handleGdbReadyReadStandardError())); + connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()), + this, SLOT(handleGdbReadyReadStandardOutput())); + + m_rfcommProc.setObjectName("RFCOMM PROCESS"); + connectProcess(&m_rfcommProc); + connect(&m_rfcommProc, SIGNAL(readyReadStandardError()), + this, SLOT(handleRfcommReadyReadStandardError())); + connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), + this, SLOT(handleRfcommReadyReadStandardOutput())); + + if (m_verbose > 1) + m_trkDevice.setVerbose(true); + m_trkDevice.setSerialFrame(m_serialFrame); + + connect(&m_trkDevice, SIGNAL(logMessage(QString)), + this, SLOT(trkLogMessage(QString))); +} + +SymbianAdapter::~SymbianAdapter() +{ + m_gdbServer.close(); + logMessage("Shutting down.\n", true); +} + +void SymbianAdapter::trkLogMessage(const QString &msg) +{ + logMessage("TRK " + msg); +} + +void SymbianAdapter::setGdbServerName(const QString &name) +{ + m_gdbServerName = name; +} + +QString SymbianAdapter::gdbServerIP() const +{ + int pos = m_gdbServerName.indexOf(':'); + if (pos == -1) + return m_gdbServerName; + return m_gdbServerName.left(pos); +} + +uint SymbianAdapter::gdbServerPort() const +{ + int pos = m_gdbServerName.indexOf(':'); + if (pos == -1) + return 0; + return m_gdbServerName.mid(pos + 1).toUInt(); +} + +QByteArray SymbianAdapter::trkContinueMessage() +{ + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + +QByteArray SymbianAdapter::trkReadRegisterMessage() +{ + QByteArray ba; + appendByte(&ba, 0); // Register set, only 0 supported + appendShort(&ba, 0); + appendShort(&ba, RegisterCount - 1); // last register + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + +QByteArray SymbianAdapter::trkReadMemoryMessage(uint addr, uint len) +{ + QByteArray ba; + appendByte(&ba, 0x08); // Options, FIXME: why? + appendShort(&ba, len); + appendInt(&ba, addr); + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + return ba; +} + +void SymbianAdapter::startInferior() +{ + QString errorMessage; + if (!m_trkDevice.open(m_rfcommDevice, &errorMessage)) { + logMessage("LOOPING"); + QTimer::singleShot(1000, this, SLOT(startInferior())); + return; + } + + m_trkDevice.sendTrkInitialPing(); + sendTrkMessage(0x01); // Connect + sendTrkMessage(0x05, TrkCB(handleSupportMask)); + sendTrkMessage(0x06, TrkCB(handleCpuType)); + sendTrkMessage(0x04, TrkCB(handleTrkVersions)); // Versions + //sendTrkMessage(0x09); // Unrecognized command + //sendTrkMessage(0x4a, 0, + // "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File + //sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File + + QByteArray ba; + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + + QByteArray file("C:\\sys\\bin\\filebrowseapp.exe"); + appendString(&ba, file, TargetByteOrder); + sendTrkMessage(0x40, TrkCB(handleCreateProcess), ba); // Create Item + //sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(startGdbServer)); +} + +void SymbianAdapter::logMessage(const QString &msg, bool force) +{ + if (m_verbose || force) + emit output(QString(), msg); +} + +// +// Gdb +// +void SymbianAdapter::handleGdbConnection() +{ + logMessage("HANDLING GDB CONNECTION"); + + m_gdbConnection = m_gdbServer.nextPendingConnection(); + connect(m_gdbConnection, SIGNAL(disconnected()), + m_gdbConnection, SLOT(deleteLater())); + connect(m_gdbConnection, SIGNAL(readyRead()), + this, SLOT(readGdbServerCommand())); +} + +static inline QString msgGdbPacket(const QString &p) +{ + return QLatin1String("gdb: ") + p; +} + +void SymbianAdapter::readGdbServerCommand() +{ + QByteArray packet = m_gdbConnection->readAll(); + m_gdbReadBuffer.append(packet); + + logMessage("gdb: -> " + QString::fromAscii(packet)); + if (packet != m_gdbReadBuffer) + logMessage("buffer: " + m_gdbReadBuffer); + + QByteArray &ba = m_gdbReadBuffer; + while (ba.size()) { + char code = ba.at(0); + ba = ba.mid(1); + + if (code == '+') { + //logMessage("ACK"); + continue; + } + + if (code == '-') { + logMessage("NAK: Retransmission requested"); + continue; + } + + if (code == char(0x03)) { + logMessage("INTERRUPT RECEIVED"); + interruptInferior(); + continue; + } + + if (code != '$') { + logMessage("Broken package (2) " + quoteUnprintableLatin1(ba) + + hexNumber(code)); + continue; + } + + int pos = ba.indexOf('#'); + if (pos == -1) { + logMessage("Invalid checksum format in " + + quoteUnprintableLatin1(ba)); + continue; + } + + bool ok = false; + uint checkSum = ba.mid(pos + 1, 2).toUInt(&ok, 16); + if (!ok) { + logMessage("Invalid checksum format 2 in " + + quoteUnprintableLatin1(ba)); + return; + } + + //logMessage(QString("Packet checksum: %1").arg(checkSum)); + byte sum = 0; + for (int i = 0; i < pos; ++i) + sum += ba.at(i); + + if (sum != checkSum) { + logMessage(QString("ERROR: Packet checksum wrong: %1 %2 in " + + quoteUnprintableLatin1(ba)).arg(checkSum).arg(sum)); + } + + QByteArray cmd = ba.left(pos); + ba.remove(0, pos + 3); + handleGdbServerCommand(cmd); + } +} + +bool SymbianAdapter::sendGdbServerPacket(const QByteArray &packet, bool doFlush) +{ + if (!m_gdbConnection) { + logMessage(QString::fromLatin1("Cannot write to gdb: No connection (%1)") + .arg(QString::fromLatin1(packet)), true); + return false; + } + if (m_gdbConnection->state() != QAbstractSocket::ConnectedState) { + logMessage(QString::fromLatin1("Cannot write to gdb: Not connected (%1)") + .arg(QString::fromLatin1(packet)), true); + return false; + } + if (m_gdbConnection->write(packet) == -1) { + logMessage(QString::fromLatin1("Cannot write to gdb: %1 (%2)") + .arg(m_gdbConnection->errorString()).arg(QString::fromLatin1(packet)), true); + return false; + } + if (doFlush) + m_gdbConnection->flush(); + return true; +} + +void SymbianAdapter::sendGdbServerAck() +{ + if (!m_gdbAckMode) + return; + QByteArray packet = "+"; + logMessage("gdb: <- " + packet); + sendGdbServerPacket(packet, false); +} + +void SymbianAdapter::sendGdbServerMessage(const QByteArray &msg, const QByteArray &logNote) +{ + byte sum = 0; + for (int i = 0; i != msg.size(); ++i) + sum += msg.at(i); + + char checkSum[30]; + qsnprintf(checkSum, sizeof(checkSum) - 1, "%02x ", sum); + + //logMessage(QString("Packet checksum: %1").arg(sum)); + + QByteArray packet; + packet.append("$"); + packet.append(msg); + packet.append('#'); + packet.append(checkSum); + int pad = qMax(0, 24 - packet.size()); + logMessage("gdb: <- " + packet + QByteArray(pad, ' ') + logNote); + sendGdbServerPacket(packet, true); +} + +void SymbianAdapter::sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, + const QByteArray &logNote) +{ + QByteArray ba = msg + char(1) + logNote; + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportToGdb), "", ba); // Answer gdb +} + +void SymbianAdapter::reportToGdb(const TrkResult &result) +{ + QByteArray message = result.cookie.toByteArray(); + QByteArray note; + int pos = message.lastIndexOf(char(1)); // HACK + if (pos != -1) { + note = message.mid(pos + 1); + message = message.left(pos); + } + message.replace("@CODESEG@", hexNumber(m_session.codeseg)); + message.replace("@DATASEG@", hexNumber(m_session.dataseg)); + message.replace("@PID@", hexNumber(m_session.pid)); + message.replace("@TID@", hexNumber(m_session.tid)); + sendGdbServerMessage(message, note); +} + +QByteArray SymbianAdapter::trkBreakpointMessage(uint addr, uint len, bool armMode) +{ + QByteArray ba; + appendByte(&ba, 0x82); // unused option + appendByte(&ba, armMode /*bp.mode == ArmMode*/ ? 0x00 : 0x01); + appendInt(&ba, addr); + appendInt(&ba, len); + appendInt(&ba, 0x00000001); + appendInt(&ba, m_session.pid); + appendInt(&ba, 0xFFFFFFFF); + return ba; +} + +void SymbianAdapter::handleGdbServerCommand(const QByteArray &cmd) +{ + // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html + if (0) {} + + else if (cmd == "!") { + sendGdbServerAck(); + //sendGdbServerMessage("", "extended mode not enabled"); + sendGdbServerMessage("OK", "extended mode enabled"); + } + + else if (cmd.startsWith("?")) { + logMessage(msgGdbPacket(QLatin1String("Query halted"))); + // Indicate the reason the target halted. + // The reply is the same as for step and continue. + sendGdbServerAck(); + // The command below will trigger fetching a stack trace while + // the process does not seem to be fully functional. Most notably + // the PC points to a 0x9..., which is not in "our" range + //sendGdbServerMessage("T05library:r;", "target halted (library load)"); + //sendGdbServerMessage("S05", "target halted (trap)"); + sendGdbServerMessage("S00", "target halted (trap)"); + //sendGdbServerMessage("O" + QByteArray("Starting...").toHex()); + } + + else if (cmd == "c") { + logMessage(msgGdbPacket(QLatin1String("Continue"))); + sendGdbServerAck(); + QByteArray ba; + appendByte(&ba, 0); // options + appendInt(&ba, 0); // start address + appendInt(&ba, 0); // end address + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, TrkCallback(), ba); + } + + else if (cmd.startsWith("C")) { + logMessage(msgGdbPacket(QLatin1String("Continue with signal"))); + // C sig[;addr] Continue with signal sig (hex signal number) + //Reply: See section D.3 Stop Reply Packets, for the reply specifications. + sendGdbServerAck(); + bool ok = false; + uint signalNumber = cmd.mid(1).toInt(&ok, 16); + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x18, TrkCB(handleSignalContinue), ba, signalNumber); // Continue + } + + else if (cmd.startsWith("D")) { + sendGdbServerAck(); + sendGdbServerMessage("OK", "shutting down"); + qApp->quit(); + } + + else if (cmd == "g") { + logMessage(msgGdbPacket(QLatin1String("Read registers"))); + // Read general registers. + //sendGdbServerMessage("00000000", "read registers"); + sendGdbServerAck(); + sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), + trkReadRegisterMessage()); + } + + else if (cmd.startsWith("Hc")) { + logMessage(msgGdbPacket(QLatin1String("Set thread & continue"))); + // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). + // for step and continue operations + //$Hc-1#09 + sendGdbServerAck(); + sendGdbServerMessage("OK", "Set current thread for step & continue"); + } + + else if (cmd.startsWith("Hg")) { + logMessage(msgGdbPacket(QLatin1String("Set thread"))); + // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). + // for 'other operations. 0 - any thread + //$Hg0#df + sendGdbServerAck(); + m_session.currentThread = cmd.mid(2).toInt(0, 16); + sendGdbServerMessage("OK", "Set current thread " + + QByteArray::number(m_session.currentThread)); + } + + else if (cmd == "k") { + logMessage(msgGdbPacket(QLatin1String("kill"))); + // kill + sendGdbServerAck(); + QByteArray ba; + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // Sub-command: Delete Process + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item + sendGdbServerMessageAfterTrkResponse("", "process killed"); + } + + else if (cmd.startsWith("m")) { + logMessage(msgGdbPacket(QLatin1String("Read memory"))); + // m addr,length + sendGdbServerAck(); + uint addr = 0, len = 0; + do { + const int pos = cmd.indexOf(','); + if (pos == -1) + break; + bool ok; + addr = cmd.mid(1, pos - 1).toUInt(&ok, 16); + if (!ok) + break; + len = cmd.mid(pos + 1).toUInt(&ok, 16); + if (!ok) + break; + } while (false); + if (len) { + readMemory(addr, len); + } else { + sendGdbServerMessage("E20", "Error " + cmd); + } + } + else if (cmd.startsWith("p")) { + logMessage(msgGdbPacket(QLatin1String("read register"))); + // 0xf == current instruction pointer? + //sendGdbServerMessage("0000", "current IP"); + sendGdbServerAck(); + #if 0 + A1 = 0, first integer-like argument + A4 = 3, last integer-like argument + AP = 11, + IP = 12, + SP = 13, Contains address of top of stack + LR = 14, address to return to from a function call + PC = 15, Contains program counter + F0 = 16, first floating point register + F3 = 19, last floating point argument register + F7 = 23, last floating point register + FPS = 24, floating point status register + PS = 25, Contains processor status + WR0, WMMX data registers. + WR15 = WR0 + 15, + WC0, WMMX control registers. + WCSSF = WC0 + 2, + WCASF = WC0 + 3, + WC7 = WC0 + 7, + WCGR0, WMMX general purpose registers. + WCGR3 = WCGR0 + 3, + WCGR7 = WCGR0 + 7, + NUM_REGS, + + // Other useful registers. + FP = 11, Frame register in ARM code, if used. + THUMB_FP = 7, Frame register in Thumb code, if used. + NUM_ARG_REGS = 4, + LAST_ARG = A4, + NUM_FP_ARG_REGS = 4, + LAST_FP_ARG = F3 + #endif + bool ok = false; + const uint registerNumber = cmd.mid(1).toInt(&ok, 16); + QByteArray logMsg = "Read Register"; + if (registerNumber == RegisterPSGdb) { + QByteArray ba; + appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness); + logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]); + sendGdbServerMessage(ba.toHex(), logMsg); + } else if (registerNumber < RegisterCount) { + QByteArray ba; + appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness); + logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]); + sendGdbServerMessage(ba.toHex(), logMsg); + } else { + sendGdbServerMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber)); + //sendGdbServerMessage("E01", "read single unknown register"); + } + } + + else if (cmd == "qAttached") { + //$qAttached#8f + // 1: attached to an existing process + // 0: created a new process + sendGdbServerAck(); + sendGdbServerMessage("0", "new process created"); + //sendGdbServerMessage("1", "attached to existing process"); + //sendGdbServerMessage("E01", "new process created"); + } + + else if (cmd.startsWith("qC")) { + logMessage(msgGdbPacket(QLatin1String("query thread id"))); + // Return the current thread ID + //$qC#b4 + sendGdbServerAck(); + sendGdbServerMessageAfterTrkResponse("QC@TID@"); + } + + else if (cmd.startsWith("qSupported")) { + //$qSupported#37 + //$qSupported:multiprocess+#c6 + //logMessage("Handling 'qSupported'"); + sendGdbServerAck(); + if (0) + sendGdbServerMessage(QByteArray(), "nothing supported"); + else + sendGdbServerMessage( + "PacketSize=7cf;" + "QPassSignals+;" + "qXfer:libraries:read+;" + //"qXfer:auxv:read+;" + "qXfer:features:read+"); + } + + else if (cmd == "qPacketInfo") { + // happens with gdb 6.4.50.20060226-cvs / CodeSourcery + // deprecated by qSupported? + sendGdbServerAck(); + sendGdbServerMessage("", "FIXME: nothing?"); + } + + else if (cmd == "qOffsets") { + sendGdbServerAck(); + sendGdbServerMessageAfterTrkResponse("TextSeg=@CODESEG@;DataSeg=@DATASEG@"); + } + + else if (cmd == "qSymbol::") { + if (m_verbose) + logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup"))); + // Notify the target that GDB is prepared to serve symbol lookup requests. + sendGdbServerAck(); + if (1) + sendGdbServerMessage("OK", "no further symbols needed"); + else + sendGdbServerMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more"); + } + + else if (cmd.startsWith("qXfer:features:read:target.xml:")) { + // $qXfer:features:read:target.xml:0,7ca#46...Ack + sendGdbServerAck(); + sendGdbServerMessage("l<target><architecture>symbianelf</architecture></target>"); + } + + else if (cmd == "QStartNoAckMode") { + //$qSupported#37 + //logMessage("Handling 'QStartNoAckMode'"); + sendGdbServerAck(); + sendGdbServerMessage("OK", "ack no-ack mode"); + m_gdbAckMode = false; + } + + else if (cmd.startsWith("QPassSignals")) { + // list of signals to pass directly to inferior + // $QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;4c;#8f + // happens only if "QPassSignals+;" is qSupported + sendGdbServerAck(); + // FIXME: use the parameters + sendGdbServerMessage("OK", "passing signals accepted"); + } + + else if (cmd == "s" || cmd.startsWith("vCont;s")) { + logMessage(msgGdbPacket(QLatin1String("Step range"))); + logMessage(" from " + hexxNumber(m_snapshot.registers[RegisterPC])); + sendGdbServerAck(); + m_running = true; + QByteArray ba; + appendByte(&ba, 0x01); // options + appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address + //appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address + appendInt(&ba, -1); // end address + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + sendTrkMessage(0x19, TrkCB(handleStepRange), ba, "Step range"); + // FIXME: should be triggered by "real" stop" + //sendGdbServerMessageAfterTrkResponse("S05", "target halted"); + } + + else if (cmd == "vCont?") { + // actions supported by the vCont packet + sendGdbServerAck(); + //sendGdbServerMessage("OK"); // we don't support vCont. + sendGdbServerMessage("vCont;c;C;s;S"); + } + + else if (cmd == "vCont;c") { + // vCont[;action[:thread-id]]...' + sendGdbServerAck(); + m_running = true; + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } + + else if (cmd.startsWith("vKill")) { + // kill + sendGdbServerAck(); + QByteArray ba; + appendByte(&ba, 0); // Sub-command: Delete Process + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, TrkCallback(), ba, "Delete process"); // Delete Item + sendGdbServerMessageAfterTrkResponse("", "process killed"); + } + + else if (0 && cmd.startsWith("Z0,")) { + // Tell gdb we don't support software breakpoints + sendGdbServerMessage(""); + } + + else if (cmd.startsWith("Z0,") || cmd.startsWith("Z1,")) { + sendGdbServerAck(); + // Insert breakpoint + logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); + // $Z0,786a4ccc,4#99 + const int pos = cmd.lastIndexOf(','); + bool ok = false; + const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); + const uint len = cmd.mid(pos + 1).toInt(&ok, 16); + //qDebug() << "ADDR: " << hexNumber(addr) << " LEN: " << len; + logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2") + .arg(addr, 0, 16).arg(len)); + + //---IDE------------------------------------------------------ + // Command: 0x1B Set Break + //BreakType: 0x82 + // Options: 0x00 + // Address: 0x78674340 (2020033344) i.e + 0x00000340 + // Length: 0x00000001 (1) + // Count: 0x00000000 (0) + //ProcessID: 0x000001b5 (437) + // ThreadID: 0xffffffff (-1) + // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00 + // 00 00 01 B5 FF FF FF FF] + const QByteArray ba = trkBreakpointMessage(addr, len, m_session.pid); + sendTrkMessage(0x1B, TrkCB(handleAndReportSetBreakpoint), ba, addr); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + } + + else if (cmd.startsWith("z0,") || cmd.startsWith("z1,")) { + sendGdbServerAck(); + // Remove breakpoint + logMessage(msgGdbPacket(QLatin1String("Remove breakpoint"))); + // $z0,786a4ccc,4#99 + const int pos = cmd.lastIndexOf(','); + bool ok = false; + const uint addr = cmd.mid(3, pos - 3).toInt(&ok, 16); + const uint len = cmd.mid(pos + 1).toInt(&ok, 16); + const uint bp = m_session.addressToBP[addr]; + if (bp == 0) { + logMessage(QString::fromLatin1("NO RECORDED BP AT 0x%1, %2") + .arg(addr, 0, 16).arg(len)); + } else { + //---IDE------------------------------------------------------ + // Command: 0x1C Clear Break + // [1C 25 00 00 00 0A 78 6A 43 40] + m_session.addressToBP.remove(addr); + QByteArray ba; + appendByte(&ba, 0x00); + appendShort(&ba, bp); + appendInt(&ba, addr); + sendTrkMessage(0x1C, TrkCB(handleClearBreakpoint), ba, addr); + } + } + + else if (cmd.startsWith("qPart:") || cmd.startsWith("qXfer:")) { + QByteArray data = cmd.mid(1 + cmd.indexOf(':')); + // "qPart:auxv:read::0,147": Read OS auxiliary data (see info aux) + bool handled = false; + if (data.startsWith("auxv:read::")) { + const int offsetPos = data.lastIndexOf(':') + 1; + const int commaPos = data.lastIndexOf(','); + if (commaPos != -1) { + bool ok1 = false, ok2 = false; + const int offset = data.mid(offsetPos, commaPos - offsetPos) + .toInt(&ok1, 16); + const int length = data.mid(commaPos + 1).toInt(&ok2, 16); + if (ok1 && ok2) { + const QString msg = QString::fromLatin1("Read of OS auxilary " + "vector (%1, %2) not implemented.").arg(offset).arg(length); + logMessage(msgGdbPacket(msg), true); + sendGdbServerMessage("E20", msg.toLatin1()); + handled = true; + } + } + } // auxv read + if (!handled) { + const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") + + QString::fromAscii(cmd); + logMessage(msgGdbPacket(msg), true); + sendGdbServerMessage("E20", msg.toLatin1()); + } + } // qPart/qXfer + else { + logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") + + QString::fromAscii(cmd))); + } +} + +void SymbianAdapter::executeCommand(const QString &msg) +{ + if (msg == "EI") { + sendGdbMessage("-exec-interrupt"); + } else if (msg == "C") { + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + } else if (msg == "R") { + sendTrkMessage(0x18, TrkCB(handleReadRegisters), + trkReadRegisterMessage(), "READ REGS"); + } else if (msg == "I") { + interruptInferior(); + } else { + logMessage("EXECUTING GDB COMMAND " + msg); + sendGdbMessage(msg); + } +} + +void SymbianAdapter::sendTrkMessage(byte code, TrkCallback callback, + const QByteArray &data, const QVariant &cookie) +{ + m_trkDevice.sendTrkMessage(code, callback, data, cookie); +} + +void SymbianAdapter::sendTrkAck(byte token) +{ + logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token))); + m_trkDevice.sendTrkAck(token); +} + +void SymbianAdapter::handleTrkError(const QString &msg) +{ + logMessage("## TRK ERROR: " + msg); +} + +void SymbianAdapter::handleTrkResult(const TrkResult &result) +{ + if (result.isDebugOutput) { + sendTrkAck(result.token); + logMessage(QLatin1String("APPLICATION OUTPUT: ") + + QString::fromAscii(result.data)); + sendGdbServerMessage("O" + result.data.toHex()); + return; + } + logMessage("READ TRK " + result.toString()); + QByteArray prefix = "READ BUF: "; + QByteArray str = result.toString().toUtf8(); + switch (result.code) { + case 0x80: // ACK + break; + case 0xff: { // NAK. This mostly means transmission error, not command failed. + QString logMsg; + QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token + << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str; + logMessage(logMsg, true); + break; + } + case 0x90: { // Notified Stopped + // 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00 + const char *data = result.data.data(); + const uint addr = extractInt(data); + const uint pid = extractInt(data + 4); + const uint tid = extractInt(data + 8); + logMessage(prefix + QString::fromLatin1("NOTE: PID %1/TID %2 " + "STOPPED at 0x%3").arg(pid).arg(tid).arg(addr, 0, 16)); + sendTrkAck(result.token); + if (addr) { + // Todo: Do not send off GdbMessages if a synced gdb + // query is pending, queue instead + if (m_running) { + m_running = false; + sendGdbServerMessage("S05", "Target stopped"); + } + } else { + logMessage(QLatin1String("Ignoring stop at 0")); + } + break; + } + case 0x91: { // Notify Exception (obsolete) + logMessage(prefix + "NOTE: EXCEPTION " + str); + sendTrkAck(result.token); + break; + } + case 0x92: { // + logMessage(prefix + "NOTE: INTERNAL ERROR: " + str); + sendTrkAck(result.token); + break; + } + + // target->host OS notification + case 0xa0: { // Notify Created + const char *data = result.data.data(); + const byte error = result.data.at(0); + // type: 1 byte; for dll item, this value is 2. + const byte type = result.data.at(1); + const uint pid = extractInt(data + 2); + const uint tid = extractInt(data + 6); + const uint codeseg = extractInt(data + 10); + const uint dataseg = extractInt(data + 14); + const uint len = extractShort(data + 18); + const QByteArray name = result.data.mid(20, len); // library name + m_session.modules += QString::fromAscii(name); + QString logMsg; + QTextStream str(&logMsg); + str << prefix << " NOTE: LIBRARY LOAD: token=" << result.token; + if (error) + str << " ERROR: " << int(error); + str << " TYPE: " << int(type) << " PID: " << pid << " TID: " << tid; + str << " CODE: " << hexxNumber(codeseg); + str << " DATA: " << hexxNumber(dataseg); + str << " NAME: '" << name << '\''; + logMessage(logMsg); + // This lets gdb trigger a register update etc + //sendGdbServerMessage("T05library:r;"); + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + break; + } + case 0xa1: { // NotifyDeleted + const ushort itemType = extractByte(result.data.data() + 1); + const ushort len = result.data.size() > 12 + ? extractShort(result.data.data() + 10) : ushort(0); + const QString name = len + ? QString::fromAscii(result.data.mid(12, len)) : QString(); + if (!name.isEmpty()) + m_session.modules.removeAll(name); + logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3") + .arg(QString::fromAscii(prefix)) + .arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")) + .arg(name)); + sendTrkAck(result.token); + if (itemType == 0) { + sendGdbServerMessage("W00", "Process exited"); + //sendTrkMessage(0x02, TrkCB(handleDisconnect)); + } + break; + } + case 0xa2: { // NotifyProcessorStarted + logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str); + sendTrkAck(result.token); + break; + } + case 0xa6: { // NotifyProcessorStandby + logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str); + sendTrkAck(result.token); + break; + } + case 0xa7: { // NotifyProcessorReset + logMessage(prefix + "NOTE: PROCESSOR RESET: " + str); + sendTrkAck(result.token); + break; + } + default: { + logMessage(prefix + "INVALID: " + str); + break; + } + } +} + +void SymbianAdapter::handleCpuType(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 03 00 04 00 00 04 00 00 00] + m_session.cpuMajor = result.data[1]; + m_session.cpuMinor = result.data[2]; + m_session.bigEndian = result.data[3]; + m_session.defaultTypeSize = result.data[4]; + m_session.fpTypeSize = result.data[5]; + m_session.extended1TypeSize = result.data[6]; + //m_session.extended2TypeSize = result.data[6]; + QString logMsg; + QTextStream(&logMsg) << "HANDLE CPU TYPE: CPU=" << m_session.cpuMajor << '.' + << m_session.cpuMinor << " bigEndian=" << m_session.bigEndian + << " defaultTypeSize=" << m_session.defaultTypeSize + << " fpTypeSize=" << m_session.fpTypeSize + << " extended1TypeSize=" << m_session.extended1TypeSize; + logMessage(logMsg); +} + +void SymbianAdapter::handleSetTrkBreakpoint(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + const uint bpnr = extractInt(result.data.data()); + logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + + stringFromArray(result.data.data())); +} + +void SymbianAdapter::handleCreateProcess(const TrkResult &result) +{ + // 40 00 00] + //logMessage(" RESULT: " + result.toString()); + // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00] + const char *data = result.data.data(); + m_session.pid = extractInt(data + 1); + m_session.tid = extractInt(data + 5); + m_session.codeseg = extractInt(data + 9); + m_session.dataseg = extractInt(data + 13); + + logMessage("PID: " + hexxNumber(m_session.pid)); + logMessage("TID: " + hexxNumber(m_session.tid)); + logMessage("COD: " + hexxNumber(m_session.codeseg)); + logMessage("DAT: " + hexxNumber(m_session.dataseg)); + + QByteArray ba; + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); + + startGdb(); + + +#if 0 + //---IDE------------------------------------------------------ + // Command: 0x42 Read Info + // [42 0C 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F + // 72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00] + sendTrkMessage(0x42, TrkCB(handleReadInfo), + "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " + "72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00"); + //sendTrkMessage(0x42, TrkCB(handleReadInfo), + // "00 01 00 00 00 00"); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x20 Unspecified general OS-related error + // [80 0C 20] + + + //---IDE------------------------------------------------------ + // Command: 0x42 Read Info + // [42 0D 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F + // 72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00] + sendTrkMessage(0x42, TrkCB(handleReadInfo), + "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " + "72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00"); + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x20 Unspecified general OS-related error + // [80 0D 20] +#endif + + //sendTrkMessage(0x18, TrkCB(handleStop), + // "01 " + formatInt(m_session.pid) + formatInt(m_session.tid)); +} + +void SymbianAdapter::handleReadRegisters(const TrkResult &result) +{ + logMessage(" RESULT: " + result.toString()); + // [80 0B 00 00 00 00 00 C9 24 FF BC 00 00 00 00 00 + // 60 00 00 00 00 00 00 78 67 79 70 00 00 00 00 00...] + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + return; + } + const char *data = result.data.data() + 1; // Skip ok byte + for (int i = 0; i < RegisterCount; ++i) + m_snapshot.registers[i] = extractInt(data + 4 * i); +} + +void SymbianAdapter::handleAndReportReadRegisters(const TrkResult &result) +{ + handleReadRegisters(result); + QByteArray ba; + for (int i = 0; i < 16; ++i) { + const uint reg = m_registerEndianness == LittleEndian + ? swapEndian(m_snapshot.registers[i]) : m_snapshot.registers[i]; + ba += hexNumber(reg, 8); + } + QByteArray logMsg = "REGISTER CONTENTS: "; + if (m_verbose > 1) { + for (int i = 0; i < RegisterCount; ++i) { + logMsg += dumpRegister(i, m_snapshot.registers[i]); + logMsg += ' '; + } + } + sendGdbServerMessage(ba, logMsg); +} + +static inline QString msgMemoryReadError(int code, uint addr, uint len = 0) +{ + const QString lenS = len ? QString::number(len) : QLatin1String("<unknown>"); + return QString::fromLatin1("Memory read error %1 at: 0x%2 %3") + .arg(code).arg(addr, 0 ,16).arg(lenS); +} + +void SymbianAdapter::handleReadMemoryBuffered(const TrkResult &result) +{ + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) + logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); + const uint blockaddr = result.cookie.toUInt(); + if (const int errorCode = result.errorCode()) { + logMessage(msgMemoryReadError(errorCode, blockaddr)); + return; + } + const QByteArray ba = result.data.mid(3); + m_snapshot.memory.insert(blockaddr, ba); +} + +// Format log message for memory access with some smartness about registers +QByteArray SymbianAdapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const +{ + QByteArray logMsg = "memory contents"; + if (m_verbose > 1) { + logMsg += " addr: " + hexxNumber(addr); + // indicate dereferencing of registers + if (len == 4) { + if (addr == m_snapshot.registers[RegisterPC]) { + logMsg += "[PC]"; + } else if (addr == m_snapshot.registers[RegisterPSTrk]) { + logMsg += "[PSTrk]"; + } else if (addr == m_snapshot.registers[RegisterSP]) { + logMsg += "[SP]"; + } else if (addr == m_snapshot.registers[RegisterLR]) { + logMsg += "[LR]"; + } else if (addr > m_snapshot.registers[RegisterSP] && + (addr - m_snapshot.registers[RegisterSP]) < 10240) { + logMsg += "[SP+"; // Stack area ...stack seems to be top-down + logMsg += QByteArray::number(addr - m_snapshot.registers[RegisterSP]); + logMsg += ']'; + } + } + logMsg += " length "; + logMsg += QByteArray::number(len); + logMsg += " :"; + logMsg += stringFromArray(ba, 16).toAscii(); + } + return logMsg; +} + +void SymbianAdapter::reportReadMemoryBuffered(const TrkResult &result) +{ + const qulonglong cookie = result.cookie.toULongLong(); + const uint addr = cookie >> 32; + const uint len = uint(cookie); + + // Gdb accepts less memory according to documentation. + // Send E on complete failure. + QByteArray ba; + uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; + for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { + const Snapshot::Memory::const_iterator it = m_snapshot.memory.constFind(blockaddr); + if (it == m_snapshot.memory.constEnd()) + break; + ba.append(it.value()); + } + const int previousChunkOverlap = addr % MemoryChunkSize; + if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap) + ba.remove(0, previousChunkOverlap); + if (ba.size() > int(len)) + ba.truncate(len); + + if (ba.isEmpty()) { + ba = "E20"; + sendGdbServerMessage(ba, msgMemoryReadError(32, addr, len).toLatin1()); + } else { + sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); + } +} + +void SymbianAdapter::handleReadMemoryUnbuffered(const TrkResult &result) +{ + //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data)); + const uint blockaddr = result.cookie.toUInt(); + if (extractShort(result.data.data() + 1) + 3 != result.data.size()) + logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); + if (const int errorCode = result.errorCode()) { + const QByteArray ba = "E20"; + sendGdbServerMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); + } else { + const QByteArray ba = result.data.mid(3); + sendGdbServerMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); + } +} + +void SymbianAdapter::handleStepRange(const TrkResult &result) +{ + // [80 0f 00] + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + return; + } + logMessage("STEPPING FINISHED "); + //sendGdbServerMessage("S05", "Stepping finished"); +} + +void SymbianAdapter::handleAndReportSetBreakpoint(const TrkResult &result) +{ + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + uint bpnr = extractByte(result.data.data()); + uint addr = result.cookie.toUInt(); + m_session.addressToBP[addr] = bpnr; + logMessage("SET BREAKPOINT " + hexxNumber(bpnr) + " " + + stringFromArray(result.data.data())); + sendGdbServerMessage("OK"); + //sendGdbServerMessage("OK"); +} + +void SymbianAdapter::handleClearBreakpoint(const TrkResult &result) +{ + logMessage("CLEAR BREAKPOINT "); + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + //return; + } + //---TRK------------------------------------------------------ + // Command: 0x80 Acknowledge + // Error: 0x00 + // [80 09 00 00 00 00 0A] + // FIXME: + sendGdbServerMessage("OK"); +} + +void SymbianAdapter::handleSignalContinue(const TrkResult &result) +{ + int signalNumber = result.cookie.toInt(); + logMessage(" HANDLE SIGNAL CONTINUE: " + stringFromArray(result.data)); + logMessage("NUMBER" + QString::number(signalNumber)); + sendGdbServerMessage("O" + QByteArray("Console output").toHex()); + sendGdbServerMessage("W81"); // "Process exited with result 1 +} + +void SymbianAdapter::handleSupportMask(const TrkResult &result) +{ + const char *data = result.data.data(); + QByteArray str; + for (int i = 0; i < 32; ++i) { + //str.append(" [" + formatByte(data[i]) + "]: "); + for (int j = 0; j < 8; ++j) + if (data[i] & (1 << j)) + str.append(QByteArray::number(i * 8 + j, 16)); + } + logMessage("SUPPORTED: " + str); + } + +void SymbianAdapter::handleTrkVersions(const TrkResult &result) +{ + QString logMsg; + QTextStream str(&logMsg); + str << "Versions: "; + if (result.data.size() >= 5) { + str << "Trk version " << int(result.data.at(1)) << '.' + << int(result.data.at(2)) + << ", Protocol version " << int(result.data.at(3)) + << '.' << int(result.data.at(4)); + } + logMessage(logMsg); +} + +void SymbianAdapter::handleDisconnect(const TrkResult & /*result*/) +{ + logMessage(QLatin1String("Trk disconnected"), true); +} + +void SymbianAdapter::readMemory(uint addr, uint len) +{ + Q_ASSERT(len < (2 << 16)); + + // We try to get medium-sized chunks of data from the device + if (m_verbose > 2) + logMessage(QString::fromLatin1("readMemory %1 bytes from 0x%2 blocksize=%3") + .arg(len).arg(addr, 0, 16).arg(MemoryChunkSize)); + + if (m_bufferedMemoryRead) { + uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; + for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { + if (!m_snapshot.memory.contains(blockaddr)) { + if (m_verbose) + logMessage(QString::fromLatin1("Requesting buffered " + "memory %1 bytes from 0x%2") + .arg(MemoryChunkSize).arg(blockaddr, 0, 16)); + sendTrkMessage(0x10, TrkCB(handleReadMemoryBuffered), + trkReadMemoryMessage(blockaddr, MemoryChunkSize), + QVariant(blockaddr)); + } + } + const qulonglong cookie = (qulonglong(addr) << 32) + len; + sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(reportReadMemoryBuffered), + QByteArray(), cookie); + } else { + if (m_verbose) + logMessage(QString::fromLatin1("Requesting unbuffered memory %1 " + "bytes from 0x%2").arg(len).arg(addr, 0, 16)); + sendTrkMessage(0x10, TrkCB(handleReadMemoryUnbuffered), + trkReadMemoryMessage(addr, len), QVariant(addr)); + } +} + +void SymbianAdapter::interruptInferior() +{ + QByteArray ba; + // stop the thread (2) or the process (1) or the whole system (0) + // We choose 2, as 1 does not seem to work. + appendByte(&ba, 2); + appendInt(&ba, m_session.pid); + appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes. + sendTrkMessage(0x1a, TrkCallback(), ba, "Interrupting..."); +} + +void SymbianAdapter::connectProcess(QProcess *proc) +{ + connect(proc, SIGNAL(error(QProcess::ProcessError)), + this, SLOT(handleProcError(QProcess::ProcessError))); + connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(handleProcFinished(int, QProcess::ExitStatus))); + connect(proc, SIGNAL(started()), + this, SLOT(handleProcStarted())); + connect(proc, SIGNAL(stateChanged(QProcess::ProcessState)), + this, SLOT(handleProcStateChanged(QProcess::ProcessState))); +} + +void SymbianAdapter::sendOutput(QObject *sender, const QString &data) +{ + if (sender) + emit output(sender->objectName() + " : ", data); + else + emit output(QString(), data); +} + +void SymbianAdapter::handleProcError(QProcess::ProcessError error) +{ + sendOutput(sender(), QString("Process Error %1").arg(error)); +} + +void SymbianAdapter::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + sendOutput(sender(), + QString("ProcessFinished %1 %2").arg(exitCode).arg(exitStatus)); +} + +void SymbianAdapter::handleProcStarted() +{ + sendOutput(sender(), QString("Process Started")); +} + +void SymbianAdapter::handleProcStateChanged(QProcess::ProcessState newState) +{ + sendOutput(sender(), QString("Process State %1").arg(newState)); +} + +void SymbianAdapter::run() +{ + sendOutput("### Starting SymbianAdapter"); + m_rfcommProc.start("rfcomm listen " + m_rfcommDevice + " 1"); + m_rfcommProc.waitForStarted(); + + connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), + this, SLOT(handleTrkResult(trk::TrkResult))); + connect(&m_trkDevice, SIGNAL(error(QString)), + this, SLOT(handleTrkError(QString))); + + startInferior(); +} + +void SymbianAdapter::startGdb() +{ + if (!m_gdbServer.listen(QHostAddress(gdbServerIP()), gdbServerPort())) { + logMessage(QString("Unable to start the gdb server at %1: %2.") + .arg(m_gdbServerName).arg(m_gdbServer.errorString()), true); + QCoreApplication::exit(5); + return; + } + + logMessage(QString("Gdb server running on %1.\nRegister endianness: %3.") + .arg(m_gdbServerName).arg(m_registerEndianness), true); + + connect(&m_gdbServer, SIGNAL(newConnection()), + this, SLOT(handleGdbConnection())); + + logMessage("STARTING GDB"); + QStringList gdbArgs; + gdbArgs.append("--nx"); // Do not read .gdbinit file + gdbArgs.append("-i"); + gdbArgs.append("mi"); + m_gdbProc.start(QDir::currentPath() + "/cs-gdb", gdbArgs); + m_gdbProc.waitForStarted(); + + sendGdbMessage("set confirm off"); // confirm potentially dangerous operations? + sendGdbMessage("set endian little"); + sendGdbMessage("set remotebreak on"); + sendGdbMessage("set breakpoint pending on"); + sendGdbMessage("set trust-readonly-sections on"); + //sendGdbMessage("mem 0 ~0ll rw 8 cache"); + + // FIXME: "remote noack" does not seem to be supported on cs-gdb? + //sendGdbMessage("set remote noack-packet"); + + // FIXME: creates a lot of noise a la '&"putpkt: Junk: Ack " &' + // even thouhg the communication seems sane + //sendGdbMessage("set debug remote 1"); // creates l + + //sendGdbMessage("target remote " + m_gdbServerName); +// sendGdbMessage("target extended-remote " + m_gdbServerName); + //sendGdbMessage("target extended-async " + m_gdbServerName); + //sendGdbMessage("set remotecache ...") // Set cache use for remote targets + //sendGdbMessage("file filebrowseapp.sym"); +// sendGdbMessage("add-symbol-file filebrowseapp.sym " + m_baseAddress); +// sendGdbMessage("symbol-file filebrowseapp.sym"); +// sendGdbMessage("print E32Main"); +// sendGdbMessage("break E32Main"); + //sendGdbMessage("continue"); + //sendGdbMessage("info files"); + //sendGdbMessage("file filebrowseapp.sym -readnow"); + + sendGdbMessage("add-symbol-file filebrowseapp.sym " + + hexxNumber(m_session.codeseg)); + sendGdbMessage("symbol-file filebrowseapp.sym"); + + // -symbol-info-address not implemented in cs-gdb 6.4-6.8 (at least) + sendGdbMessage("info address E32Main", + GdbCB(handleInfoMainAddress)); + sendGdbMessage("info address CFileBrowseAppUi::HandleCommandL", + GdbCB(handleInfoMainAddress)); + +#if 1 + // FIXME: Gdb based version. That's the goal + //sendGdbMessage("break E32Main"); + //sendGdbMessage("continue"); + //sendTrkMessage(0x18, TrkCB(handleContinueAfterCreateProcess), + // trkContinueMessage(), "CONTINUE"); +#else + // Directly talk to TRK. Works for now... + sendGdbMessage("break E32Main"); + sendGdbMessage("break filebrowseappui.cpp:39"); + // sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); +#endif +} + +void SymbianAdapter::sendGdbMessage(const QString &msg, GdbCallback callback, + const QVariant &cookie) +{ + static int token = 0; + ++token; + GdbCommand data; + data.command = msg; + data.callback = callback; + data.cookie = cookie; + m_gdbCookieForToken[token] = data; + logMessage(QString("<- GDB: %1 %2").arg(token).arg(msg)); + m_gdbProc.write(QString("%1%2\n").arg(token).arg(msg).toLatin1()); +} + +void SymbianAdapter::handleGdbReadyReadStandardError() +{ + QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardError(); + sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); +} + +void SymbianAdapter::handleGdbReadyReadStandardOutput() +{ + QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardOutput(); + QString str = QString::fromLatin1(ba); + // FIXME: fragile. merge with gdbengine logic +#if 0 + QRegExp re(QString(".*([0-9]+)[^]done.*")); + int pos = re.indexIn(str); + if (pos == -1) { + logMessage(QString("\n-> GDB: %1 %**% %2 %**%\n").arg(str).arg(pos)); + return; + } + int token = re.cap(1).toInt(); + logMessage(QString("\n-> GDB: %1 %2##\n").arg(token).arg(QString::fromLatin1(ba))); + if (!token) + return; + GdbCommand cmd = m_gdbCookieForToken.take(token); + logMessage("FOUND CALLBACK FOR " + cmd.command); + GdbResult result; + result.data = ba; + if (!cmd.callback.isNull()) + cmd.callback(result); +#else + bool ok; + QRegExp re(QString("Symbol .._Z7E32Mainv.. is a function at address 0x(.*)\\.")); + if (re.indexIn(str) != -1) { + logMessage(QString("-> GDB MAIN BREAKPOINT: %1").arg(re.cap(1))); + uint addr = re.cap(1).toInt(&ok, 16); + sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); + return; + } + QRegExp re1(QString("Symbol .._ZN16CFileBrowseAppUi14HandleCommandLEi.. is a function at address 0x(.*)\\.")); + if (re1.indexIn(str) != -1) { + logMessage(QString("-> GDB USER BREAKPOINT: %1").arg(re1.cap(1))); + uint addr = re1.cap(1).toInt(&ok, 16); + sendTrkMessage(0x1B, TrkCallback(), trkBreakpointMessage(addr, 1)); + + sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); + sendGdbMessage("target remote " + m_gdbServerName); + return; + } + logMessage(QString("-> GDB: %1").arg(str)); +#endif +} + +void SymbianAdapter::handleInfoMainAddress(const GdbResult &result) +{ + Q_UNUSED(result); +} + +void SymbianAdapter::handleSetTrkMainBreakpoint(const TrkResult &result) +{ + Q_UNUSED(result); +/* + //---TRK------------------------------------------------------ + // [80 09 00 00 00 00 0A] + const uint bpnr = extractInt(result.data.data()); + logMessage("SET MAIN BREAKPOINT " + hexxNumber(bpnr) + + stringFromArray(result.data.data())); +*/ +} + +void SymbianAdapter::handleInfoAddress(const GdbResult &result) +{ + Q_UNUSED(result); + // FIXME +} + +void SymbianAdapter::handleRfcommReadyReadStandardError() +{ + QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardError(); + sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); +} + +void SymbianAdapter::handleRfcommReadyReadStandardOutput() +{ + QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardOutput(); + sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); +} + +// +// GdbProcessBase +// + +void SymbianAdapter::start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode) +{ + //m_gdbProc.start(program, args, mode); +} + +void SymbianAdapter::kill() +{ + //m_gdbProc.kill(); +} + +void SymbianAdapter::terminate() +{ + //m_gdbProc.terminate(); +} + +bool SymbianAdapter::waitForStarted(int msecs) +{ + //return m_gdbProc.waitForStarted(msecs); + return true; +} + +bool SymbianAdapter::waitForFinished(int msecs) +{ + //return m_gdbProc.waitForFinished(msecs); + return true; +} + +QProcess::ProcessState SymbianAdapter::state() const +{ + return m_gdbProc.state(); +} + +QString SymbianAdapter::errorString() const +{ + return m_gdbProc.errorString(); +} + +QByteArray SymbianAdapter::readAllStandardError() +{ + return m_gdbProc.readAllStandardError(); +} + +QByteArray SymbianAdapter::readAllStandardOutput() +{ + return m_gdbProc.readAllStandardOutput(); +} + +qint64 SymbianAdapter::write(const char *data) +{ + return m_gdbProc.write(data); +} + +void SymbianAdapter::setWorkingDirectory(const QString &dir) +{ + m_gdbProc.setWorkingDirectory(dir); +} + +void SymbianAdapter::setEnvironment(const QStringList &env) +{ + m_gdbProc.setEnvironment(env); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/symbian/symbianadapter.h b/src/plugins/debugger/symbian/symbianadapter.h new file mode 100644 index 0000000000000000000000000000000000000000..45c5b762c04818885c88d1c6a0ae6d0f0cb56c01 --- /dev/null +++ b/src/plugins/debugger/symbian/symbianadapter.h @@ -0,0 +1,247 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_SYMBIANADAPTER_H +#define DEBUGGER_SYMBIANADAPTER_H + +#include "trkutils.h" +#include "trkclient.h" +#include "../gdb/gdbprocessbase.h" + +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QHash> +#include <QtCore/QPointer> +#include <QtCore/QProcess> +#include <QtCore/QQueue> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QTextStream> +#include <QtCore/QTimer> + +#include <QtGui/QAction> +#include <QtGui/QApplication> +#include <QtGui/QMainWindow> +#include <QtGui/QKeyEvent> +#include <QtGui/QTextBlock> +#include <QtGui/QTextEdit> +#include <QtGui/QToolBar> + +#include <QtNetwork/QTcpServer> +#include <QtNetwork/QTcpSocket> +#include <QtNetwork/QLocalServer> +#include <QtNetwork/QLocalSocket> + +namespace Debugger { +namespace Internal { + +struct GdbResult +{ + QByteArray data; +}; + +/////////////////////////////////////////////////////////////////////// +// +// SymbianAdapter +// +/////////////////////////////////////////////////////////////////////// + +class SymbianAdapter : public GdbProcessBase +{ + Q_OBJECT + +public: + typedef trk::TrkResult TrkResult; + typedef trk::TrkFunctor1<const TrkResult &> TrkCallback; + typedef trk::TrkFunctor1<const GdbResult &> GdbCallback; + + SymbianAdapter(); + ~SymbianAdapter(); + void setGdbServerName(const QString &name); + QString gdbServerIP() const; + uint gdbServerPort() const; + void setVerbose(int verbose) { m_verbose = verbose; } + void setSerialFrame(bool b) { m_serialFrame = b; } + void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; } + +public slots: + void startInferior(); + +signals: + void output(const QString &senderName, const QString &data); + +private slots: + void handleProcError(QProcess::ProcessError error); + void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus); + void handleProcStarted(); + void handleProcStateChanged(QProcess::ProcessState newState); + void run(); + void startGdb(); + +private: + friend class RunnerGui; + void connectProcess(QProcess *proc); + void sendOutput(QObject *sender, const QString &data); + void sendOutput(const QString &data) { sendOutput(0, data); } + + QString m_rfcommDevice; // /dev/rfcomm0 + QString m_gdbServerName; // 127.0.0.1:(2222+uid) + + QProcess m_gdbProc; + QProcess m_rfcommProc; + bool m_running; + +public: + // + // Implementation of GdbProcessBase + // + void start(const QString &program, const QStringList &args, + QIODevice::OpenMode mode = QIODevice::ReadWrite); + void kill(); + void terminate(); + bool waitForStarted(int msecs = 30000); + bool waitForFinished(int msecs = 30000); + QProcess::ProcessState state() const; + QString errorString() const; + QByteArray readAllStandardError(); + QByteArray readAllStandardOutput(); + qint64 write(const char *data); + void setWorkingDirectory(const QString &dir); + void setEnvironment(const QStringList &env); + + // + // TRK + // + void sendTrkMessage(byte code, + TrkCallback callback = TrkCallback(), + const QByteArray &data = QByteArray(), + const QVariant &cookie = QVariant()); + Q_SLOT void handleTrkResult(const trk::TrkResult &data); + Q_SLOT void handleTrkError(const QString &msg); + + // convenience messages + void sendTrkAck(byte token); + + void handleCpuType(const TrkResult &result); + void handleCreateProcess(const TrkResult &result); + void handleClearBreakpoint(const TrkResult &result); + void handleSignalContinue(const TrkResult &result); + void handleStop(const TrkResult &result); + void handleSupportMask(const TrkResult &result); + void handleTrkVersions(const TrkResult &result); + void handleDisconnect(const TrkResult &result); + + void handleAndReportCreateProcess(const TrkResult &result); + void handleAndReportReadRegisters(const TrkResult &result); + QByteArray memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const; + QByteArray trkContinueMessage(); + QByteArray trkReadRegisterMessage(); + QByteArray trkReadMemoryMessage(uint addr, uint len); + QByteArray trkBreakpointMessage(uint addr, uint len, bool armMode = true); + void handleAndReportSetBreakpoint(const TrkResult &result); + void handleReadMemoryBuffered(const TrkResult &result); + void handleReadMemoryUnbuffered(const TrkResult &result); + void handleStepRange(const TrkResult &result); + void handleReadRegisters(const TrkResult &result); + void reportReadMemoryBuffered(const TrkResult &result); + void reportToGdb(const TrkResult &result); + + // set breakpoints behind gdb's back + void handleSetTrkBreakpoint(const TrkResult &result); + void handleSetTrkMainBreakpoint(const TrkResult &result); + + void readMemory(uint addr, uint len); + void interruptInferior(); + + trk::TrkDevice m_trkDevice; + + // + // Gdb + // + struct GdbCommand + { + GdbCommand() : flags(0), callback(GdbCallback()), callbackName(0) {} + + int flags; + GdbCallback callback; + const char *callbackName; + QString command; + QVariant cookie; + //QTime postTime; + }; + + void sendGdbMessage(const QString &msg, + GdbCallback callback = GdbCallback(), + const QVariant &cookie = QVariant()); + Q_SLOT void handleGdbConnection(); + Q_SLOT void readGdbServerCommand(); + void readGdbResponse(); + void handleGdbServerCommand(const QByteArray &cmd); + void sendGdbServerMessage(const QByteArray &msg, + const QByteArray &logNote = QByteArray()); + void sendGdbServerMessageAfterTrkResponse(const QByteArray &msg, + const QByteArray &logNote = QByteArray()); + void sendGdbServerAck(); + bool sendGdbServerPacket(const QByteArray &packet, bool doFlush); + + Q_SLOT void handleGdbReadyReadStandardError(); + Q_SLOT void handleGdbReadyReadStandardOutput(); + void logMessage(const QString &msg, bool force = false); + Q_SLOT void trkLogMessage(const QString &msg); + + void handleInfoAddress(const GdbResult &result); + void handleInfoMainAddress(const GdbResult &result); + + QTcpServer m_gdbServer; + QPointer<QTcpSocket> m_gdbConnection; + QByteArray m_gdbReadBuffer; + bool m_gdbAckMode; + + QHash<int, GdbCommand> m_gdbCookieForToken; + + // + // Rfcomm + // + Q_SLOT void handleRfcommReadyReadStandardError(); + Q_SLOT void handleRfcommReadyReadStandardOutput(); + + // Debuggee state + Q_SLOT void executeCommand(const QString &msg); + trk::Session m_session; // global-ish data (process id, target information) + trk::Snapshot m_snapshot; // local-ish data (memory and registers) + int m_verbose; + bool m_serialFrame; + bool m_bufferedMemoryRead; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_SYMBIANADAPTER_H diff --git a/src/plugins/debugger/symbian/symbianengine.cpp b/src/plugins/debugger/symbian/symbianengine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11c6b03c8ad2f81e78a2a2a3386be525fc05530d --- /dev/null +++ b/src/plugins/debugger/symbian/symbianengine.cpp @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#define QT_NO_CAST_FROM_ASCII + +#include "gdb/gdbengine.h" +#include "symbianadapter.h" + +//#include "debuggerdialogs.h" + +#include <utils/qtcassert.h> +#include <texteditor/itexteditor.h> +#include <coreplugin/icore.h> +#include <coreplugin/dialogs/ioptionspage.h> + +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QMetaObject> +#include <QtCore/QTime> +#include <QtCore/QTimer> +#include <QtCore/QTextStream> + + +namespace Debugger { +namespace Internal { + + +IDebuggerEngine *createSymbianEngine(DebuggerManager *parent, + QList<Core::IOptionsPage*> *opts) +{ + Q_UNUSED(opts); + //opts->push_back(new GdbOptionsPage); + return new GdbEngine(parent, new SymbianAdapter); +} + +} // namespace Internal +} // namespace Debugger + + diff --git a/tests/manual/trk/trkdevicex.cpp b/src/plugins/debugger/symbian/trkclient.cpp similarity index 93% rename from tests/manual/trk/trkdevicex.cpp rename to src/plugins/debugger/symbian/trkclient.cpp index 31382de3f03c237a043171487cf419c1d0388abf..5ae9766ac5abbab34f6b12fb051226c26b9a0776 100644 --- a/tests/manual/trk/trkdevicex.cpp +++ b/src/plugins/debugger/symbian/trkclient.cpp @@ -27,7 +27,7 @@ ** **************************************************************************/ -#include "trkdevicex.h" +#include "trkclient.h" #include "trkutils.h" #include <QtCore/QString> @@ -35,7 +35,6 @@ #include <QtCore/QQueue> #include <QtCore/QHash> #include <QtCore/QMap> -#include <QtCore/QSharedPointer> #ifdef Q_OS_WIN # include <windows.h> @@ -117,14 +116,12 @@ struct TrkMessage QByteArray data; QVariant cookie; Callback callback; - bool invokeOnNAK; }; TrkMessage::TrkMessage(byte c, byte t, Callback cb) : code(c), token(t), - callback(cb), - invokeOnNAK(false) + callback(cb) { } @@ -144,8 +141,7 @@ public: // Enqueue messages. void queueTrkMessage(byte code, Callback callback, - const QByteArray &data, const QVariant &cookie, - bool invokeOnNAK); + const QByteArray &data, const QVariant &cookie); void queueTrkInitialPing(); // Call this from the device read notification with the results. @@ -184,14 +180,13 @@ byte TrkWriteQueue::nextTrkWriteToken() } void TrkWriteQueue::queueTrkMessage(byte code, Callback callback, - const QByteArray &data, const QVariant &cookie, bool invokeOnNAK) + const QByteArray &data, const QVariant &cookie) { const byte token = code == TRK_WRITE_QUEUE_NOOP_CODE ? byte(0) : nextTrkWriteToken(); TrkMessage msg(code, token, callback); msg.data = data; msg.cookie = cookie; - msg.invokeOnNAK = invokeOnNAK; trkWriteQueue.append(msg); } @@ -233,16 +228,14 @@ void TrkWriteQueue::notifyWriteResult(bool ok) void TrkWriteQueue::slotHandleResult(const TrkResult &result) { trkWriteBusy = false; - if (result.code != TrkNotifyAck && result.code != TrkNotifyNak) - return; + //if (result.code != TrkNotifyAck && result.code != TrkNotifyNak) + // return; // Find which request the message belongs to and invoke callback // if ACK or on NAK if desired. const TokenMessageMap::iterator it = writtenTrkMessages.find(result.token); if (it == writtenTrkMessages.end()) return; - const bool invokeCB = it.value().callback - && (result.code == TrkNotifyAck || it.value().invokeOnNAK); - + const bool invokeCB = it.value().callback; if (invokeCB) { TrkResult result1 = result; result1.cookie = it.value().cookie; @@ -257,8 +250,18 @@ void TrkWriteQueue::queueTrkInitialPing() trkWriteQueue.append(TrkMessage(0, 0)); } -struct TrkDevicePrivate { + +/////////////////////////////////////////////////////////////////////// +// +// TrkDevicePrivate +// +/////////////////////////////////////////////////////////////////////// + +struct TrkDevicePrivate +{ TrkDevicePrivate(); + + TrkWriteQueue queue; #ifdef Q_OS_WIN HANDLE hdevice; #else @@ -298,11 +301,13 @@ TrkDevicePrivate::TrkDevicePrivate() : TrkDevice::TrkDevice(QObject *parent) : QObject(parent), - d(new TrkDevicePrivate), - qd(new TrkWriteQueue) + d(new TrkDevicePrivate) +{} + +TrkDevice::~TrkDevice() { - connect(this, SIGNAL(messageReceived(trk::TrkResult)), - this, SLOT(slotHandleResult(trk::TrkResult))); + close(); + delete d; } bool TrkDevice::open(const QString &port, QString *errorMessage) @@ -355,14 +360,6 @@ bool TrkDevice::open(const QString &port, QString *errorMessage) #endif } - -TrkDevice::~TrkDevice() -{ - close(); - delete d; - delete qd; -} - void TrkDevice::close() { if (!isOpen()) @@ -492,6 +489,7 @@ void TrkDevice::tryTrkRead() while (extractResult(&d->trkReadBuffer, d->serialFrame, &r, &rawData)) { //if (verbose()) // logMessage("Read TrkResult " + r.data.toHex()); + d->queue.slotHandleResult(r); emit messageReceived(r); if (!rawData.isEmpty()) emit rawDataReceived(rawData); @@ -512,14 +510,14 @@ void TrkDevice::emitError(const QString &s) } void TrkDevice::sendTrkMessage(byte code, Callback callback, - const QByteArray &data, const QVariant &cookie, bool invokeOnNAK) + const QByteArray &data, const QVariant &cookie) { - qd->queueTrkMessage(code, callback, data, cookie, invokeOnNAK); + d->queue.queueTrkMessage(code, callback, data, cookie); } void TrkDevice::sendTrkInitialPing() { - qd->queueTrkInitialPing(); + d->queue.queueTrkInitialPing(); } bool TrkDevice::sendTrkAck(byte token) @@ -535,10 +533,10 @@ bool TrkDevice::sendTrkAck(byte token) void TrkDevice::tryTrkWrite() { TrkMessage message; - if (!qd->pendingMessage(&message)) + if (!d->queue.pendingMessage(&message)) return; const bool success = trkWriteRawMessage(message); - qd->notifyWriteResult(success); + d->queue.notifyWriteResult(success); } bool TrkDevice::trkWriteRawMessage(const TrkMessage &msg) @@ -553,10 +551,5 @@ bool TrkDevice::trkWriteRawMessage(const TrkMessage &msg) return rc; } -void TrkDevice::slotHandleResult(const TrkResult &result) -{ - qd->slotHandleResult(result); -} - } // namespace trk diff --git a/tests/manual/trk/trkdevicex.h b/src/plugins/debugger/symbian/trkclient.h similarity index 92% rename from tests/manual/trk/trkdevicex.h rename to src/plugins/debugger/symbian/trkclient.h index 9d0e9da0dcc62c0cf9bc925f26f194c645d8e7fe..5a7a7440775ef782e88035ae5f0396faf2012e3b 100644 --- a/tests/manual/trk/trkdevicex.h +++ b/src/plugins/debugger/symbian/trkclient.h @@ -46,8 +46,6 @@ namespace trk { struct TrkResult; struct TrkMessage; struct TrkDevicePrivate; -class TrkWriteQueue; -struct TrkWriteQueueIODevicePrivate; /* TrkDevice: Implements a Windows COM or Linux device for * Trk communications. Provides synchronous write and asynchronous @@ -106,9 +104,7 @@ public: void sendTrkMessage(unsigned char code, Callback callBack = Callback(), const QByteArray &data = QByteArray(), - const QVariant &cookie = QVariant(), - // Invoke callback on receiving NAK, too. - bool invokeOnNAK = false); + const QVariant &cookie = QVariant()); // Enqeue an initial ping void sendTrkInitialPing(); @@ -116,15 +112,11 @@ public: // Send an Ack synchronously, bypassing the queue bool sendTrkAck(unsigned char token); -private slots: - void slotHandleResult(const trk::TrkResult &); - private: void tryTrkWrite(); bool trkWriteRawMessage(const TrkMessage &msg); TrkDevicePrivate *d; - TrkWriteQueue *qd; }; } // namespace trk diff --git a/tests/manual/trk/trkfunctor.h b/src/plugins/debugger/symbian/trkfunctor.h similarity index 97% rename from tests/manual/trk/trkfunctor.h rename to src/plugins/debugger/symbian/trkfunctor.h index 69a67e97a616a45d4457a2b65cdbe1fbeb3e1e0b..4b0d366912063d973d7f2ccfecba4d042201ed89 100644 --- a/tests/manual/trk/trkfunctor.h +++ b/src/plugins/debugger/symbian/trkfunctor.h @@ -27,11 +27,14 @@ ** **************************************************************************/ -#ifndef _TRK_FUNCTOR_H_ -#define _TRK_FUNCTOR_H_ +#ifndef DEBUGGER_TRK_FUNCTOR_H +#define DEBUGGER_TRK_FUNCTOR_H #include <QtGlobal> + +// FIXME: rename into something less TRK-specific + namespace trk { namespace Internal { /* Helper class for the 1-argument functor: diff --git a/tests/manual/trk/trkutils.cpp b/src/plugins/debugger/symbian/trkutils.cpp similarity index 96% rename from tests/manual/trk/trkutils.cpp rename to src/plugins/debugger/symbian/trkutils.cpp index 81925c07d674e0efb19afb836f658c193eaf47a3..4036b2ad6563f30ca734393ffd9a6b71f86dd531 100644 --- a/tests/manual/trk/trkutils.cpp +++ b/src/plugins/debugger/symbian/trkutils.cpp @@ -43,6 +43,11 @@ QByteArray hexNumber(uint n, int digits) return QByteArray(digits - ba.size(), '0') + ba; } +QByteArray hexxNumber(uint n, int digits) +{ + return "0x" + hexNumber(n, digits); +} + TrkResult::TrkResult() : code(0), token(0), @@ -345,5 +350,16 @@ int TrkResult::errorCode() const return errorCode; return isNAK ? 0xff : 0; } + +QString TrkResult::errorString() const +{ + // NAK means always error, else data sized 1 with a non-null element + if (code == 0xff) + return "NAK"; + if (data.size() < 1) + return "Unknown error packet"; + return errorMessage(data.at(0)); +} + } // namespace trk diff --git a/tests/manual/trk/trkutils.h b/src/plugins/debugger/symbian/trkutils.h similarity index 96% rename from tests/manual/trk/trkutils.h rename to src/plugins/debugger/symbian/trkutils.h index 42df54b680ddc48ccbadb3255e65ade30974de54..6f1b280eb85b4d23e1eaca53655ea314ac14a2f8 100644 --- a/tests/manual/trk/trkutils.h +++ b/src/plugins/debugger/symbian/trkutils.h @@ -72,6 +72,7 @@ enum Command { QByteArray decode7d(const QByteArray &ba); QByteArray encode7d(const QByteArray &ba); +inline byte extractByte(const char *data) { return *data; } ushort extractShort(const char *data); uint extractInt(const char *data); @@ -143,7 +144,7 @@ struct Session uint tid; uint codeseg; uint dataseg; - QHash<uint, uint> tokenToBreakpointIndex; + QHash<uint, uint> addressToBP; // Gdb request uint currentThread; @@ -177,6 +178,7 @@ struct TrkResult QString toString() const; // 0 for no error. int errorCode() const; + QString errorString() const; byte code; byte token; @@ -192,9 +194,9 @@ ushort isValidTrkResult(const QByteArray &buffer, bool serialFrame); bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *r, QByteArray *rawData = 0); QByteArray errorMessage(byte code); QByteArray hexNumber(uint n, int digits = 0); +QByteArray hexxNumber(uint n, int digits = 0); // prepends '0x', too uint swapEndian(uint in); - } // namespace trk #endif // DEBUGGER_TRK_UTILS diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index a766a1e5a8b876490417b72baf5ba3c122395d79..e3b7757881ea3ab21ea8545db5c4491bb694535f 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -58,7 +58,13 @@ void AbstractProcessStep::setCommand(const QString &buildConfiguration, const QS QString AbstractProcessStep::command(const QString &buildConfiguration) const { - return value(buildConfiguration, PROCESS_COMMAND).toString(); + QString result = value(buildConfiguration, PROCESS_COMMAND).toString(); + if (QFileInfo(result).isRelative()) { + QString searchInPath = environment(buildConfiguration).searchInPath(result); + if (!searchInPath.isEmpty()) + result = searchInPath; + } + return result; } void AbstractProcessStep::setWorkingDirectory(const QString &buildConfiguration, const QString &workingDirectory) diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index a0dc6873c93184aadf70d98544d1a2b617fb8698..2d61bd50366153855ede723cdc2b2cc4c37201cb 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -344,12 +344,7 @@ QString QmlRunConfiguration::type() const QString QmlRunConfiguration::executable() const { - if (! QFile::exists(m_qmlViewer)) { - QMessageBox::information(Core::ICore::instance()->mainWindow(), - tr("QML Viewer"), - tr("Could not find the qmlviewer executable, please specify one.")); - } - + // No need to verify if the QML Viewer exists. The console will tell us anyway when we try to launch it. return m_qmlViewer; } diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp index 8de81100d8cd9c8b4425cc999864b76478dfce82..6da82ccdf594ca4b9ddd8aebf9778c419a3c653e 100644 --- a/src/plugins/texteditor/basetextdocument.cpp +++ b/src/plugins/texteditor/basetextdocument.cpp @@ -93,7 +93,7 @@ bool BaseTextDocument::save(const QString &fileName) cursor.beginEditBlock(); if (m_storageSettings.m_cleanWhitespace) - cleanWhitespace(cursor, m_storageSettings.m_inEntireDocument); + cleanWhitespace(cursor, m_storageSettings.m_cleanIndentation, m_storageSettings.m_inEntireDocument); if (m_storageSettings.m_addFinalNewLine) ensureFinalNewLine(cursor); cursor.endEditBlock(); @@ -301,23 +301,28 @@ void BaseTextDocument::setSyntaxHighlighter(QSyntaxHighlighter *highlighter) -void BaseTextDocument::cleanWhitespace() +void BaseTextDocument::cleanWhitespace(const QTextCursor &cursor) { - QTextCursor cursor(m_document); - cursor.beginEditBlock(); - cleanWhitespace(cursor, true); - if (m_storageSettings.m_addFinalNewLine) - ensureFinalNewLine(cursor); - cursor.endEditBlock(); + bool hasSelection = cursor.hasSelection(); + QTextCursor copyCursor = cursor; + copyCursor.beginEditBlock(); + cleanWhitespace(copyCursor, true, true); + if (!hasSelection) + ensureFinalNewLine(copyCursor); + copyCursor.endEditBlock(); } -void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool inEntireDocument) +void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool cleanIndentation, bool inEntireDocument) { TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(m_document->documentLayout()); - QTextBlock block = m_document->firstBlock(); - while (block.isValid()) { + QTextBlock block = m_document->findBlock(cursor.selectionStart()); + QTextBlock end; + if (cursor.hasSelection()) + end = m_document->findBlock(cursor.selectionEnd()-1).next(); + + while (block.isValid() && block != end) { if (inEntireDocument || block.revision() > documentLayout->lastSaveRevision) { @@ -327,7 +332,7 @@ void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool inEntireDocumen cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, trailing); cursor.removeSelectedText(); } - if (m_storageSettings.m_cleanIndentation && !m_tabSettings.isIndentationClean(blockText)) { + if (cleanIndentation && !m_tabSettings.isIndentationClean(blockText)) { cursor.setPosition(block.position()); int firstNonSpace = m_tabSettings.firstNonSpace(blockText); if (firstNonSpace == blockText.length()) { diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h index 88e1c609a132fa5dc5f3ae6af81616ac9230f7e6..eaf37c91caf2ae40acca18e649522dcdd07ff264 100644 --- a/src/plugins/texteditor/basetextdocument.h +++ b/src/plugins/texteditor/basetextdocument.h @@ -110,7 +110,7 @@ public: void reload(QTextCodec *codec); - void cleanWhitespace(); + void cleanWhitespace(const QTextCursor &cursor); signals: void titleChanged(QString title); @@ -146,7 +146,7 @@ private: bool m_hasDecodingError; QByteArray m_decodingErrorSample; - void cleanWhitespace(QTextCursor& cursor, bool onlyInModifiedLines); + void cleanWhitespace(QTextCursor& cursor, bool cleanIndentation, bool inEntireDocument); void ensureFinalNewLine(QTextCursor& cursor); }; diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 8c23d975df5d876a7a04d7b85ad8c6d76b2df5ff..cce27c4c21b3a2ebf59a8e560abafe027f5dde51 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -833,7 +833,7 @@ void BaseTextEditor::moveLineUpDown(bool up) void BaseTextEditor::cleanWhitespace() { - d->m_document->cleanWhitespace(); + d->m_document->cleanWhitespace(textCursor()); } void BaseTextEditor::keyPressEvent(QKeyEvent *e) @@ -887,13 +887,18 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) QTextCursor cursor = textCursor(); if (d->m_inBlockSelectionMode) cursor.clearSelection(); - if (d->m_document->tabSettings().m_autoIndent) { + const TabSettings &ts = d->m_document->tabSettings(); + if (ts.m_autoIndent) { cursor.beginEditBlock(); cursor.insertBlock(); indent(document(), cursor, QChar::Null); cursor.endEditBlock(); } else { + cursor.beginEditBlock(); + QString previousBlockText = cursor.block().text(); cursor.insertBlock(); + cursor.insertText(ts.indentationString(previousBlockText)); + cursor.endEditBlock(); } e->accept(); setTextCursor(cursor); @@ -1337,6 +1342,16 @@ bool BaseTextEditor::codeFoldingSupported() const return d->m_codeFoldingSupported; } +void BaseTextEditor::setMouseNavigationEnabled(bool b) +{ + d->m_mouseNavigationEnabled = b; +} + +bool BaseTextEditor::mouseNavigationEnabled() const +{ + return d->m_mouseNavigationEnabled; +} + void BaseTextEditor::setRevisionsVisible(bool b) { d->m_revisionsVisible = b; @@ -1372,12 +1387,14 @@ BaseTextEditorPrivate::BaseTextEditorPrivate() m_marksVisible(false), m_codeFoldingVisible(false), m_codeFoldingSupported(false), + m_mouseNavigationEnabled(true), m_revisionsVisible(false), m_lineNumbersVisible(true), m_highlightCurrentLine(true), m_requestMarkEnabled(true), m_lineSeparatorsAllowed(false), m_visibleWrapColumn(0), + m_showingLink(false), m_editable(0), m_actionHack(0), m_inBlockSelectionMode(false), @@ -2721,6 +2738,32 @@ void BaseTextEditorPrivate::clearVisibleCollapsedBlock() void BaseTextEditor::mouseMoveEvent(QMouseEvent *e) { d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier); + + bool linkFound = false; + + if (d->m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier) { + // Link emulation behaviour for 'go to definition' + const QTextCursor cursor = cursorForPosition(e->pos()); + + // Check that the mouse was actually on the text somewhere + bool onText = cursorRect(cursor).right() >= e->x(); + if (!onText) { + QTextCursor nextPos = cursor; + nextPos.movePosition(QTextCursor::Right); + onText = cursorRect(nextPos).right() >= e->x(); + } + + const Link link = findLinkAt(cursor, false); + + if (onText && link.isValid()) { + showLink(link); + linkFound = true; + } + } + + if (!linkFound) + clearLink(); + if (e->buttons() == Qt::NoButton) { const QTextBlock collapsedBlock = collapsedBlockAt(e->pos()); const int blockNumber = collapsedBlock.next().blockNumber(); @@ -2767,6 +2810,38 @@ void BaseTextEditor::mousePressEvent(QMouseEvent *e) QPlainTextEdit::mousePressEvent(e); } +void BaseTextEditor::mouseReleaseEvent(QMouseEvent *e) +{ + if (d->m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier + && !(e->modifiers() & Qt::ShiftModifier) + && e->button() == Qt::LeftButton) { + + const QTextCursor cursor = cursorForPosition(e->pos()); + if (openLink(findLinkAt(cursor))) { + clearLink(); + return; + } + } + + QPlainTextEdit::mouseReleaseEvent(e); +} + +void BaseTextEditor::leaveEvent(QEvent *e) +{ + // Clear link emulation when the mouse leaves the editor + clearLink(); + QPlainTextEdit::leaveEvent(e); +} + +void BaseTextEditor::keyReleaseEvent(QKeyEvent *e) +{ + // Clear link emulation when Ctrl is released + if (e->key() == Qt::Key_Control) + clearLink(); + + QPlainTextEdit::keyReleaseEvent(e); +} + void BaseTextEditor::extraAreaLeaveEvent(QEvent *) { // fake missing mouse move event from Qt @@ -2833,7 +2908,7 @@ void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e) document()->findBlockByNumber(d->m_highlightBlocksInfo.open.last()).position() ); QTextBlock c = cursor.block(); - if (!TextBlockUserData::canCollapse(c)) + if (TextBlockUserData::hasCollapseAfter(c.previous())) c = c.previous(); toggleBlockVisible(c); d->moveCursorVisible(false); @@ -3119,17 +3194,14 @@ void BaseTextEditor::handleBackspaceKey() continue; previousIndent = tabSettings.columnAt(previousNonEmptyBlockText, tabSettings.firstNonSpace(previousNonEmptyBlockText)); - if (previousIndent < indent) + if (previousIndent < indent) { + cursor.beginEditBlock(); + cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor); + cursor.insertText(tabSettings.indentationString(previousNonEmptyBlockText)); + cursor.endEditBlock(); break; + } } - - if (previousIndent >= indent) - previousIndent = 0; - - cursor.beginEditBlock(); - cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor); - cursor.insertText(tabSettings.indentationString(0, previousIndent)); - cursor.endEditBlock(); } void BaseTextEditor::wheelEvent(QWheelEvent *e) @@ -3186,6 +3258,50 @@ void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar } } +BaseTextEditor::Link BaseTextEditor::findLinkAt(const QTextCursor &, bool) +{ + return Link(); +} + +bool BaseTextEditor::openLink(const Link &link) +{ + if (link.fileName.isEmpty()) + return false; + + if (baseTextDocument()->fileName() == link.fileName) { + Core::EditorManager *editorManager = Core::EditorManager::instance(); + editorManager->addCurrentPositionToNavigationHistory(); + gotoLine(link.line, link.column); + setFocus(); + return true; + } + + return openEditorAt(link.fileName, link.line, link.column); +} + +void BaseTextEditor::showLink(const Link &link) +{ + QTextEdit::ExtraSelection sel; + sel.cursor = textCursor(); + sel.cursor.setPosition(link.pos); + sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); + sel.format = d->m_linkFormat; + sel.format.setFontUnderline(true); + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel); + viewport()->setCursor(Qt::PointingHandCursor); + d->m_showingLink = true; +} + +void BaseTextEditor::clearLink() +{ + if (!d->m_showingLink) + return; + + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); + viewport()->setCursor(Qt::IBeamCursor); + d->m_showingLink = false; +} + void BaseTextEditorPrivate::updateMarksBlock(const QTextBlock &block) { if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block)) @@ -4005,8 +4121,8 @@ void BaseTextEditor::unCommentSelection() void BaseTextEditor::showEvent(QShowEvent* e) { if (!d->m_fontSettings.isEmpty()) { - setFontSettings(d->m_fontSettings); - d->m_fontSettings.clear(); + setFontSettings(d->m_fontSettings); + d->m_fontSettings.clear(); } QPlainTextEdit::showEvent(e); } @@ -4015,11 +4131,12 @@ void BaseTextEditor::showEvent(QShowEvent* e) void BaseTextEditor::setFontSettingsIfVisible(const TextEditor::FontSettings &fs) { if (!isVisible()) { - d->m_fontSettings = fs; - return; + d->m_fontSettings = fs; + return; } setFontSettings(fs); } + void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs) { const QTextCharFormat textFormat = fs.toTextCharFormat(QLatin1String(Constants::C_TEXT)); @@ -4030,6 +4147,7 @@ void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs) const QTextCharFormat parenthesesFormat = fs.toTextCharFormat(QLatin1String(Constants::C_PARENTHESES)); d->m_currentLineFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE)); d->m_currentLineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE_NUMBER)); + d->m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK)); d->m_ifdefedOutFormat = fs.toTextCharFormat(QLatin1String(Constants::C_DISABLED_CODE)); QFont font(textFormat.font()); @@ -4082,6 +4200,7 @@ void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds) setCodeFoldingVisible(ds.m_displayFoldingMarkers); setHighlightCurrentLine(ds.m_highlightCurrentLine); setRevisionsVisible(ds.m_markTextChanges); + setMouseNavigationEnabled(ds.m_mouseNavigation); if (d->m_displaySettings.m_visualizeWhitespace != ds.m_visualizeWhitespace) { if (QSyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter()) diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 906e73a14fe2c8cb2c221956511f267690148f41..17a67d3b0a9bd4bde8cdc329cad1db02f32ee01d 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -145,13 +145,10 @@ public: inline static bool hasCollapseAfter(const QTextBlock & block) { - if (!block.isValid()) - return false; - TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData()); - if (data && data->collapseMode() != NoCollapse) { + if (!block.isValid()) { return false; } else if (block.next().isValid()) { - data = static_cast<TextBlockUserData*>(block.next().userData()); + TextBlockUserData *data = static_cast<TextBlockUserData*>(block.next().userData()); if (data && data->collapseMode() == TextBlockUserData::CollapseThis && !data->m_ifdefedOut) return true; } @@ -277,8 +274,7 @@ private: }; -class TEXTEDITOR_EXPORT BaseTextEditor - : public QPlainTextEdit +class TEXTEDITOR_EXPORT BaseTextEditor : public QPlainTextEdit { Q_OBJECT @@ -348,6 +344,9 @@ public: void setCodeFoldingSupported(bool b); bool codeFoldingSupported() const; + void setMouseNavigationEnabled(bool b); + bool mouseNavigationEnabled() const; + void setRevisionsVisible(bool b); bool revisionsVisible() const; @@ -499,14 +498,54 @@ protected: void timerEvent(QTimerEvent *); void mouseMoveEvent(QMouseEvent *); void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void leaveEvent(QEvent *); + void keyReleaseEvent(QKeyEvent *); - // Rertuns true if key triggers an indent. + // Returns true if key triggers an indent. virtual bool isElectricCharacter(const QChar &ch) const; // Indent a text block based on previous line. Default does nothing virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar); // Indent at cursor. Calls indentBlock for selection or current line. virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar); + struct Link + { + Link(const QString &fileName = QString(), + int line = 0, + int column = 0) + : pos(-1) + , length(-1) + , fileName(fileName) + , line(line) + , column(column) + {} + + bool isValid() const + { return !(pos == -1 || length == -1); } + + int pos; // Link position + int length; // Link length + + QString fileName; // Target file + int line; // Target line + int column; // Target column + }; + + /*! + Reimplement this function to enable code navigation. + + \a resolveTarget is set to true when the target of the link is relevant + (it isn't until the link is used). + */ + virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true); + + /*! + Reimplement this function if you want to customize the way a link is + opened. Returns whether the link was opened succesfully. + */ + virtual bool openLink(const Link &link); + protected slots: virtual void slotUpdateExtraAreaWidth(); virtual void slotModificationChanged(bool); @@ -540,6 +579,8 @@ private: QTextBlock collapsedBlockAt(const QPoint &pos, QRect *box = 0) const; + void showLink(const Link &); + void clearLink(); // parentheses matcher private slots: diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index dbf5b66d1e884b0a8850cfef2aa1a100099c4a75..1956f858800a807347a8c0938512aa69fc3a96d7 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -194,6 +194,7 @@ public: uint m_marksVisible : 1; uint m_codeFoldingVisible : 1; uint m_codeFoldingSupported : 1; + uint m_mouseNavigationEnabled : 1; uint m_revisionsVisible : 1; uint m_lineNumbersVisible : 1; uint m_highlightCurrentLine : 1; @@ -201,6 +202,9 @@ public: uint m_lineSeparatorsAllowed : 1; int m_visibleWrapColumn; + QTextCharFormat m_linkFormat; + bool m_showingLink; + QTextCharFormat m_ifdefedOutFormat; QRegExp m_searchExpr; @@ -226,7 +230,7 @@ public: QString copyBlockSelection(); void removeBlockSelection(const QString &text = QString()); bool m_moveLineUndoHack; - + QTextCursor m_findScope; QTextCursor m_selectBlockAnchor; diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp index e0225ce8bcdbb12bf17d711504ece37e8f797ca5..393434d90852ab7ca4431f98f674fa1c7713b6f0 100644 --- a/src/plugins/texteditor/tabsettings.cpp +++ b/src/plugins/texteditor/tabsettings.cpp @@ -110,6 +110,18 @@ int TabSettings::firstNonSpace(const QString &text) const return i; } +QString TabSettings::indentationString(const QString &text) const +{ + return text.left(firstNonSpace(text)); +} + + +int TabSettings::indentationColumn(const QString &text) const +{ + return columnAt(text, firstNonSpace(text)); +} + + int TabSettings::trailingWhitespaces(const QString &text) const { int i = 0; @@ -225,7 +237,7 @@ void TabSettings::indentLine(QTextBlock block, int newIndent) const const int oldBlockLength = text.size(); // Quickly check whether indenting is required. - if (oldBlockLength == 0 && newIndent == 0) + if (indentationColumn(text) == newIndent) return; const QString indentString = indentationString(0, newIndent); @@ -234,12 +246,6 @@ void TabSettings::indentLine(QTextBlock block, int newIndent) const if (oldBlockLength == indentString.length() && text == indentString) return; - if (oldBlockLength > indentString.length() && - text.startsWith(indentString) && - !text.at(indentString.length()).isSpace()) { - return; - } - QTextCursor cursor(block); cursor.beginEditBlock(); cursor.movePosition(QTextCursor::StartOfBlock); diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h index ec2c3dfe8ea35666a5728909a08725153f526c16..f26e0bb5ad99dae0824bc74d1268f051ed849fb7 100644 --- a/src/plugins/texteditor/tabsettings.h +++ b/src/plugins/texteditor/tabsettings.h @@ -63,6 +63,8 @@ struct TEXTEDITOR_EXPORT TabSettings int spacesLeftFromPosition(const QString &text, int position) const; int indentedColumn(int column, bool doIndent = true) const; QString indentationString(int startColumn, int targetColumn) const; + QString indentationString(const QString &text) const; + int indentationColumn(const QString &text) const; void indentLine(QTextBlock block, int newIndent) const; diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index c4718c084957a9e68adf00a1d04f5e357677ce88..d536a03ef0fea5490d362386e069310d3fdc8406 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -1139,10 +1139,11 @@ ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pr } if (!qmake_cache.isEmpty()) { qmake_cache = QDir::cleanPath(qmake_cache); - if (evaluateFileInto(qmake_cache, &m_option->cache_valuemap, 0)) { + QHash<QString, QStringList> cache_valuemap; + if (evaluateFileInto(qmake_cache, &cache_valuemap, 0)) { m_option->cachefile = qmake_cache; if (m_option->qmakespec.isEmpty()) { - const QStringList &vals = m_option->cache_valuemap.value(QLatin1String("QMAKESPEC")); + const QStringList &vals = cache_valuemap.value(QLatin1String("QMAKESPEC")); if (!vals.isEmpty()) m_option->qmakespec = vals.first(); } @@ -1196,8 +1197,9 @@ ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pr if (!evaluateFileInto(spec, &m_option->base_valuemap, &m_option->base_functions)) { errorMessage(format("Could not read qmake configuration file %1").arg(spec)); - } else { - evaluateFileInto(qmake_cache, &m_option->base_valuemap, 0); + } else if (!m_option->cachefile.isEmpty()) { + evaluateFileInto(m_option->cachefile, + &m_option->base_valuemap, &m_option->base_functions); } } diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h index cba159c6b8f1ee9e03924d958933e17100fa3180..691dd78e02b30256c6ee604ab59f1b90c12f2bc6 100644 --- a/src/shared/proparser/profileevaluator.h +++ b/src/shared/proparser/profileevaluator.h @@ -88,8 +88,7 @@ public: friend class ProFileEvaluator; friend class ProFileEvaluator::Private; static QString field_sep; // Just a cache for quick construction - QHash<QString, QStringList> cache_valuemap; // Cached results of .qmake.cache - QHash<QString, QStringList> base_valuemap; // ~ and qmake.conf and default_pre.prf + QHash<QString, QStringList> base_valuemap; // Cached results of qmake.conf, .qmake.cache & default_pre.prf FunctionDefs base_functions; QStringList feature_roots; }; diff --git a/tests/manual/trk/adapter.pro b/tests/manual/trk/adapter.pro index 22f4aa3cddb1785127a452b4ee5ee116deebe501..9ee1a95d8f7b3893881eb7b4100848872ce2c903 100644 --- a/tests/manual/trk/adapter.pro +++ b/tests/manual/trk/adapter.pro @@ -1,14 +1,20 @@ TEMPLATE = app +DEBUGGERHOME = ../../../src/plugins/debugger/symbian + +INCLUDEPATH *= $$DEBUGGERHOME + +UTILSDIR = ../../../src/libs QT = core network win32:CONFIG+=console -HEADERS += trkutils.h \ -trkfunctor.h \ -trkdevice.h \ +HEADERS += \ + $$DEBUGGERHOME/trkutils.h \ + $$DEBUGGERHOME/trkfunctor.h \ + $$PWD/trkdevice.h \ SOURCES += \ - adapter.cpp \ - trkutils.cpp \ - trkdevice.cpp + $$DEBUGGERHOME/trkutils.cpp \ + $$PWD/trkdevice.cpp \ + $$PWD/adapter.cpp \ diff --git a/tests/manual/trk/runner.cpp b/tests/manual/trk/runner.cpp index eeb080ca0d8ec2128e0c2ab79a0f3099b0cb7359..4724df4d1799cb1bacb82c91c4ed31ec82355646 100755 --- a/tests/manual/trk/runner.cpp +++ b/tests/manual/trk/runner.cpp @@ -27,10 +27,8 @@ ** **************************************************************************/ -#include "trkutils.h" -#include "trkdevicex.h" +#include "symbianadapter.h" -#include <QtCore/QCoreApplication> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> @@ -43,23 +41,53 @@ #include <QtCore/QTextStream> #include <QtCore/QTimer> +#include <QtGui/QAction> #include <QtGui/QApplication> +#include <QtGui/QMainWindow> #include <QtGui/QKeyEvent> #include <QtGui/QTextBlock> #include <QtGui/QTextEdit> +#include <QtGui/QToolBar> #include <QtNetwork/QTcpServer> #include <QtNetwork/QTcpSocket> #include <QtNetwork/QLocalServer> #include <QtNetwork/QLocalSocket> +/* +fetch-register p info registers +set-register P set +binary-download X load, set +read-aux-vector qXfer:auxv:read info auxv +symbol-lookup qSymbol Detecting multiple threads +attach vAttach attach +verbose-resume vCont Stepping or resuming multiple threads +run vRun run +software-breakpoint Z0 break +hardware-breakpoint Z1 hbreak +write-watchpoint Z2 watch +read-watchpoint Z3 rwatch +access-watchpoint Z4 awatch +target-features qXfer:features:read set architecture +library-info qXfer:libraries:read info sharedlibrary +memory-map qXfer:memory-map:read info mem +read-spu-object qXfer:spu:read info spu +write-spu-object qXfer:spu:write info spu +get-thread-local- +storage-address qGetTLSAddr Displaying __thread variables +supported-packets qSupported Remote communications parameters +pass-signals QPassSignals handle signal +hostio-close-packet vFile:close remote get, remote put +hostio-open-packet vFile:open remote get, remote put +hostio-pread-packet vFile:pread remote get, remote put +hostio-pwrite-packet vFile:pwrite remote get, remote put +hostio-unlink-packet vFile:unlink remote delete +*/ using namespace trk; enum { KnownRegisters = RegisterPSGdb + 1}; -#define CB(s) Callback(this, &Adapter::s) - static const char *registerNames[KnownRegisters] = { "A1", "A2", "A3", "A4", @@ -81,1529 +109,55 @@ static QByteArray dumpRegister(int n, uint value) ba += '#'; ba += QByteArray::number(n); } - ba += "=0x" + hexNumber(value); + ba += "=" + hexxNumber(value); return ba; } + /////////////////////////////////////////////////////////////////////// // -// Adapter +// RunnerGui // /////////////////////////////////////////////////////////////////////// -class Adapter : public QObject +class TextEdit : public QTextEdit { Q_OBJECT -public: - typedef TrkFunctor1<const TrkResult &> Callback; - - Adapter(); - ~Adapter(); - void setGdbServerName(const QString &name); - QString gdbServerIP() const; - uint gdbServerPort() const; - void setTrkServerName(const QString &name) { m_trkServerName = name; } - void setVerbose(int verbose) { m_verbose = verbose; } - void setSerialFrame(bool b) { m_serialFrame = b; } - void setRegisterEndianness(Endianness r) { m_registerEndianness = r; } - void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; } - -public slots: - void startServer(); - -private slots: - void handleResult(const trk::TrkResult &data); - signals: - void output(const QString &senderName, const QString &data); - -private slots: - void handleProcError(QProcess::ProcessError error); - void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus); - void handleProcReadyReadStandardError(); - void handleProcReadyReadStandardOutput(); - void handleProcStarted(); - void handleProcStateChanged(QProcess::ProcessState newState); - void run(); - void startGdb(); - void writeToGdb(const QString &msg); - -private: - friend class RunnerGui; - void connectProcess(QProcess *proc); - void sendOutput(QObject *sender, const QString &data); - void sendOutput(const QString &data) { sendOutput(0, data); } - - QString m_endianness; - QString m_trkServerName; // - QString m_gdbServerName; // 127.0.0.1:(2222+uid) - - QProcess m_gdbProc; - QProcess m_rfcommProc; - -public: - // - // TRK - // - - bool openTrkPort(const QString &port, QString *errorMessage); // or server name for local server - void sendTrkMessage(byte code, - Callback callBack = Callback(), - const QByteArray &data = QByteArray(), - const QVariant &cookie = QVariant(), - bool invokeOnFailure = false); - - // convenience messages - void sendTrkInitialPing(); - void sendTrkContinue(); - void waitForTrkFinished(); - void sendTrkAck(byte token); - - // kill process and breakpoints - void cleanUp(); - - void handleCpuType(const TrkResult &result); - void handleCreateProcess(const TrkResult &result); - void handleClearBreakpoint(const TrkResult &result); - void handleSignalContinue(const TrkResult &result); - void handleWaitForFinished(const TrkResult &result); - void handleStop(const TrkResult &result); - void handleSupportMask(const TrkResult &result); - void handleTrkVersions(const TrkResult &result); - void handleDisconnect(const TrkResult &result); - - void handleAndReportCreateProcess(const TrkResult &result); - void handleAndReportReadRegisters(const TrkResult &result); - QByteArray memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const; - void handleAndReportSetBreakpoint(const TrkResult &result); - void handleReadMemoryBuffered(const TrkResult &result); - void handleReadMemoryUnbuffered(const TrkResult &result); - void handleStepRange(const TrkResult &result); - void reportReadMemoryBuffered(const TrkResult &result); - void reportToGdb(const TrkResult &result); - - void clearTrkBreakpoint(const Breakpoint &bp); - - void handleSetTrkBreakpoint(const TrkResult &result); - void setTrkBreakpoint(const Breakpoint &bp); - - void readMemory(uint addr, uint len); - void startInferiorIfNeeded(); - void interruptInferior(); - - TrkDevice m_trkDevice; - - QList<Breakpoint> m_breakpoints; - - // - // Gdb - // - Q_SLOT void handleGdbConnection(); - Q_SLOT void readFromGdb(); - void handleGdbResponse(const QByteArray &ba); - void sendGdbMessage(const QByteArray &msg, - const QByteArray &logNote = QByteArray()); - void sendGdbMessageAfterSync(const QByteArray &msg, - const QByteArray &logNote = QByteArray()); - void sendGdbAckMessage(); - bool sendGdbPacket(const QByteArray &packet, bool doFlush); - void executeGdbCommand(const QString &msg); - - void logMessage(const QString &msg, bool force = false); - Q_SLOT void trkLogMessage(const QString &msg); - - QTcpServer m_gdbServer; - QPointer<QTcpSocket> m_gdbConnection; - QByteArray m_gdbReadBuffer; - bool m_gdbAckMode; - - // Debuggee state - Session m_session; // global-ish data (process id, target information) - Snapshot m_snapshot; // local-ish data (memory and registers) - int m_verbose; - Endianness m_registerEndianness; - bool m_serialFrame; - bool m_startInferiorTriggered; - bool m_bufferedMemoryRead; -}; - -Adapter::Adapter() -{ - m_gdbAckMode = true; - m_verbose = 2; - m_registerEndianness = LittleEndian; - //m_serialFrame = true; - m_serialFrame = false; - m_startInferiorTriggered = false; - //m_bufferedMemoryRead = true; - m_bufferedMemoryRead = false; - // m_breakpoints.append(Breakpoint(0x0040)); // E32Main - m_breakpoints.append(Breakpoint(0x0cc8)); // E32Main - m_trkServerName = "/dev/rfcomm0"; - - m_endianness = "little"; - - uid_t userId = getuid(); - m_gdbServerName = QString("127.0.0.1:%1").arg(2222 + userId); - - m_gdbProc.setObjectName("GDB PROCESS"); - connectProcess(&m_gdbProc); - - m_rfcommProc.setObjectName("RFCOMM PROCESS"); - connectProcess(&m_rfcommProc); - - connect(&m_trkDevice, SIGNAL(logMessage(QString)), - this, SLOT(trkLogMessage(QString))); -} - -Adapter::~Adapter() -{ - m_gdbServer.close(); - logMessage("Shutting down.\n", true); -} - -void Adapter::trkLogMessage(const QString &msg) -{ - logMessage("TRK " + msg); -} - -void Adapter::setGdbServerName(const QString &name) -{ - m_gdbServerName = name; -} - -QString Adapter::gdbServerIP() const -{ - int pos = m_gdbServerName.indexOf(':'); - if (pos == -1) - return m_gdbServerName; - return m_gdbServerName.left(pos); -} - -uint Adapter::gdbServerPort() const -{ - int pos = m_gdbServerName.indexOf(':'); - if (pos == -1) - return 0; - return m_gdbServerName.mid(pos + 1).toUInt(); -} - -void Adapter::startServer() -{ - QString errorMessage; - if (!openTrkPort(m_trkServerName, &errorMessage)) { - logMessage(errorMessage, true); - logMessage("LOOPING"); - QTimer::singleShot(1000, this, SLOT(startServer())); - return; - } - - sendTrkInitialPing(); - sendTrkMessage(0x01); // Connect - sendTrkMessage(0x05, CB(handleSupportMask)); - sendTrkMessage(0x06, CB(handleCpuType)); - sendTrkMessage(0x04, CB(handleTrkVersions)); // Versions - //sendTrkMessage(0x09); // Unrecognized command - //sendTrkMessage(0x4a, 0, - // "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File - //sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File - - logMessage("Connected to TRK server"); - - if (!m_gdbServer.listen(QHostAddress(gdbServerIP()), gdbServerPort())) { - logMessage(QString("Unable to start the gdb server at %1: %2.") - .arg(m_gdbServerName).arg(m_gdbServer.errorString()), true); - QCoreApplication::exit(5); - return; - } - - logMessage(QString("Gdb server running on %1.\nRegister endianness: %3.") - .arg(m_gdbServerName).arg(m_registerEndianness), true); - - connect(&m_gdbServer, SIGNAL(newConnection()), - this, SLOT(handleGdbConnection())); - - startGdb(); -} - -void Adapter::logMessage(const QString &msg, bool force) -{ - if (m_verbose || force) - emit output(QString(), msg); -} - -// -// Gdb -// -void Adapter::handleGdbConnection() -{ - logMessage("HANDLING GDB CONNECTION"); - - m_gdbConnection = m_gdbServer.nextPendingConnection(); - connect(m_gdbConnection, SIGNAL(disconnected()), - m_gdbConnection, SLOT(deleteLater())); - connect(m_gdbConnection, SIGNAL(readyRead()), - this, SLOT(readFromGdb())); - m_startInferiorTriggered = false; -} - -static inline QString msgGdbPacket(const QString &p) -{ - return QLatin1String("gdb: ") + p; -} - -void Adapter::readFromGdb() -{ - QByteArray packet = m_gdbConnection->readAll(); - m_gdbReadBuffer.append(packet); - - logMessage("gdb: -> " + QString::fromAscii(packet)); - if (packet != m_gdbReadBuffer) - logMessage("buffer: " + m_gdbReadBuffer); - - QByteArray &ba = m_gdbReadBuffer; - while (ba.size()) { - char code = ba.at(0); - ba = ba.mid(1); - - if (code == '+') { - //logMessage("ACK"); - continue; - } - - if (code == '-') { - logMessage("NAK: Retransmission requested"); - continue; - } - - if (code == char(0x03)) { - logMessage("INTERRUPT RECEIVED"); - interruptInferior(); - continue; - } - - if (code != '$') { - logMessage("Broken package (2) " + quoteUnprintableLatin1(ba) - + hexNumber(code)); - continue; - } - - int pos = ba.indexOf('#'); - if (pos == -1) { - logMessage("Invalid checksum format in " - + quoteUnprintableLatin1(ba)); - continue; - } - - bool ok = false; - uint checkSum = ba.mid(pos + 1, 2).toUInt(&ok, 16); - if (!ok) { - logMessage("Invalid checksum format 2 in " - + quoteUnprintableLatin1(ba)); - return; - } - - //logMessage(QString("Packet checksum: %1").arg(checkSum)); - byte sum = 0; - for (int i = 0; i < pos; ++i) - sum += ba.at(i); - - if (sum != checkSum) { - logMessage(QString("ERROR: Packet checksum wrong: %1 %2 in " - + quoteUnprintableLatin1(ba)).arg(checkSum).arg(sum)); - } - - QByteArray response = ba.left(pos); - ba.remove(0, pos + 3); - handleGdbResponse(response); - } -} - -bool Adapter::sendGdbPacket(const QByteArray &packet, bool doFlush) -{ - if (!m_gdbConnection || m_gdbConnection->state() != QAbstractSocket::ConnectedState) { - logMessage(QString::fromLatin1("Cannot write to gdb: Not connected (%1)").arg(QString::fromLatin1(packet)), true); - return false; - } - if (m_gdbConnection->write(packet) == -1) { - logMessage(QString::fromLatin1("Cannot write to gdb: %1 (%2)").arg(m_gdbConnection->errorString()).arg(QString::fromLatin1(packet)), true); - return false; - } - if (doFlush) - m_gdbConnection->flush(); - return true; -} - -void Adapter::sendGdbAckMessage() -{ - if (!m_gdbAckMode) - return; - QByteArray packet = "+"; - logMessage("gdb: <- " + packet); - sendGdbPacket(packet, false); -} - -void Adapter::sendGdbMessage(const QByteArray &msg, const QByteArray &logNote) -{ - byte sum = 0; - for (int i = 0; i != msg.size(); ++i) - sum += msg.at(i); - - char checkSum[30]; - qsnprintf(checkSum, sizeof(checkSum) - 1, "%02x ", sum); - - //logMessage(QString("Packet checksum: %1").arg(sum)); - - QByteArray packet; - packet.append("$"); - packet.append(msg); - packet.append('#'); - packet.append(checkSum); - int pad = qMax(0, 24 - packet.size()); - logMessage("gdb: <- " + packet + QByteArray(pad, ' ') + logNote); - sendGdbPacket(packet, true); -} - -void Adapter::sendGdbMessageAfterSync(const QByteArray &msg, const QByteArray &logNote) -{ - QByteArray ba = msg + char(1) + logNote; - sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, CB(reportToGdb), "", ba); // Answer gdb -} - -void Adapter::reportToGdb(const TrkResult &result) -{ - QByteArray message = result.cookie.toByteArray(); - QByteArray note; - int pos = message.lastIndexOf(char(1)); // HACK - if (pos != -1) { - note = message.mid(pos + 1); - message = message.left(pos); - } - message.replace("@CODESEG@", hexNumber(m_session.codeseg)); - message.replace("@DATASEG@", hexNumber(m_session.dataseg)); - message.replace("@PID@", hexNumber(m_session.pid)); - message.replace("@TID@", hexNumber(m_session.tid)); - sendGdbMessage(message, note); -} - -static QByteArray trkBreakpointMessage(uint addr, int len, int pid, bool armMode = true) -{ - QByteArray ba; - appendByte(&ba, 0x82); // unused option - appendByte(&ba, armMode /*bp.mode == ArmMode*/ ? 0x00 : 0x01); - appendInt(&ba, addr); - appendInt(&ba, len); - appendInt(&ba, 0x00000001); - appendInt(&ba, pid); - appendInt(&ba, 0xFFFFFFFF); - return ba; -} - -void Adapter::handleGdbResponse(const QByteArray &response) -{ - // http://sourceware.org/gdb/current/onlinedocs/gdb_34.html - if (0) {} - - else if (response == "!") { - sendGdbAckMessage(); - sendGdbMessage("", "extended mode not enabled"); - //sendGdbMessage("OK", "extended mode enabled"); - } - - else if (response.startsWith("?")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Query halted"))); - // Indicate the reason the target halted. - // The reply is the same as for step and continue. - sendGdbAckMessage(); - startInferiorIfNeeded(); - sendGdbMessage("T05library:r;", "target halted (library load)"); - // trap 05 - // sendGdbMessage("S05", "target halted (trap)"); - } - - else if (response == "c") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("continue"))); - sendGdbAckMessage(); - QByteArray ba; - appendByte(&ba, 0); // options - appendInt(&ba, 0); // start address - appendInt(&ba, 0); // end address - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x18, Callback(), ba); - // FIXME: should be triggered by real stop - //sendGdbMessageAfterSync("S11", "target stopped"); - } - - else if (response.startsWith("C")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("continue with signal"))); - // C sig[;addr] Continue with signal sig (hex signal number) - //Reply: See section D.3 Stop Reply Packets, for the reply specifications. - sendGdbAckMessage(); - bool ok = false; - uint signalNumber = response.mid(1).toInt(&ok, 16); - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x18, CB(handleSignalContinue), ba, signalNumber); // Continue - } - - else if (response.startsWith("D")) { - sendGdbAckMessage(); - sendGdbMessage("OK", "shutting down"); - qApp->quit(); - } - - else if (response == "g") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("read registers"))); - // Read general registers. - //sendGdbMessage("00000000", "read registers"); - sendGdbAckMessage(); - QByteArray ba; - appendByte(&ba, 0); // Register set, only 0 supported - appendShort(&ba, 0); - appendShort(&ba, RegisterCount - 1); // last register - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x12, CB(handleAndReportReadRegisters), ba, QVariant(), true); - } - - else if (response.startsWith("Hc")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Set thread & continue"))); - // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). - // for step and continue operations - //$Hc-1#09 - sendGdbAckMessage(); - sendGdbMessage("OK", "Set current thread for step & continue"); - } - - else if (response.startsWith("Hg")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Set thread"))); - // Set thread for subsequent operations (`m', `M', `g', `G', et.al.). - // for 'other operations. 0 - any thread - //$Hg0#df - sendGdbAckMessage(); - m_session.currentThread = response.mid(2).toInt(0, 16); - sendGdbMessage("OK", "Set current thread " - + QByteArray::number(m_session.currentThread)); - } - - else if (response == "k") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("kill"))); - // kill - sendGdbAckMessage(); - QByteArray ba; - appendByte(&ba, 0); // Sub-command: Delete Process - appendInt(&ba, m_session.pid); - sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item - sendGdbMessageAfterSync("", "process killed"); - } + void executeCommand(QString); - else if (response.startsWith("m")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("read memory"))); - // m addr,length - sendGdbAckMessage(); - uint addr = 0, len = 0; - do { - const int pos = response.indexOf(','); - if (pos == -1) - break; - bool ok; - addr = response.mid(1, pos - 1).toUInt(&ok, 16); - if (!ok) - break; - len = response.mid(pos + 1).toUInt(&ok, 16); - if (!ok) - break; - } while (false); - if (len) { - readMemory(addr, len); - } else { - sendGdbMessage("E20", "Error " + response); - } - } - else if (response.startsWith("p")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("read register"))); - // 0xf == current instruction pointer? - //sendGdbMessage("0000", "current IP"); - sendGdbAckMessage(); - #if 0 - A1 = 0, first integer-like argument - A4 = 3, last integer-like argument - AP = 11, - IP = 12, - SP = 13, Contains address of top of stack - LR = 14, address to return to from a function call - PC = 15, Contains program counter - F0 = 16, first floating point register - F3 = 19, last floating point argument register - F7 = 23, last floating point register - FPS = 24, floating point status register - PS = 25, Contains processor status - WR0, WMMX data registers. - WR15 = WR0 + 15, - WC0, WMMX control registers. - WCSSF = WC0 + 2, - WCASF = WC0 + 3, - WC7 = WC0 + 7, - WCGR0, WMMX general purpose registers. - WCGR3 = WCGR0 + 3, - WCGR7 = WCGR0 + 7, - NUM_REGS, - - // Other useful registers. - FP = 11, Frame register in ARM code, if used. - THUMB_FP = 7, Frame register in Thumb code, if used. - NUM_ARG_REGS = 4, - LAST_ARG = A4, - NUM_FP_ARG_REGS = 4, - LAST_FP_ARG = F3 - #endif - bool ok = false; - const uint registerNumber = response.mid(1).toInt(&ok, 16); - QByteArray logMsg = "Read Register"; - if (registerNumber == RegisterPSGdb) { - QByteArray ba; - appendInt(&ba, m_snapshot.registers[RegisterPSTrk], m_registerEndianness); - logMsg += dumpRegister(registerNumber, m_snapshot.registers[RegisterPSTrk]); - sendGdbMessage(ba.toHex(), logMsg); - } else if (registerNumber < RegisterCount) { - QByteArray ba; - appendInt(&ba, m_snapshot.registers[registerNumber], m_registerEndianness); - logMsg += dumpRegister(registerNumber, m_snapshot.registers[registerNumber]); - sendGdbMessage(ba.toHex(), logMsg); - } else { - sendGdbMessage("0000", "read single unknown register #" + QByteArray::number(registerNumber)); - //sendGdbMessage("E01", "read single unknown register"); - } - } - - else if (response == "qAttached") { - //$qAttached#8f - // 1: attached to an existing process - // 0: created a new process - sendGdbAckMessage(); - sendGdbMessage("0", "new process created"); - //sendGdbMessage("1", "attached to existing process"); - //sendGdbMessage("E01", "new process created"); - } - - else if (response.startsWith("qC")) { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("query thread id"))); - // Return the current thread ID - //$qC#b4 - sendGdbAckMessage(); - startInferiorIfNeeded(); - sendGdbMessageAfterSync("QC@TID@"); - } - - else if (response.startsWith("qSupported")) { - //$qSupported#37 - //$qSupported:multiprocess+#c6 - //logMessage("Handling 'qSupported'"); - sendGdbAckMessage(); - if (0) - sendGdbMessage(QByteArray(), "nothing supported"); - else - sendGdbMessage( - "PacketSize=7cf;" - //"QPassSignals+;" - "qXfer:libraries:read+;" - //"qXfer:auxv:read+;" - "qXfer:features:read+"); - } - - else if (response == "qPacketInfo") { - // happens with gdb 6.4.50.20060226-cvs / CodeSourcery - // deprecated by qSupported? - sendGdbAckMessage(); - sendGdbMessage("", "FIXME: nothing?"); - } - - else if (response == "qOffsets") { - sendGdbAckMessage(); - startInferiorIfNeeded(); - sendGdbMessageAfterSync("TextSeg=@CODESEG@;DataSeg=@DATASEG@"); +public slots: + void handleOutput(const QString &senderName, const QString &data) + { + QString str = senderName + data; + str.replace("\\t", QString(QChar(0x09))); + str.replace("\\n", QString("\n")); + append(str); + + QTextCursor tc = textCursor(); + tc.movePosition(QTextCursor::End); + setTextCursor(tc); + /* + int pos1 = str.indexOf("#"); + int pos2 = str.indexOf(")", pos1); + if (pos1 != -1 && pos2 != -1) + str = str.left(pos1) + "<b>" + str.mid(pos1, pos2 - pos1 + 1) + + "</b> " + str.mid(pos2 + 1); + insertHtml(str + "\n"); + */ + setCurrentCharFormat(QTextCharFormat()); + ensureCursorVisible(); } - else if (response == "qSymbol::") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("notify can handle symbol lookup"))); - // Notify the target that GDB is prepared to serve symbol lookup requests. - sendGdbAckMessage(); - if (1) - sendGdbMessage("OK", "no further symbols needed"); + void keyPressEvent(QKeyEvent *ev) + { + if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_Return) + emit executeCommand(textCursor().block().text()); else - sendGdbMessage("qSymbol:" + QByteArray("_Z7E32Mainv").toHex(), "ask for more"); - } - - else if (response.startsWith("qXfer:features:read:target.xml:")) { - // $qXfer:features:read:target.xml:0,7ca#46...Ack - sendGdbAckMessage(); - sendGdbMessage("l<target><architecture>symbianelf</architecture></target>"); - } - - else if (response == "QStartNoAckMode") { - //$qSupported#37 - //logMessage("Handling 'QStartNoAckMode'"); - sendGdbAckMessage(); - sendGdbMessage("OK", "ack no-ack mode"); - m_gdbAckMode = false; - } - - else if (response.startsWith("QPassSignals")) { - // list of signals to pass directly to inferior - // $QPassSignals:e;10;14;17;1a;1b;1c;21;24;25;4c;#8f - // happens only if "QPassSignals+;" is qSupported - sendGdbAckMessage(); - // FIXME: use the parameters - sendGdbMessage("OK", "passing signals accepted"); - } - - else if (response == "s") { - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Step range"))); - sendGdbAckMessage(); - QByteArray ba; - appendByte(&ba, 0); // options - appendInt(&ba, m_snapshot.registers[RegisterPC]); // start address - appendInt(&ba, m_snapshot.registers[RegisterPC] + 4); // end address - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x19, CB(handleStepRange), ba, "Step range"); - // FIXME: should be triggered by "real" stop" - //sendGdbMessageAfterSync("S05", "target halted"); - } - - else if (response == "vCont?") { - // actions supported by the vCont packet - sendGdbAckMessage(); - sendGdbMessage(""); // we don't support vCont. - //sendGdbMessage("vCont;c"); - } - - //else if (response.startsWith("vCont")) { - // // vCont[;action[:thread-id]]...' - //} - - else if (response.startsWith("vKill")) { - // kill - sendGdbAckMessage(); - QByteArray ba; - appendByte(&ba, 0); // Sub-command: Delete Process - appendInt(&ba, m_session.pid); - sendTrkMessage(0x41, Callback(), ba, "Delete process"); // Delete Item - sendGdbMessageAfterSync("", "process killed"); - } - - else if (response.startsWith("Z0,")) { // Insert breakpoint - if (m_verbose) - logMessage(msgGdbPacket(QLatin1String("Insert breakpoint"))); - // $z0,786a4ccc,4#99 - const int pos = response.lastIndexOf(','); - bool ok = false; - const uint addr = response.mid(3, pos - 1).toInt(&ok, 16); - const uint len = response.mid(pos + 1).toInt(&ok, 16); - if (m_verbose) - logMessage(QString::fromLatin1("Inserting breakpoint at 0x%1, %2").arg(addr,0 ,16).arg(len)); - - //---IDE------------------------------------------------------ - // Command: 0x1B Set Break - //BreakType: 0x82 - // Options: 0x00 - // Address: 0x78674340 (2020033344) i.e + 0x00000340 - // Length: 0x00000001 (1) - // Count: 0x00000000 (0) - //ProcessID: 0x000001b5 (437) - // ThreadID: 0xffffffff (-1) - // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00 - // 00 00 01 B5 FF FF FF FF] - const QByteArray ba = trkBreakpointMessage(addr, len, m_session.pid); - sendTrkMessage(0x1B, CB(handleAndReportSetBreakpoint), ba); - //m_session.toekn - - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] - } else if (response.startsWith("qPart:") || response.startsWith("qXfer:")) { - QByteArray data = response.mid(1 + response.indexOf(':')); - // "qPart:auxv:read::0,147": Read OS auxiliary data (see info aux) - bool handled = false; - if (data.startsWith("auxv:read::")) { - const int offsetPos = data.lastIndexOf(':') + 1; - const int commaPos = data.lastIndexOf(','); - if (commaPos != -1) { - bool ok1 = false, ok2 = false; - const int offset = data.mid(offsetPos, commaPos - offsetPos).toInt(&ok1, 16); - const int length = data.mid(commaPos + 1).toInt(&ok2, 16); - if (ok1 && ok2) { - const QString msg = QString::fromLatin1("Read of OS auxilary vector (%1, %2) not implemented.").arg(offset).arg(length); - logMessage(msgGdbPacket(msg), true); - sendGdbMessage("E20", msg.toLatin1()); - handled = true; - } - } - } // auxv read - if (!handled) { - const QString msg = QLatin1String("FIXME unknown 'XFER'-request: ") + QString::fromAscii(response); - logMessage(msgGdbPacket(msg), true); - sendGdbMessage("E20", msg.toLatin1()); - } - } // qPart/qXfer - else { - logMessage(msgGdbPacket(QLatin1String("FIXME unknown: ") + QString::fromAscii(response))); - } -} - -void Adapter::executeGdbCommand(const QString &msg) -{ - logMessage("EXECUTING GDB COMMAND " + msg); - if (msg == "S") - writeToGdb("-exec-interrupt"); - if (msg == "I") - interruptInferior(); - else - writeToGdb(msg); -} - -bool Adapter::openTrkPort(const QString &port, QString *errorMessage) -{ - connect(&m_trkDevice, SIGNAL(messageReceived(trk::TrkResult)), - this, SLOT(handleResult(trk::TrkResult))); - if (m_verbose > 1) - m_trkDevice.setVerbose(true); - m_trkDevice.setSerialFrame(m_serialFrame); - return m_trkDevice.open(port, errorMessage); -} - -void Adapter::sendTrkMessage(byte code, Callback callBack, - const QByteArray &data, const QVariant &cookie, bool invokeOnFailure) -{ - m_trkDevice.sendTrkMessage(code, callBack, data, cookie, invokeOnFailure); -} - -void Adapter::sendTrkInitialPing() -{ - m_trkDevice.sendTrkInitialPing(); -} - -void Adapter::sendTrkContinue() -{ - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x18, Callback(), ba, "CONTINUE"); -} - -void Adapter::waitForTrkFinished() -{ - // initiate one last roundtrip to ensure all is flushed - sendTrkMessage(0x0, CB(handleWaitForFinished)); -} - -void Adapter::sendTrkAck(byte token) -{ - logMessage(QString("SENDING ACKNOWLEDGEMENT FOR TOKEN %1").arg(int(token))); - m_trkDevice.sendTrkAck(token); -} - -void Adapter::handleResult(const TrkResult &result) -{ - if (result.isDebugOutput) { - logMessage(QLatin1String("APPLICATION OUTPUT: ") + QString::fromAscii(result.data)); - return; - } - QByteArray prefix = "READ BUF: "; - QByteArray str = result.toString().toUtf8(); - switch (result.code) { - case 0x80: // ACK - break; - case 0xff: { // NAK. This mostly means transmission error, not command failed. - QString logMsg; - QTextStream(&logMsg) << prefix << "NAK: for token=" << result.token << " ERROR: " << errorMessage(result.data.at(0)) << ' ' << str; - logMessage(logMsg, true); - break; - } - case 0x90: { // Notified Stopped - // 90 01 78 6a 40 40 00 00 07 23 00 00 07 24 00 00 - const char *data = result.data.data(); - const uint addr = extractInt(data); //code address: 4 bytes; code base address for the library - const uint pid = extractInt(data + 4); // ProcessID: 4 bytes; - const uint tid = extractInt(data + 8); // ThreadID: 4 bytes - logMessage(prefix + QString::fromLatin1("NOTE: PID %1/TID %2 " - "STOPPED at 0x%3").arg(pid).arg(tid).arg(addr, 0, 16)); - sendTrkAck(result.token); - if (addr) { - // Todo: Do not send off GdbMessages if a synced gdb - // query is pending, queue instead - //sendGdbMessage("S05", "Target stopped"); - } else { - if (m_verbose) - logMessage(QLatin1String("Ignoring stop at 0")); - } - break; - } - case 0x91: { // Notify Exception (obsolete) - logMessage(prefix + "NOTE: EXCEPTION " + str); - sendTrkAck(result.token); - break; - } - case 0x92: { // - logMessage(prefix + "NOTE: INTERNAL ERROR: " + str); - sendTrkAck(result.token); - break; - } - - // target->host OS notification - case 0xa0: { // Notify Created - const char *data = result.data.data(); - const byte error = result.data.at(0); - const byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2. - const uint pid = extractInt(data + 2); // ProcessID: 4 bytes; - const uint tid = extractInt(data + 6); //threadID: 4 bytes - const uint codeseg = extractInt(data + 10); //code address: 4 bytes; code base address for the library - const uint dataseg = extractInt(data + 14); //data address: 4 bytes; data base address for the library - const uint len = extractShort(data + 18); //length: 2 bytes; length of the library name string to follow - const QByteArray name = result.data.mid(20, len); // name: library name - m_session.modules += QString::fromAscii(name); - QString logMsg; - QTextStream str(&logMsg); - str<< prefix << " NOTE: LIBRARY LOAD: token=" << result.token; - if (error) - str<< " ERROR: " << int(error); - str << " TYPE: " << int(type) << " PID: " << pid << " TID: " << tid; - str.setIntegerBase(16); - str << " CODE: 0x" << codeseg << " DATA: 0x" << dataseg; - str.setIntegerBase(10); - str << " NAME: '" << name << '\''; - logMessage(logMsg); - sendTrkContinue(); - break; - } - case 0xa1: { // NotifyDeleted - const ushort itemType = (unsigned char)result.data.at(1); - const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0); - const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString(); - if (!name.isEmpty()) - m_session.modules.removeAll(name); - logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3") - .arg(QString::fromAscii(prefix)) - .arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")) - .arg(name)); - sendTrkAck(result.token); - break; - } - case 0xa2: { // NotifyProcessorStarted - logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str); - sendTrkAck(result.token); - break; - } - case 0xa6: { // NotifyProcessorStandby - logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str); - sendTrkAck(result.token); - break; - } - case 0xa7: { // NotifyProcessorReset - logMessage(prefix + "NOTE: PROCESSOR RESET: " + str); - sendTrkAck(result.token); - break; - } - default: { - logMessage(prefix + "INVALID: " + str); - break; - } - } -} - -void Adapter::handleCpuType(const TrkResult &result) -{ - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 03 00 04 00 00 04 00 00 00] - m_session.cpuMajor = result.data[1]; - m_session.cpuMinor = result.data[2]; - m_session.bigEndian = result.data[3]; - m_session.defaultTypeSize = result.data[4]; - m_session.fpTypeSize = result.data[5]; - m_session.extended1TypeSize = result.data[6]; - //m_session.extended2TypeSize = result.data[6]; - QString logMsg; - QTextStream(&logMsg) << "HANDLE CPU TYPE: CPU=" << m_session.cpuMajor << '.' - << m_session.cpuMinor << " bigEndian=" << m_session.bigEndian - << " defaultTypeSize=" << m_session.defaultTypeSize - << " fpTypeSize=" << m_session.fpTypeSize - << " extended1TypeSize=" << m_session.extended1TypeSize; - logMessage(logMsg); -} - -void Adapter::setTrkBreakpoint(const Breakpoint &bp) -{ - //---IDE------------------------------------------------------ - // Command: 0x1B Set Break - //BreakType: 0x82 - // Options: 0x00 - // Address: 0x78674340 (2020033344) i.e + 0x00000340 - // Length: 0x00000001 (1) - // Count: 0x00000000 (0) - //ProcessID: 0x000001b5 (437) - // ThreadID: 0xffffffff (-1) - // [1B 09 82 00 78 67 43 40 00 00 00 01 00 00 00 00 - // 00 00 01 B5 FF FF FF FF] - const QByteArray ba = trkBreakpointMessage(m_session.codeseg + bp.offset, 1, m_session.pid); - sendTrkMessage(0x1B, CB(handleSetTrkBreakpoint), ba); - - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] -} - -void Adapter::handleSetTrkBreakpoint(const TrkResult &result) -{ - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] - const uint bpnr = extractInt(result.data.data()); - if (m_verbose) - logMessage(QString::fromLatin1("SET BREAKPOINT %1 %2").arg(bpnr).arg(stringFromArray(result.data.data()))); -} - -void Adapter::handleCreateProcess(const TrkResult &result) -{ - // 40 00 00] - //logMessage(" RESULT: " + result.toString()); - // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00] - const char *data = result.data.data(); - m_session.pid = extractInt(data + 1); - m_session.tid = extractInt(data + 5); - m_session.codeseg = extractInt(data + 9); - m_session.dataseg = extractInt(data + 13); - - logMessage("PID: 0x" + hexNumber(m_session.pid)); - logMessage("TID: 0x" + hexNumber(m_session.tid)); - logMessage("COD: 0x" + hexNumber(m_session.codeseg)); - logMessage("DAT: 0x" + hexNumber(m_session.dataseg)); - - writeToGdb("add-symbol-file filebrowseapp.sym 0x" - + hexNumber(m_session.codeseg)); - writeToGdb("symbol-file filebrowseapp.sym"); - - foreach (const Breakpoint &bp, m_breakpoints) - setTrkBreakpoint(bp); - - sendTrkContinue(); - -#if 0 - //setTrkBreakpoint(0x0000, ArmMode); - //clearTrkBreakpoint(0x0000); - -#if 1 - //---IDE------------------------------------------------------ - // Command: 0x42 Read Info - // [42 0C 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F - // 72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00] - sendTrkMessage(0x42, CB(handleReadInfo), - "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " - "72 70 68 69 63 44 4C 4C 32 2E 64 6C 6C 00"); - //sendTrkMessage(0x42, CB(handleReadInfo), - // "00 01 00 00 00 00"); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x20 Unspecified general OS-related error - // [80 0C 20] - - - //---IDE------------------------------------------------------ - // Command: 0x42 Read Info - // [42 0D 00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F - // 72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00] - sendTrkMessage(0x42, CB(handleReadInfo), - "00 06 00 00 00 00 00 14 50 6F 6C 79 6D 6F " - "72 70 68 69 63 44 4C 4C 31 2E 64 6C 6C 00"); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x20 Unspecified general OS-related error - // [80 0D 20] -#endif - - //sendTrkMessage(0x18, CB(handleStop), - // "01 " + formatInt(m_session.pid) + formatInt(m_session.tid)); - - //---IDE------------------------------------------------------ - // Command: 0x18 Continue - //ProcessID: 0x000001B5 (437) - // ThreadID: 0x000001B6 (438) - // [18 0E 00 00 01 B5 00 00 01 B6] - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - sendTrkMessage(0x18, CB(handleContinue), ba); - //sendTrkMessage(0x18, CB(handleContinue), - // formatInt(m_session.pid) + "ff ff ff ff"); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 0E 00] -#endif -} - -void Adapter::handleAndReportReadRegisters(const TrkResult &result) -{ - logMessage(" RESULT: " + result.toString()); - // [80 0B 00 00 00 00 00 C9 24 FF BC 00 00 00 00 00 - // 60 00 00 00 00 00 00 78 67 79 70 00 00 00 00 00...] - - const char *data = result.data.data() + 1; // Skip ok byte - for (int i = 0; i < RegisterCount; ++i) { - m_snapshot.registers[i] = extractInt(data + 4 * i); - } - QByteArray ba; - for (int i = 0; i < 16; ++i) { - const uint reg = m_registerEndianness == LittleEndian - ? swapEndian(m_snapshot.registers[i]) : m_snapshot.registers[i]; - ba += hexNumber(reg, 8); - } - QByteArray logMsg = "REGISTER CONTENTS: "; - if (m_verbose > 1) { - for (int i = 0; i < RegisterCount; ++i) { - logMsg += dumpRegister(i, m_snapshot.registers[i]); - logMsg += ' '; - } - } - sendGdbMessage(ba, logMsg); -} - -static inline QString msgMemoryReadError(int code, uint addr, uint len = 0) -{ - const QString lenS = len ? QString::number(len) : QLatin1String("<unknown>"); - return QString::fromLatin1("Memory read error %1 at: 0x%2 %3").arg(code).arg(addr, 0 ,16).arg(lenS); -} - -void Adapter::handleReadMemoryBuffered(const TrkResult &result) -{ - const uint blockaddr = result.cookie.toUInt(); - if (const int errorCode = result.errorCode()) { - logMessage(msgMemoryReadError(errorCode, blockaddr)); - return; - } - const QByteArray ba = result.data.mid(1); - m_snapshot.memory.insert(blockaddr , ba); -} - -// Format log message for memory access with some smartness about registers -QByteArray Adapter::memoryReadLogMessage(uint addr, uint len, const QByteArray &ba) const -{ - QByteArray logMsg = "memory contents"; - if (m_verbose > 1) { - logMsg += " addr: 0x"; - logMsg += QByteArray::number(addr, 16); - // indicate dereferencing of registers - if (len == 4) { - if (addr == m_snapshot.registers[RegisterPC]) { - logMsg += "[PC]"; - } else if (addr == m_snapshot.registers[RegisterPSTrk]) { - logMsg += "[PSTrk]"; - } else if (addr == m_snapshot.registers[RegisterSP]) { - logMsg += "[SP]"; - } else if (addr == m_snapshot.registers[RegisterLR]) { - logMsg += "[LR]"; - } else if (addr > m_snapshot.registers[RegisterSP] && - (addr - m_snapshot.registers[RegisterSP]) < 10240) { - logMsg += "[SP+"; // Stack area ...stack seems to be top-down - logMsg += QByteArray::number(addr - m_snapshot.registers[RegisterSP]); - logMsg += ']'; - } - } - logMsg += " length "; - logMsg += QByteArray::number(len); - logMsg += " :"; - logMsg += stringFromArray(ba, 16); - } - return logMsg; -} - -void Adapter::reportReadMemoryBuffered(const TrkResult &result) -{ - const qulonglong cookie = result.cookie.toULongLong(); - const uint addr = cookie >> 32; - const uint len = uint(cookie); - - // Gdb accepts less memory according to documentation. - // Send E on complete failure. - QByteArray ba; - uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; - for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { - const Snapshot::Memory::const_iterator it = m_snapshot.memory.constFind(blockaddr); - if (it == m_snapshot.memory.constEnd()) - break; - ba.append(it.value()); - } - const int previousChunkOverlap = addr % MemoryChunkSize; - if (previousChunkOverlap != 0 && ba.size() > previousChunkOverlap) - ba.remove(0, previousChunkOverlap); - if (ba.size() > int(len)) - ba.truncate(len); - - if (ba.isEmpty()) { - ba = "E20"; - sendGdbMessage(ba, msgMemoryReadError(32, addr, len).toLatin1()); - } else { - sendGdbMessage(ba.toHex(), memoryReadLogMessage(addr, len, ba)); - } -} - -void Adapter::handleReadMemoryUnbuffered(const TrkResult &result) -{ - //logMessage("UNBUFFERED MEMORY READ: " + stringFromArray(result.data)); - const uint blockaddr = result.cookie.toUInt(); - if (extractShort(result.data.data() + 1) + 3 != result.data.size()) { - logMessage("\n BAD MEMORY RESULT: " + result.data.toHex() + "\n"); - } - if (const int errorCode = result.errorCode()) { - const QByteArray ba = "E20"; - sendGdbMessage(ba, msgMemoryReadError(32, blockaddr).toLatin1()); - } else { - const QByteArray ba = result.data.mid(3); - sendGdbMessage(ba.toHex(), memoryReadLogMessage(blockaddr, ba.size(), ba)); - } -} - -void Adapter::handleStepRange(const TrkResult &result) -{ - // [80 0f 12] - //uint bpnr = extractInt(result.data.data()); - logMessage("STEPPING FINISHED " + stringFromArray(result.data.data())); - sendGdbMessage("S05", "Stepping finished"); -} - -void Adapter::handleAndReportSetBreakpoint(const TrkResult &result) -{ - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] - uint bpnr = extractInt(result.data.data()); - logMessage("SET BREAKPOINT " + bpnr + stringFromArray(result.data.data())); - sendGdbMessage("OK"); -} - -void Adapter::clearTrkBreakpoint(const Breakpoint &bp) -{ - //---IDE------------------------------------------------------ - // Command: 0x1C Clear Break - // [1C 25 00 00 00 0A 78 6A 43 40] - QByteArray ba; - appendByte(&ba, 0x00); - appendShort(&ba, bp.number); - appendInt(&ba, m_session.codeseg + bp.offset); - sendTrkMessage(0x1C, CB(handleClearBreakpoint), ba); -} - -void Adapter::handleClearBreakpoint(const TrkResult &result) -{ - Q_UNUSED(result); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00 00 00 00 0A] - logMessage("CLEAR BREAKPOINT "); -} - -void Adapter::handleSignalContinue(const TrkResult &result) -{ - int signalNumber = result.cookie.toInt(); - logMessage(" HANDLE SIGNAL CONTINUE: " + stringFromArray(result.data)); - logMessage("NUMBER" + QString::number(signalNumber)); - sendGdbMessage("O" + QByteArray("Console output").toHex()); - sendGdbMessage("W81"); // "Process exited with result 1 -} - -void Adapter::handleWaitForFinished(const TrkResult &result) -{ - logMessage(" FINISHED: " + stringFromArray(result.data)); - //qApp->exit(1); -} - -void Adapter::handleSupportMask(const TrkResult &result) -{ - const char *data = result.data.data(); - QByteArray str; - for (int i = 0; i < 32; ++i) { - //str.append(" [" + formatByte(data[i]) + "]: "); - for (int j = 0; j < 8; ++j) - if (data[i] & (1 << j)) - str.append(QByteArray::number(i * 8 + j, 16)); - } - logMessage("SUPPORTED: " + str); - } - -void Adapter::handleTrkVersions(const TrkResult &result) -{ - QString logMsg; - QTextStream str(&logMsg); - str << "Versions: "; - if (result.data.size() >= 5) { - str << "Trk version " << int(result.data.at(1)) << '.' - << int(result.data.at(2)) - << ", Protocol version " << int(result.data.at(3)) - << '.' << int(result.data.at(4)); + QTextEdit::keyPressEvent(ev); } - logMessage(logMsg); -} - -void Adapter::handleDisconnect(const TrkResult & /*result*/) -{ - logMessage(QLatin1String("Trk disconnected"), true); -} - -void Adapter::cleanUp() -{ - // - //---IDE------------------------------------------------------ - // Command: 0x41 Delete Item - // Sub Cmd: Delete Process - //ProcessID: 0x0000071F (1823) - // [41 24 00 00 00 00 07 1F] - logMessage(QString::fromLatin1("Cleanup PID=%1").arg(m_session.pid), true); - if (!m_session.pid) - return; - - QByteArray ba; - appendByte(&ba, 0x00); - appendByte(&ba, 0x00); - appendInt(&ba, m_session.pid); - sendTrkMessage(0x41, Callback(), ba, "Delete process"); - - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 24 00] - - foreach (const Breakpoint &bp, m_breakpoints) - clearTrkBreakpoint(bp); - - sendTrkMessage(0x02, CB(handleDisconnect)); - m_startInferiorTriggered = false; - //---IDE------------------------------------------------------ - // Command: 0x1C Clear Break - // [1C 25 00 00 00 0A 78 6A 43 40] - - //---TRK------------------------------------------------------ - // Command: 0xA1 Notify Deleted - // [A1 09 00 00 00 00 00 00 00 00 07 1F] - //---IDE------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 09 00] - - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 25 00] - - //---IDE------------------------------------------------------ - // Command: 0x1C Clear Break - // [1C 26 00 00 00 0B 78 6A 43 70] - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 - // [80 26 00] - - - //---IDE------------------------------------------------------ - // Command: 0x02 Disconnect - // [02 27] -// sendTrkMessage(0x02, CB(handleDisconnect)); - //---TRK------------------------------------------------------ - // Command: 0x80 Acknowledge - // Error: 0x00 -} - -static inline QByteArray memoryRequestTrkMessage(uint addr, uint len, int pid, int tid) -{ - QByteArray ba; - appendByte(&ba, 0x08); // Options, FIXME: why? - appendShort(&ba, len); - appendInt(&ba, addr); - appendInt(&ba, pid); - appendInt(&ba, tid); - return ba; -} - -void Adapter::readMemory(uint addr, uint len) -{ - Q_ASSERT(len < (2 << 16)); - - // We try to get medium-sized chunks of data from the device - if (m_verbose > 2) - logMessage(QString::fromLatin1("readMemory %1 bytes from 0x%2 blocksize=%3").arg(len).arg(addr, 0, 16).arg(MemoryChunkSize)); - - if (m_bufferedMemoryRead) { - uint blockaddr = (addr / MemoryChunkSize) * MemoryChunkSize; - for (; blockaddr < addr + len; blockaddr += MemoryChunkSize) { - if (!m_snapshot.memory.contains(blockaddr)) { - if (m_verbose) - logMessage(QString::fromLatin1("Requesting buffered memory %1 bytes from 0x%2").arg(MemoryChunkSize).arg(blockaddr, 0, 16)); - sendTrkMessage(0x10, CB(handleReadMemoryBuffered), - memoryRequestTrkMessage(blockaddr, MemoryChunkSize, m_session.pid, m_session.tid), - QVariant(blockaddr), true); - } - } - const qulonglong cookie = (qulonglong(addr) << 32) + len; - sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, CB(reportReadMemoryBuffered), QByteArray(), cookie); - } else { - if (m_verbose) - logMessage(QString::fromLatin1("Requesting unbuffered memory %1 bytes from 0x%2").arg(len).arg(addr, 0, 16)); - sendTrkMessage(0x10, CB(handleReadMemoryUnbuffered), - memoryRequestTrkMessage(addr, len, m_session.pid, m_session.tid), - QVariant(addr), true); - } -} - -void Adapter::startInferiorIfNeeded() -{ - if (m_startInferiorTriggered) - return; - if (m_session.pid != 0) { - logMessage("Process already 'started'"); - return; - } - // It's not started yet - m_startInferiorTriggered = true; - QByteArray ba; - appendByte(&ba, 0); // ? - appendByte(&ba, 0); // ? - appendByte(&ba, 0); // ? - - QByteArray file("C:\\sys\\bin\\filebrowseapp.exe"); - appendString(&ba, file, TargetByteOrder); - sendTrkMessage(0x40, CB(handleCreateProcess), ba); // Create Item -} - -void Adapter::interruptInferior() -{ - QByteArray ba; - // stop the thread (2) or the process (1) or the whole system (0) - appendByte(&ba, 1); - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); // threadID: 4 bytes Variable number of bytes. - sendTrkMessage(0x1A, Callback(), ba, "Interrupting..."); -} - -void Adapter::connectProcess(QProcess *proc) -{ - connect(proc, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(handleProcError(QProcess::ProcessError))); - connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(handleProcFinished(int, QProcess::ExitStatus))); - connect(proc, SIGNAL(readyReadStandardError()), - this, SLOT(handleProcReadyReadStandardError())); - connect(proc, SIGNAL(readyReadStandardOutput()), - this, SLOT(handleProcReadyReadStandardOutput())); - connect(proc, SIGNAL(started()), - this, SLOT(handleProcStarted())); - connect(proc, SIGNAL(stateChanged(QProcess::ProcessState)), - this, SLOT(handleProcStateChanged(QProcess::ProcessState))); -} - -void Adapter::sendOutput(QObject *sender, const QString &data) -{ - if (sender) - emit output(sender->objectName() + " : ", data); - else - emit output(QString(), data); -} - -void Adapter::handleProcError(QProcess::ProcessError error) -{ - sendOutput(sender(), QString("Process Error %1").arg(error)); -} - -void Adapter::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - sendOutput(sender(), - QString("ProcessFinished %1 %2").arg(exitCode).arg(exitStatus)); -} - -void Adapter::handleProcReadyReadStandardError() -{ - QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardError(); - sendOutput(sender(), QString("stderr: %1").arg(QString::fromLatin1(ba))); -} - -void Adapter::handleProcReadyReadStandardOutput() -{ - QByteArray ba = qobject_cast<QProcess *>(sender())->readAllStandardOutput(); - sendOutput(sender(), QString("stdout: %1").arg(QString::fromLatin1(ba))); -} - -void Adapter::handleProcStarted() -{ - sendOutput(sender(), QString("Process Started")); -} - -void Adapter::handleProcStateChanged(QProcess::ProcessState newState) -{ - sendOutput(sender(), QString("Process State %1").arg(newState)); -} - -void Adapter::run() -{ - startServer(); - sendOutput("### Starting Adapter"); - - m_rfcommProc.start("rfcomm listen /dev/rfcomm0 1"); - - uid_t userId = getuid(); - if (m_trkServerName.isEmpty()) - m_trkServerName = QString("TRKSERVER-%1").arg(userId); -} - -void Adapter::startGdb() -{ - logMessage("STARTING GDB"); - QStringList gdbArgs; - gdbArgs.append("--nx"); // Do not read .gdbinit file - gdbArgs.append("-i"); - gdbArgs.append("mi"); - m_gdbProc.start(QDir::currentPath() + "/cs-gdb", gdbArgs); - m_gdbProc.waitForStarted(); - - //writeToGdb("set remote noack-packet on"); - writeToGdb("set confirm off"); - writeToGdb("set endian " + m_endianness); - //writeToGdb("set debug remote 1"); - //writeToGdb("target remote " + m_gdbServerName); - writeToGdb("target extended-remote " + m_gdbServerName); - //writeToGdb("file filebrowseapp.sym"); -// writeToGdb("add-symbol-file filebrowseapp.sym " + m_baseAddress); -// writeToGdb("symbol-file filebrowseapp.sym"); -// writeToGdb("print E32Main"); -// writeToGdb("break E32Main"); - //writeToGdb("continue"); - //writeToGdb("info files"); - //writeToGdb("file filebrowseapp.sym -readnow"); -} - -void Adapter::writeToGdb(const QString &msg) -{ - logMessage("<- GDB: " + msg); - m_gdbProc.write(msg.toLatin1() + "\n"); -} +}; /////////////////////////////////////////////////////////////////////// // @@ -1611,55 +165,65 @@ void Adapter::writeToGdb(const QString &msg) // /////////////////////////////////////////////////////////////////////// -class RunnerGui : public QTextEdit +using namespace Debugger::Internal; + +class RunnerGui : public QMainWindow { Q_OBJECT public: - RunnerGui(Adapter *adapter); - void keyPressEvent(QKeyEvent *ev); + RunnerGui(SymbianAdapter *adapter); private slots: - void handleOutput(const QString &senderName, const QString &data); + void executeStepICommand() { executeCommand("-exec-step-instruction"); } + void executeStepCommand() { executeCommand("-exec-step"); } + void executeNextICommand() { executeCommand("-exec-next-instruction"); } + void executeNextCommand() { executeCommand("-exec-next"); } + void executeContinueCommand() { executeCommand("-exec-continue"); } + void executeDisassICommand() { executeCommand("disass $pc $pc+4"); } private: - Adapter *m_adapter; + void executeCommand(const QString &cmd) { m_adapter->executeCommand(cmd); } + void connectAction(QAction *&, QString name, const char *slot); + + SymbianAdapter *m_adapter; + TextEdit m_textEdit; + QToolBar m_toolBar; + QAction *m_stepIAction; + QAction *m_stepAction; + QAction *m_nextIAction; + QAction *m_nextAction; + QAction *m_disassIAction; + QAction *m_continueAction; }; -RunnerGui::RunnerGui(Adapter *adapter) - : m_adapter(adapter) +RunnerGui::RunnerGui(SymbianAdapter *adapter) + : m_adapter(adapter) { resize(1200, 1000); - connect(adapter, SIGNAL(output(QString,QString)), - this, SLOT(handleOutput(QString,QString))); -} + setCentralWidget(&m_textEdit); -void RunnerGui::handleOutput(const QString &senderName, const QString &data) -{ - append(senderName + data); - QTextCursor tc = textCursor(); - tc.movePosition(QTextCursor::End); - setTextCursor(tc); - if (senderName.startsWith("GDB PROCESS")) { - QString str = data; - int pos = str.indexOf("~\""); - if (pos != -1) - str = str.mid(pos + 2); - str.replace("\\t", QString(QChar(0x09))); - str.replace("\\n", QString("\n")); - insertHtml("<b>" + str + "</b>"); - setCurrentCharFormat(QTextCharFormat()); - } - ensureCursorVisible(); + addToolBar(&m_toolBar); + connectAction(m_stepIAction, "Step Inst", SLOT(executeStepICommand())); + connectAction(m_stepAction, "Step", SLOT(executeStepCommand())); + connectAction(m_nextIAction, "Next Inst", SLOT(executeNextICommand())); + connectAction(m_nextAction, "Next", SLOT(executeNextCommand())); + connectAction(m_disassIAction, "Disass Inst", SLOT(executeDisassICommand())); + connectAction(m_continueAction, "Continue", SLOT(executeContinueCommand())); + + connect(adapter, SIGNAL(output(QString,QString)), + &m_textEdit, SLOT(handleOutput(QString,QString))); + connect(&m_textEdit, SIGNAL(executeCommand(QString)), + m_adapter, SLOT(executeCommand(QString))); } -void RunnerGui::keyPressEvent(QKeyEvent *ev) +void RunnerGui::connectAction(QAction *&action, QString name, const char *slot) { - if (ev->modifiers() == Qt::ControlModifier && ev->key() == Qt::Key_Return) - m_adapter->executeGdbCommand(textCursor().block().text()); - else - QTextEdit::keyPressEvent(ev); + action = new QAction(this); + action->setText(name); + m_toolBar.addAction(action); + connect(action, SIGNAL(triggered()), this, slot); } /////////////////////////////////////////////////////////////////////// @@ -1671,7 +235,7 @@ void RunnerGui::keyPressEvent(QKeyEvent *ev) int main(int argc, char *argv[]) { QApplication app(argc, argv); - Adapter adapter; + SymbianAdapter adapter; RunnerGui gui(&adapter); gui.show(); QTimer::singleShot(0, &adapter, SLOT(run())); diff --git a/tests/manual/trk/runner.pro b/tests/manual/trk/runner.pro index 4ced7ccd71abbd0302dc062e6acca3867e284054..21461da2d94b33ce1a3df8759d3894afa3fa154d 100644 --- a/tests/manual/trk/runner.pro +++ b/tests/manual/trk/runner.pro @@ -1,15 +1,21 @@ TEMPLATE = app +DEBUGGERHOME = ../../../src/plugins/debugger/symbian +INCLUDEPATH *= $$DEBUGGERHOME + QT += network win32:CONFIG+=console HEADERS += \ - trkutils.h \ - trkdevicex.h \ + $$DEBUGGERHOME/../gdb/gdbprocessbase.h \ + $$DEBUGGERHOME/trkutils.h \ + $$DEBUGGERHOME/trkclient.h \ + $$DEBUGGERHOME/symbianadapter.h \ SOURCES += \ - runner.cpp \ - trkutils.cpp \ - trkdevicex.cpp \ + $$DEBUGGERHOME/trkutils.cpp \ + $$DEBUGGERHOME/trkclient.cpp \ + $$DEBUGGERHOME/symbianadapter.cpp \ + $$PWD/runner.cpp \ diff --git a/tests/manual/trk/trkdevice.h b/tests/manual/trk/trkdevice.h index 7b2a5dbcd38fd2b1286353d5db6ba94126fc4300..7bfdff7411b269816d142972d97fba4d8c441426 100644 --- a/tests/manual/trk/trkdevice.h +++ b/tests/manual/trk/trkdevice.h @@ -111,7 +111,7 @@ public: explicit TrkWriteQueueDevice(QObject *parent = 0); virtual ~TrkWriteQueueDevice(); - // Construct as 'TrkWriteQueueDevice::Callback(instance, &Klass::method);' + // Construct as 'TrkWriteQueueDevice::Callback(instance, &Class::method);' typedef TrkFunctor1<const TrkResult &> Callback; // Enqueue a message with a notification callback. diff --git a/tests/manual/trk/trklauncher.pri b/tests/manual/trk/trklauncher.pri index 3593888b86116b84473a35bf89a1ca0c9466fcce..74b37e42e3cb5179d6b2b90fe7d6f6f8cb092b56 100644 --- a/tests/manual/trk/trklauncher.pri +++ b/tests/manual/trk/trklauncher.pri @@ -1,9 +1,15 @@ DEFINES += DEBUG_TRK=0 -INCLUDEPATH *= $$PWD -SOURCES += $$PWD/launcher.cpp \ - $$PWD/trkutils.cpp \ - $$PWD/trkdevice.cpp -HEADERS += $$PWD/trkutils.h \ - $$PWD/trkfunctor.h \ +DEBUGGERHOME = ../../../src/plugins/debugger/symbian + +INCLUDEPATH *= $$DEBUGGERHOME + +SOURCES += \ + $$DEBUGGERHOME/trkutils.cpp \ + $$PWD/trkdevice.cpp \ + $$PWD/launcher.cpp \ + +HEADERS += \ + $$DEBUGGERHOME/trkutils.h \ + $$DEBUGGERHOME/trkfunctor.h \ $$PWD/trkdevice.h \ $$PWD/launcher.h diff --git a/tests/manual/trk/trkserver.pro b/tests/manual/trk/trkserver.pro index a333dc2c363c49624bd2fc934c56edba0aec518a..6fbbc85c06cddef88064d35dc19b08f98e6e3626 100644 --- a/tests/manual/trk/trkserver.pro +++ b/tests/manual/trk/trkserver.pro @@ -1,12 +1,17 @@ TEMPLATE = app +DEBUGGERHOME = ../../../src/plugins/debugger/symbian + QT = core network win32:CONFIG+=console +INCLUDEPATH *= $$DEBUGGERHOME + + HEADERS += \ - trkutils.h + $$DEBUGGERHOME/trkutils.h SOURCES += \ - trkutils.cpp \ - trkserver.cpp + $$DEBUGGERHOME/trkutils.cpp \ + $$PWD/trkserver.cpp