Commit e82d6c7b authored by hjk's avatar hjk

debugger: create a disassembler view as main editor

"Stepping instruction wise" and "display disassembler" mode is now toggled by a
single action. This also allows to re-use F10 and F11 as keyboard shortcut.

Missing: caching of disassembler output, removal of old disassembler view.
parent 74602f31
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#include "breakhandler.h" #include "breakhandler.h"
#include "debuggermanager.h"
#include "stackframe.h"
#include "imports.h" // TextEditor::BaseTextMark #include "imports.h" // TextEditor::BaseTextMark
#include <QtCore/QDebug> #include <QtCore/QDebug>
...@@ -242,8 +245,8 @@ bool BreakpointData::conditionsMatch() const ...@@ -242,8 +245,8 @@ bool BreakpointData::conditionsMatch() const
// //
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
BreakHandler::BreakHandler(QObject *parent) BreakHandler::BreakHandler(DebuggerManager *manager, QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent), m_manager(manager)
{ {
} }
...@@ -345,13 +348,12 @@ void BreakHandler::saveBreakpoints() ...@@ -345,13 +348,12 @@ void BreakHandler::saveBreakpoints()
map.insert(QLatin1String("usefullpath"), QLatin1String("1")); map.insert(QLatin1String("usefullpath"), QLatin1String("1"));
list.append(map); list.append(map);
} }
setSessionValueRequested("Breakpoints", list); m_manager->setSessionValue("Breakpoints", list);
} }
void BreakHandler::loadBreakpoints() void BreakHandler::loadBreakpoints()
{ {
QVariant value; QVariant value = m_manager->sessionValue("Breakpoints");
sessionValueRequested("Breakpoints", &value);
QList<QVariant> list = value.toList(); QList<QVariant> list = value.toList();
clear(); clear();
foreach (const QVariant &var, list) { foreach (const QVariant &var, list) {
...@@ -677,8 +679,12 @@ void BreakHandler::activateBreakpoint(int index) ...@@ -677,8 +679,12 @@ void BreakHandler::activateBreakpoint(int index)
{ {
const BreakpointData *data = at(index); const BreakpointData *data = at(index);
//qDebug() << "BREAKPOINT ACTIVATED: " << data->fileName; //qDebug() << "BREAKPOINT ACTIVATED: " << data->fileName;
if (!data->markerFileName.isEmpty()) if (!data->markerFileName.isEmpty()) {
emit gotoLocation(data->markerFileName, data->markerLineNumber, false); StackFrame frame;
frame.file = data->markerFileName;
frame.line = data->markerLineNumber;
m_manager->gotoLocation(frame, false);
}
} }
void BreakHandler::breakByFunction(const QString &functionName) void BreakHandler::breakByFunction(const QString &functionName)
......
...@@ -40,6 +40,7 @@ namespace Internal { ...@@ -40,6 +40,7 @@ namespace Internal {
class BreakpointMarker; class BreakpointMarker;
class BreakHandler; class BreakHandler;
class DebuggerManager;
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// //
...@@ -113,7 +114,7 @@ class BreakHandler : public QAbstractItemModel ...@@ -113,7 +114,7 @@ class BreakHandler : public QAbstractItemModel
Q_OBJECT Q_OBJECT
public: public:
explicit BreakHandler(QObject *parent = 0); explicit BreakHandler(DebuggerManager *manager, QObject *parent = 0);
~BreakHandler(); ~BreakHandler();
void removeAllBreakpoints(); void removeAllBreakpoints();
...@@ -149,12 +150,6 @@ public slots: ...@@ -149,12 +150,6 @@ public slots:
void activateBreakpoint(int index); void activateBreakpoint(int index);
void removeBreakpoint(int index); void removeBreakpoint(int index);
signals:
void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
void sessionValueRequested(const QString &name, QVariant *value);
void setSessionValueRequested(const QString &name, const QVariant &value);
private: private:
friend class BreakpointMarker; friend class BreakpointMarker;
...@@ -175,6 +170,7 @@ private: ...@@ -175,6 +170,7 @@ private:
void resetBreakpoints(); void resetBreakpoints();
void removeBreakpointHelper(int index); void removeBreakpointHelper(int index);
DebuggerManager *m_manager; // not owned
QList<BreakpointData *> m_bp; QList<BreakpointData *> m_bp;
QList<BreakpointData *> m_inserted; // lately inserted breakpoints QList<BreakpointData *> m_inserted; // lately inserted breakpoints
QList<BreakpointData *> m_removed; // lately removed breakpoints QList<BreakpointData *> m_removed; // lately removed breakpoints
......
...@@ -1178,7 +1178,7 @@ void CdbDebugEngine::activateFrame(int frameIndex) ...@@ -1178,7 +1178,7 @@ void CdbDebugEngine::activateFrame(int frameIndex)
break; break;
} }
m_d->m_debuggerManager->gotoLocation(frame.file, frame.line, true); m_d->m_debuggerManager->gotoLocation(frame, true);
if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) { if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) {
watchHandler->beginCycle(); watchHandler->beginCycle();
......
/**************************************************************************
**
** 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 "cpptools.h"
namespace Debugger {
namespace Internal {
QByteArray mangleName(const QByteArray &ba)
{
return ba;
}
QByteArray demangleName(const QByteArray &ba)
{
return ba;
}
} // namespace Internal
} // namespace Debugger
/**************************************************************************
**
** 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_CPPTOOLS_H
#define DEBUGGER_CPPTOOLS_H
#include <QtCore/QByteArray>
namespace Debugger {
namespace Internal {
QByteArray mangleName(const QByteArray &ba);
QByteArray demangleName(const QByteArray &ba);
} // namespace Internal
} // namespace Debugger
#endif // DEBUGGER_WATCHWINDOW_H
...@@ -151,6 +151,13 @@ DebuggerSettings *DebuggerSettings::instance() ...@@ -151,6 +151,13 @@ DebuggerSettings *DebuggerSettings::instance()
item->setDefaultValue(false); item->setDefaultValue(false);
instance->insertItem(LogTimeStamps, item); instance->insertItem(LogTimeStamps, item);
item = new SavedAction(instance);
item->setText(tr("Step by instruction"));
item->setCheckable(true);
item->setDefaultValue(false);
item->setIcon(QIcon(":/debugger/images/debugger_stepoverproc_small.png"));
instance->insertItem(StepByInstruction, item);
// //
// Locals & Watchers // Locals & Watchers
// //
......
...@@ -77,6 +77,7 @@ enum DebuggerActionCode ...@@ -77,6 +77,7 @@ enum DebuggerActionCode
AutoQuit, AutoQuit,
LockView, LockView,
LogTimeStamps, LogTimeStamps,
StepByInstruction,
RecheckDebuggingHelpers, RecheckDebuggingHelpers,
UseDebuggingHelpers, UseDebuggingHelpers,
......
...@@ -30,15 +30,59 @@ ...@@ -30,15 +30,59 @@
#include "debuggeragents.h" #include "debuggeragents.h"
#include "idebuggerengine.h" #include "idebuggerengine.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icore.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>
#include <utils/qtcassert.h>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QTextCursor>
#include <limits.h> #include <limits.h>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
///////////////////////////////////////////////////////////////////////
//
// MemoryViewAgent
//
///////////////////////////////////////////////////////////////////////
/*!
\class MemoryViewAgent
Objects form this class are created in response to user actions in
the Gui for showing raw memory from the inferior. After creation
it handles communication between the engine and the bineditor.
*/
MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr) MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
: QObject(manager), m_engine(manager->currentEngine()) : QObject(manager), m_engine(manager->currentEngine())
{
init(addr);
}
MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr)
: QObject(manager), m_engine(manager->currentEngine())
{
bool ok = true;
init(addr.toUInt(&ok, 0));
}
MemoryViewAgent::~MemoryViewAgent()
{
m_editor->deleteLater();
}
void MemoryViewAgent::init(quint64 addr)
{ {
Core::EditorManager *editorManager = Core::EditorManager::instance(); Core::EditorManager *editorManager = Core::EditorManager::instance();
QString titlePattern = "Memory $"; QString titlePattern = "Memory $";
...@@ -49,12 +93,7 @@ MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr) ...@@ -49,12 +93,7 @@ MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
this, SLOT(fetchLazyData(int,bool))); this, SLOT(fetchLazyData(int,bool)));
editorManager->activateEditor(m_editor); editorManager->activateEditor(m_editor);
QMetaObject::invokeMethod(m_editor->widget(), "setLazyData", QMetaObject::invokeMethod(m_editor->widget(), "setLazyData",
Q_ARG(int, addr), Q_ARG(int, INT_MAX), Q_ARG(int, BinBlockSize)); Q_ARG(int, addr), Q_ARG(int, INT_MAX), Q_ARG(int, BinBlockSize));
}
MemoryViewAgent::~MemoryViewAgent()
{
m_editor->deleteLater();
} }
void MemoryViewAgent::fetchLazyData(int block, bool sync) void MemoryViewAgent::fetchLazyData(int block, bool sync)
...@@ -70,6 +109,113 @@ void MemoryViewAgent::addLazyData(quint64 addr, const QByteArray &ba) ...@@ -70,6 +109,113 @@ void MemoryViewAgent::addLazyData(quint64 addr, const QByteArray &ba)
} }
///////////////////////////////////////////////////////////////////////
//
// DisassemblerViewAgent
//
///////////////////////////////////////////////////////////////////////
static QIcon locationMarkIcon()
{
static const QIcon icon(":/debugger/images/location.svg");
return icon;
}
// Used for the disassembler view
class LocationMark2 : public TextEditor::ITextMark
{
public:
LocationMark2() {}
QIcon icon() const { return locationMarkIcon(); }
void updateLineNumber(int /*lineNumber*/) {}
void updateBlock(const QTextBlock & /*block*/) {}
void removedFromEditor() {}
void documentClosing() {}
};
struct DisassemblerViewAgentPrivate
{
QPointer<TextEditor::ITextEditor> editor;
QPointer<IDebuggerEngine> engine;
QString address;
LocationMark2 *locationMark;
};
/*!
\class DisassemblerViewAgent
Objects from this class are created in response to user actions in
the Gui for showing disassembled memory from the inferior. After creation
it handles communication between the engine and the editor.
*/
DisassemblerViewAgent::DisassemblerViewAgent(DebuggerManager *manager)
: QObject(manager), d(new DisassemblerViewAgentPrivate)
{
d->editor = 0;
d->engine = manager->currentEngine();
d->locationMark = new LocationMark2();
}
DisassemblerViewAgent::~DisassemblerViewAgent()
{
if (d->editor)
d->editor->deleteLater();
delete d;
}
void DisassemblerViewAgent::setFrame(const StackFrame &frame)
{
d->engine->fetchDisassembler(this, frame);
d->address = frame.address;
}
void DisassemblerViewAgent::setContents(const QString &contents)
{
using namespace Core;
using namespace TextEditor;
EditorManager *editorManager = EditorManager::instance();
if (!d->editor) {
QString titlePattern = "Disassembler";
d->editor = qobject_cast<ITextEditor *>(
editorManager->openEditorWithContents(
Core::Constants::K_DEFAULT_TEXT_EDITOR,
&titlePattern));
}
editorManager->activateEditor(d->editor);
QPlainTextEdit *plainTextEdit =
qobject_cast<QPlainTextEdit *>(d->editor->widget());
if (plainTextEdit)
plainTextEdit->setPlainText(contents);
d->editor->markableInterface()->removeMark(d->locationMark);
for (int pos = 0, line = 0; ; ++line, ++pos) {
if (contents.midRef(pos, d->address.size()) == d->address) {
d->editor->markableInterface()->addMark(d->locationMark, line + 1);
if (plainTextEdit) {
QTextCursor tc = plainTextEdit->textCursor();
tc.setPosition(pos);
plainTextEdit->setTextCursor(tc);
}
break;
}
pos = contents.indexOf('\n', pos + 1);
if (pos == -1)
break;
}
}
QString DisassemblerViewAgent::address() const
{
return d->address;
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger
#include "debuggeragents.moc"
...@@ -31,26 +31,21 @@ ...@@ -31,26 +31,21 @@
#define DEBUGGER_AGENTS_H #define DEBUGGER_AGENTS_H
#include "debuggermanager.h" #include "debuggermanager.h"
#include "stackframe.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
#include <utils/qtcassert.h>
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QPointer> #include <QtCore/QPointer>
#include <QtGui/QAction> #include <QtGui/QAction>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class DebuggerManager; class DebuggerManager;
class DisassemblerViewAgentPrivate;
// Object form this class are created in response to user actions in
// the Gui for showing raw memory from the inferior. After creation
// it handles communication between the engine and the bineditor.
class MemoryViewAgent : public QObject class MemoryViewAgent : public QObject
{ {
...@@ -59,6 +54,7 @@ class MemoryViewAgent : public QObject ...@@ -59,6 +54,7 @@ class MemoryViewAgent : public QObject
public: public:
// Called from Gui // Called from Gui
MemoryViewAgent(DebuggerManager *manager, quint64 startaddr); MemoryViewAgent(DebuggerManager *manager, quint64 startaddr);
MemoryViewAgent(DebuggerManager *manager, const QString &startaddr);
~MemoryViewAgent(); ~MemoryViewAgent();
enum { BinBlockSize = 1024 }; enum { BinBlockSize = 1024 };
...@@ -69,11 +65,32 @@ public slots: ...@@ -69,11 +65,32 @@ public slots:
// Called from Editor // Called from Editor
void fetchLazyData(int block, bool sync); void fetchLazyData(int block, bool sync);
public: private:
void init(quint64 startaddr);
QPointer<IDebuggerEngine> m_engine; QPointer<IDebuggerEngine> m_engine;
QPointer<Core::IEditor> m_editor; QPointer<Core::IEditor> m_editor;
}; };
class DisassemblerViewAgent : public QObject
{
Q_OBJECT
public:
// Called from Gui
DisassemblerViewAgent(DebuggerManager *manager);
~DisassemblerViewAgent();
void setFrame(const StackFrame &frame);
Q_SLOT void setContents(const QString &contents);
QString address() const;
private:
DisassemblerViewAgentPrivate *d;
};
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger
......
...@@ -45,8 +45,6 @@ const char * const RESET = "Debugger.Reset"; ...@@ -45,8 +45,6 @@ const char * const RESET = "Debugger.Reset";
const char * const STEP = "Debugger.StepLine"; const char * const STEP = "Debugger.StepLine";
const char * const STEPOUT = "Debugger.StepOut"; const char * const STEPOUT = "Debugger.StepOut";
const char * const NEXT = "Debugger.NextLine"; const char * const NEXT = "Debugger.NextLine";
const char * const STEPI = "Debugger.StepInstruction";
const char * const NEXTI = "Debugger.NextInstruction";
const char * const REVERSE = "Debugger.ReverseDirection"; const char * const REVERSE = "Debugger.ReverseDirection";
const char * const M_DEBUG_VIEWS = "Debugger.Menu.View.Debug"; const char * const M_DEBUG_VIEWS = "Debugger.Menu.View.Debug";
......
...@@ -219,8 +219,8 @@ void DebuggerManager::init() ...@@ -219,8 +219,8 @@ void DebuggerManager::init()
m_disassemblerWindow = new DisassemblerWindow; m_disassemblerWindow = new DisassemblerWindow;
m_modulesWindow = new ModulesWindow(this); m_modulesWindow = new ModulesWindow(this);
m_outputWindow = new DebuggerOutputWindow; m_outputWindow = new DebuggerOutputWindow;
m_registerWindow = new RegisterWindow; m_registerWindow = new RegisterWindow(this);
m_stackWindow = new StackWindow; m_stackWindow = new StackWindow(this);
m_sourceFilesWindow = new SourceFilesWindow; m_sourceFilesWindow = new SourceFilesWindow;
m_threadsWindow = new ThreadsWindow; m_threadsWindow = new ThreadsWindow;
m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this); m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this);
...@@ -261,7 +261,7 @@ void DebuggerManager::init() ...@@ -261,7 +261,7 @@ void DebuggerManager::init()
this, SLOT(reloadDisassembler())); this, SLOT(reloadDisassembler()));
// Breakpoints // Breakpoints
m_breakHandler = new BreakHandler; m_breakHandler = new BreakHandler(this);
QAbstractItemView *breakView = QAbstractItemView *breakView =
qobject_cast<QAbstractItemView *>(m_breakWindow); qobject_cast<QAbstractItemView *>(m_breakWindow);
breakView->setModel(m_breakHandler->model()); breakView->setModel(m_breakHandler->model());
...@@ -271,12 +271,6 @@ void DebuggerManager::init() ...@@ -271,12 +271,6 @@ void DebuggerManager::init()
m_breakHandler, SLOT(removeBreakpoint(int))); m_breakHandler, SLOT(removeBreakpoint(int)));
connect(breakView, SIGNAL(breakpointSynchronizationRequested()), connect(breakView, SIGNAL(breakpointSynchronizationRequested()),
this, SLOT(attemptBreakpointSynchronization())); this, SLOT(attemptBreakpointSynchronization()));
connect(m_breakHandler, SIGNAL(gotoLocation(QString,int,bool)),
this, SLOT(gotoLocation(QString,int,bool)));
connect(m_breakHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
this, SIGNAL(sessionValueRequested(QString,QVariant*)));
connect(m_breakHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
this, SIGNAL(setSessionValueRequested(QString,QVariant)));
connect(breakView, SIGNAL(breakByFunctionRequested(QString)), connect(breakView, SIGNAL(breakByFunctionRequested(QString)),
this, SLOT(breakByFun