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 @@
#include "breakhandler.h"
#include "debuggermanager.h"
#include "stackframe.h"
#include "imports.h" // TextEditor::BaseTextMark
#include <QtCore/QDebug>
......@@ -242,8 +245,8 @@ bool BreakpointData::conditionsMatch() const
//
//////////////////////////////////////////////////////////////////
BreakHandler::BreakHandler(QObject *parent)
: QAbstractItemModel(parent)
BreakHandler::BreakHandler(DebuggerManager *manager, QObject *parent)
: QAbstractItemModel(parent), m_manager(manager)
{
}
......@@ -345,13 +348,12 @@ void BreakHandler::saveBreakpoints()
map.insert(QLatin1String("usefullpath"), QLatin1String("1"));
list.append(map);
}
setSessionValueRequested("Breakpoints", list);
m_manager->setSessionValue("Breakpoints", list);
}
void BreakHandler::loadBreakpoints()
{
QVariant value;
sessionValueRequested("Breakpoints", &value);
QVariant value = m_manager->sessionValue("Breakpoints");
QList<QVariant> list = value.toList();
clear();
foreach (const QVariant &var, list) {
......@@ -677,8 +679,12 @@ void BreakHandler::activateBreakpoint(int index)
{
const BreakpointData *data = at(index);
//qDebug() << "BREAKPOINT ACTIVATED: " << data->fileName;
if (!data->markerFileName.isEmpty())
emit gotoLocation(data->markerFileName, data->markerLineNumber, false);
if (!data->markerFileName.isEmpty()) {
StackFrame frame;
frame.file = data->markerFileName;
frame.line = data->markerLineNumber;
m_manager->gotoLocation(frame, false);
}
}
void BreakHandler::breakByFunction(const QString &functionName)
......
......@@ -40,6 +40,7 @@ namespace Internal {
class BreakpointMarker;
class BreakHandler;
class DebuggerManager;
//////////////////////////////////////////////////////////////////
//
......@@ -113,7 +114,7 @@ class BreakHandler : public QAbstractItemModel
Q_OBJECT
public:
explicit BreakHandler(QObject *parent = 0);
explicit BreakHandler(DebuggerManager *manager, QObject *parent = 0);
~BreakHandler();
void removeAllBreakpoints();
......@@ -149,12 +150,6 @@ public slots:
void activateBreakpoint(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:
friend class BreakpointMarker;
......@@ -175,6 +170,7 @@ private:
void resetBreakpoints();
void removeBreakpointHelper(int index);
DebuggerManager *m_manager; // not owned
QList<BreakpointData *> m_bp;
QList<BreakpointData *> m_inserted; // lately inserted breakpoints
QList<BreakpointData *> m_removed; // lately removed breakpoints
......
......@@ -1178,7 +1178,7 @@ void CdbDebugEngine::activateFrame(int frameIndex)
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) {
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()
item->setDefaultValue(false);
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
//
......
......@@ -77,6 +77,7 @@ enum DebuggerActionCode
AutoQuit,
LockView,
LogTimeStamps,
StepByInstruction,
RecheckDebuggingHelpers,
UseDebuggingHelpers,
......
......@@ -30,15 +30,59 @@
#include "debuggeragents.h"
#include "idebuggerengine.h"
#include <coreplugin/coreconstants.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>
namespace Debugger {
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)
: 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();
QString titlePattern = "Memory $";
......@@ -49,12 +93,7 @@ MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
this, SLOT(fetchLazyData(int,bool)));
editorManager->activateEditor(m_editor);
QMetaObject::invokeMethod(m_editor->widget(), "setLazyData",
Q_ARG(int, addr), Q_ARG(int, INT_MAX), Q_ARG(int, BinBlockSize));
}
MemoryViewAgent::~MemoryViewAgent()
{
m_editor->deleteLater();
Q_ARG(int, addr), Q_ARG(int, INT_MAX), Q_ARG(int, BinBlockSize));
}
void MemoryViewAgent::fetchLazyData(int block, bool sync)
......@@ -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 Debugger
#include "debuggeragents.moc"
......@@ -31,26 +31,21 @@
#define DEBUGGER_AGENTS_H
#include "debuggermanager.h"
#include "stackframe.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/qtcassert.h>
#include <QtCore/QObject>
#include <QtCore/QDebug>
#include <QtCore/QPointer>
#include <QtGui/QAction>
namespace Debugger {
namespace Internal {
class DebuggerManager;
// 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 DisassemblerViewAgentPrivate;
class MemoryViewAgent : public QObject
{
......@@ -59,6 +54,7 @@ class MemoryViewAgent : public QObject
public:
// Called from Gui
MemoryViewAgent(DebuggerManager *manager, quint64 startaddr);
MemoryViewAgent(DebuggerManager *manager, const QString &startaddr);
~MemoryViewAgent();
enum { BinBlockSize = 1024 };
......@@ -69,11 +65,32 @@ public slots:
// Called from Editor
void fetchLazyData(int block, bool sync);
public:
private:
void init(quint64 startaddr);
QPointer<IDebuggerEngine> m_engine;
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 Debugger
......
......@@ -45,8 +45,6 @@ const char * const RESET = "Debugger.Reset";
const char * const STEP = "Debugger.StepLine";
const char * const STEPOUT = "Debugger.StepOut";
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 M_DEBUG_VIEWS = "Debugger.Menu.View.Debug";
......
......@@ -219,8 +219,8 @@ void DebuggerManager::init()
m_disassemblerWindow = new DisassemblerWindow;
m_modulesWindow = new ModulesWindow(this);
m_outputWindow = new DebuggerOutputWindow;
m_registerWindow = new RegisterWindow;
m_stackWindow = new StackWindow;
m_registerWindow = new RegisterWindow(this);
m_stackWindow = new StackWindow(this);
m_sourceFilesWindow = new SourceFilesWindow;
m_threadsWindow = new ThreadsWindow;
m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this);
......@@ -261,7 +261,7 @@ void DebuggerManager::init()
this, SLOT(reloadDisassembler()));
// Breakpoints
m_breakHandler = new BreakHandler;
m_breakHandler = new BreakHandler(this);
QAbstractItemView *breakView =
qobject_cast<QAbstractItemView *>(m_breakWindow);
breakView->setModel(m_breakHandler->model());
......@@ -271,12 +271,6 @@ void DebuggerManager::init()
m_breakHandler, SLOT(removeBreakpoint(int)));
connect(breakView, SIGNAL(breakpointSynchronizationRequested()),
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)),
this, SLOT(breakByFunction(QString)), Qt::QueuedConnection);
connect(breakView, SIGNAL(breakByFunctionMainRequested()),
......@@ -357,16 +351,6 @@ void DebuggerManager::init()
//m_stepAction->setShortcut(QKeySequence(tr("F7")));
m_stepAction->setIcon(QIcon(":/debugger/images/debugger_stepinto_small.png"));
m_nextIAction = new QAction(this);
m_nextIAction->setText(tr("Step Over Instruction"));
//m_nextIAction->setShortcut(QKeySequence(tr("Shift+F6")));
m_nextIAction->setIcon(QIcon(":/debugger/images/debugger_stepoverproc_small.png"));
m_stepIAction = new QAction(this);
m_stepIAction->setText(tr("Step One Instruction"));
//m_stepIAction->setShortcut(QKeySequence(tr("Shift+F9")));
m_stepIAction->setIcon(QIcon(":/debugger/images/debugger_steponeproc_small.png"));
m_stepOutAction = new QAction(this);
m_stepOutAction->setText(tr("Step Out"));
//m_stepOutAction->setShortcut(QKeySequence(tr("Shift+F7")));
......@@ -405,10 +389,8 @@ void DebuggerManager::init()
this, SLOT(nextExec()));
connect(m_stepAction, SIGNAL(triggered()),
this, SLOT(stepExec()));
connect(m_nextIAction, SIGNAL(triggered()),
this, SLOT(nextIExec()));
connect(m_stepIAction, SIGNAL(triggered()),
this, SLOT(stepIExec()));
connect(theDebuggerAction(StepByInstruction), SIGNAL(triggered()),
this, SLOT(stepByInstructionTriggered()));
connect(m_stepOutAction, SIGNAL(triggered()),
this, SLOT(stepOutExec()));
connect(m_runToLineAction, SIGNAL(triggered()),
......@@ -427,9 +409,14 @@ void DebuggerManager::init()
connect(theDebuggerAction(ExecuteCommand), SIGNAL(triggered()),
this, SLOT(executeDebuggerCommand()));
connect(theDebuggerAction(WatchPoint), SIGNAL(triggered()),
this, SLOT(watchPoint()));
connect(theDebuggerAction(StepByInstruction), SIGNAL(triggered()),
this, SLOT(stepByInstructionTriggered()));
m_breakDock = m_mainWindow->addDockForWidget(m_breakWindow);
m_disassemblerDock = m_mainWindow->addDockForWidget(m_disassemblerWindow);
......@@ -725,14 +712,6 @@ void DebuggerManager::updateWatchData(const WatchData &data)
m_engine->updateWatchData(data);
}
QVariant DebuggerManager::sessionValue(const QString &name)
{
// this is answered by the plugin
QVariant value;
emit sessionValueRequested(name, &value);
return value;
}
static inline QString msgEngineNotAvailable(const char *engine)
{
return DebuggerManager::tr("The application requires the debugger engine '%1', which is disabled.").arg(QLatin1String(engine));
......@@ -986,7 +965,10 @@ void DebuggerManager::stepExec()
{
QTC_ASSERT(m_engine, return);
resetLocation();
m_engine->stepExec();
if (theDebuggerBoolSetting(StepByInstruction))
m_engine->stepIExec();
else
m_engine->stepExec();
}
void DebuggerManager::stepOutExec()
......@@ -1000,21 +982,10 @@ void DebuggerManager::nextExec()
{
QTC_ASSERT(m_engine, return);
resetLocation();
m_engine->nextExec();
}
void DebuggerManager::stepIExec()
{
QTC_ASSERT(m_engine, return);
resetLocation();
m_engine->stepIExec();
}
void DebuggerManager::nextIExec()
{
QTC_ASSERT(m_engine, return);
resetLocation();
m_engine->nextIExec();
if (theDebuggerBoolSetting(StepByInstruction))
m_engine->nextIExec();
else
m_engine->nextExec();
}
void DebuggerManager::watchPoint()
......@@ -1190,8 +1161,6 @@ void DebuggerManager::setStatus(int status)
m_runToFunctionAction->setEnabled(ready);
m_jumpToLineAction->setEnabled(ready);
m_nextAction->setEnabled(ready);
m_stepIAction->setEnabled(ready);
m_nextIAction->setEnabled(ready);
//showStatusMessage(QString("started: %1, running: %2").arg(started).arg(running));
emit statusChanged(m_status);
const bool notbusy = ready || status == DebuggerProcessNotReady;
......@@ -1316,17 +1285,26 @@ void DebuggerManager::resetLocation()
emit resetLocationRequested();
}
void DebuggerManager::gotoLocation(const QString &fileName, int line,
bool setMarker)
void DebuggerManager::gotoLocation(const StackFrame &frame, bool setMarker)
{
// connected to the plugin
emit gotoLocationRequested(fileName, line, setMarker);
emit gotoLocationRequested(frame, setMarker);
}
void DebuggerManager::fileOpen(const QString &fileName)
{
// connected to the plugin
emit gotoLocationRequested(