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.
This commit is contained in:
hjk
2009-08-14 13:04:05 +02:00
parent 74602f3119
commit e82d6c7b05
28 changed files with 757 additions and 209 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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();

View File

@@ -0,0 +1,47 @@
/**************************************************************************
**
** 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

View File

@@ -0,0 +1,44 @@
/**************************************************************************
**
** 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

View File

@@ -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
//

View File

@@ -77,6 +77,7 @@ enum DebuggerActionCode
AutoQuit,
LockView,
LogTimeStamps,
StepByInstruction,
RecheckDebuggingHelpers,
UseDebuggingHelpers,

View File

@@ -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"

View File

@@ -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

View File

@@ -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";

View File

@@ -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(fileName, 1, false);
StackFrame frame;
frame.file = fileName;
frame.line = -1;
emit gotoLocationRequested(frame, false);
}
void DebuggerManager::stepByInstructionTriggered()
{
QTC_ASSERT(m_stackHandler, return);
StackFrame frame = m_stackHandler->currentFrame();
gotoLocation(frame, true);
}
@@ -1497,6 +1475,20 @@ bool DebuggerManager::isReverseDebugging() const
return m_reverseDirectionAction->isChecked();
}
QVariant DebuggerManager::sessionValue(const QString &name)
{
// this is answered by the plugin
QVariant value;
emit sessionValueRequested(name, &value);
return value;
}
void DebuggerManager::setSessionValue(const QString &name, const QVariant &value)
{
emit setSessionValueRequested(name, value);
}
//////////////////////////////////////////////////////////////////////
//
// Testing

View File

@@ -77,6 +77,7 @@ class DisassemblerHandler;
class ModulesHandler;
class RegisterHandler;
class SourceFilesWindow;
class StackFrame;
class StackHandler;
class Symbol;
class ThreadsHandler;
@@ -141,8 +142,9 @@ enum LogChannel
LogMisc
};
struct DebuggerStartParameters
class DebuggerStartParameters
{
public:
DebuggerStartParameters();
void clear();
@@ -281,9 +283,8 @@ public slots:
void setBusyCursor(bool on);
void queryCurrentTextEditor(QString *fileName, int *lineNumber, QObject **ed);
QVariant sessionValue(const QString &name);
void gotoLocation(const QString &file, int line, bool setLocationMarker);
void gotoLocation(const StackFrame &frame, bool setLocationMarker);
void fileOpen(const QString &file);
void resetLocation();
@@ -302,8 +303,6 @@ public slots:
void stepExec();
void stepOutExec();
void nextExec();
void stepIExec();
void nextIExec();
void continueExec();
void detachDebugger();
@@ -313,6 +312,8 @@ public slots:
void sessionLoaded();
void aboutToUnloadSession();
void aboutToSaveSession();
QVariant sessionValue(const QString &name);
void setSessionValue(const QString &name, const QVariant &value);
void assignValueInDebugger();
void assignValueInDebugger(const QString &expr, const QString &value);
@@ -346,6 +347,7 @@ private slots:
void clearStatusMessage();
void attemptBreakpointSynchronization();
void reloadFullStack();
void stepByInstructionTriggered();
private:
//
@@ -404,7 +406,7 @@ signals:
void debugModeRequested();
void previousModeRequested();
void statusMessageRequested(const QString &msg, int timeout); // -1 for 'forever'
void gotoLocationRequested(const QString &file, int line, bool setLocationMarker);
void gotoLocationRequested(const StackFrame &frame, bool setLocationMarker);
void resetLocationRequested();
void currentTextEditorRequested(QString *fileName, int *lineNumber, QObject **ob);
void sessionValueRequested(const QString &name, QVariant *value);
@@ -468,8 +470,7 @@ private:
QAction *m_watchAction;
QAction *m_breakAction;
QAction *m_sepAction;
QAction *m_stepIAction;
QAction *m_nextIAction;
//QActio *m_stepByInstructionAction;
QAction *m_reverseDirectionAction;
QWidget *m_breakWindow;

View File

@@ -31,10 +31,12 @@
#include "breakhandler.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerdialogs.h"
#include "debuggerconstants.h"
#include "debuggermanager.h"
#include "debuggerrunner.h"
#include "stackframe.h"
#include "ui_commonoptionspage.h"
#include "ui_dumperoptionpage.h"
@@ -116,6 +118,7 @@ const char * const TOGGLE_BREAK = "Debugger.ToggleBreak";
const char * const BREAK_BY_FUNCTION = "Debugger.BreakByFunction";
const char * const BREAK_AT_MAIN = "Debugger.BreakAtMain";
const char * const ADD_TO_WATCH = "Debugger.AddToWatch";
const char * const STEP_BY_INSTRUCTION = "Debugger.StepByInstruction";
#ifdef Q_WS_MAC
const char * const INTERRUPT_KEY = "Shift+F5";
@@ -123,8 +126,6 @@ const char * const RESET_KEY = "Ctrl+Shift+F5";
const char * const STEP_KEY = "F7";
const char * const STEPOUT_KEY = "Shift+F7";
const char * const NEXT_KEY = "F6";
const char * const STEPI_KEY = "Shift+F9";
const char * const NEXTI_KEY = "Shift+F6";
const char * const REVERSE_KEY = "";
const char * const RUN_TO_LINE_KEY = "Shift+F8";
const char * const RUN_TO_FUNCTION_KEY = "Ctrl+F6";
@@ -139,8 +140,6 @@ const char * const RESET_KEY = "Ctrl+Shift+F5";
const char * const STEP_KEY = "F11";
const char * const STEPOUT_KEY = "Shift+F11";
const char * const NEXT_KEY = "F10";
const char * const STEPI_KEY = "";
const char * const NEXTI_KEY = "";
const char * const REVERSE_KEY = "F12";
const char * const RUN_TO_LINE_KEY = "";
const char * const RUN_TO_FUNCTION_KEY = "";
@@ -218,6 +217,13 @@ DebugMode::~DebugMode()
namespace Debugger {
namespace Internal {
static QIcon locationMarkIcon()
{
static const QIcon icon(":/debugger/images/location.svg");
return icon;
}
// Used in "real" editors
class LocationMark : public TextEditor::BaseTextMark
{
Q_OBJECT
@@ -226,25 +232,13 @@ public:
LocationMark(const QString &fileName, int linenumber)
: BaseTextMark(fileName, linenumber)
{}
~LocationMark();
QIcon icon() const;
QIcon icon() const { return locationMarkIcon(); }
void updateLineNumber(int /*lineNumber*/) {}
void updateBlock(const QTextBlock & /*block*/) {}
void removedFromEditor() {}
};
LocationMark::~LocationMark()
{
//qDebug() << "LOCATIONMARK DESTRUCTOR";
}
QIcon LocationMark::icon() const
{
static const QIcon icon(":/debugger/images/location.svg");
return icon;
}
} // namespace Internal
} // namespace Debugger
@@ -422,6 +416,7 @@ DebuggerPlugin::DebuggerPlugin()
: m_manager(0),
m_debugMode(0),
m_locationMark(0),
m_disassemblerViewAgent(0),
m_gdbRunningContext(0),
m_cmdLineEnabledEngines(AllEngineTypes),
m_cmdLineAttachPid(0),
@@ -682,14 +677,8 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
cmd->setDefaultKeySequence(QKeySequence(Constants::STEPOUT_KEY));
mdebug->addAction(cmd);
cmd = am->registerAction(m_manager->m_nextIAction,
Constants::NEXTI, debuggercontext);
cmd->setDefaultKeySequence(QKeySequence(Constants::NEXTI_KEY));
mdebug->addAction(cmd);
cmd = am->registerAction(m_manager->m_stepIAction,
Constants::STEPI, debuggercontext);
cmd->setDefaultKeySequence(QKeySequence(Constants::STEPI_KEY));
cmd = am->registerAction(theDebuggerAction(StepByInstruction),
Constants::STEP_BY_INSTRUCTION, debuggercontext);
mdebug->addAction(cmd);
cmd = am->registerAction(m_manager->m_runToLineAction,
@@ -831,9 +820,7 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
debugToolBarLayout->addWidget(toolButton(am->command(Constants::NEXT)->action()));
debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEP)->action()));
debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEPOUT)->action()));
debugToolBarLayout->addWidget(new Core::Utils::StyledSeparator);
debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEPI)->action()));
debugToolBarLayout->addWidget(toolButton(am->command(Constants::NEXTI)->action()));
debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEP_BY_INSTRUCTION)->action()));
#ifdef USE_REVERSE_DEBUGGING
debugToolBarLayout->addWidget(new Core::Utils::StyledSeparator);
debugToolBarLayout->addWidget(toolButton(am->command(Constants::REVERSE)->action()));
@@ -892,8 +879,8 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
connect(m_manager, SIGNAL(resetLocationRequested()),
this, SLOT(resetLocation()));
connect(m_manager, SIGNAL(gotoLocationRequested(QString,int,bool)),
this, SLOT(gotoLocation(QString,int,bool)));
connect(m_manager, SIGNAL(gotoLocationRequested(StackFrame,bool)),
this, SLOT(gotoLocation(StackFrame,bool)));
connect(m_manager, SIGNAL(statusChanged(int)),
this, SLOT(changeStatus(int)));
connect(m_manager, SIGNAL(previousModeRequested()),
@@ -1096,17 +1083,23 @@ void DebuggerPlugin::resetLocation()
m_locationMark = 0;
}
void DebuggerPlugin::gotoLocation(const QString &fileName, int lineNumber,
bool setMarker)
void DebuggerPlugin::gotoLocation(const StackFrame &frame, bool setMarker)
{
TextEditor::BaseTextEditor::openEditorAt(fileName, lineNumber);
if (setMarker) {
resetLocation();
m_locationMark = new LocationMark(fileName, lineNumber);
if (theDebuggerBoolSetting(StepByInstruction) || !frame.isUsable()) {
if (!m_disassemblerViewAgent)
m_disassemblerViewAgent = new DisassemblerViewAgent(m_manager);
m_disassemblerViewAgent->setFrame(frame);
if (setMarker)
resetLocation();
} else {
TextEditor::BaseTextEditor::openEditorAt(frame.file, frame.line);
if (setMarker) {
resetLocation();
m_locationMark = new LocationMark(frame.file, frame.line);
}
}
}
void DebuggerPlugin::changeStatus(int status)
{
bool startIsContinue = (status == DebuggerInferiorStopped);
@@ -1157,9 +1150,8 @@ void DebuggerPlugin::onModeChanged(IMode *mode)
// different then the debugger mode. E.g. Welcome and Help mode and
// also on shutdown.
if (mode != m_debugMode) {
if (mode != m_debugMode)
return;
}
EditorManager *editorManager = EditorManager::instance();
if (editorManager->currentEditor())

View File

@@ -50,6 +50,8 @@ class IMode;
namespace TextEditor {
class ITextEditor;
class ITextMark;
class BaseTextMark;
}
namespace Debugger {
@@ -59,7 +61,8 @@ class BreakpointData;
class DebuggerManager;
class DebuggerRunner;
class DebugMode;
class LocationMark;
class DisassemblerViewAgent;
class StackFrame;
class DebuggerPlugin : public ExtensionSystem::IPlugin
{
@@ -94,7 +97,7 @@ private slots:
void updateActions(int status);
void resetLocation();
void gotoLocation(const QString &fileName, int line, bool setMarker);
void gotoLocation(const StackFrame &frame, bool setMarker);
void breakpointSetRemoveMarginActionTriggered();
void breakpointEnableDisableMarginActionTriggered();
@@ -127,7 +130,8 @@ private:
DebuggerRunner *m_debuggerRunner;
QString m_previousMode;
LocationMark *m_locationMark;
TextEditor::BaseTextMark *m_locationMark;
DisassemblerViewAgent *m_disassemblerViewAgent;
int m_gdbRunningContext;
unsigned m_cmdLineEnabledEngines;
quint64 m_cmdLineAttachPid;

View File

@@ -30,7 +30,7 @@
#ifndef DEBUGGER_DEBUGGERTOOLTIP_H
#define DEBUGGER_DEBUGGERTOOLTIP_H
#include <qglobal.h>
#include <QtCore/QtGlobal>
QT_BEGIN_NAMESPACE
class QAbstractItemModel;

View File

@@ -970,11 +970,11 @@ void GdbEngine::handleExecRunToFunction(const GdbResultRecord &record, const QVa
qq->notifyInferiorStopped();
q->showStatusMessage(tr("Run to Function finished. Stopped."));
GdbMi frame = record.data.findChild("frame");
QString file = QString::fromLocal8Bit(frame.findChild("fullname").data());
int line = frame.findChild("line").data().toInt();
qDebug() << "HIT:" << file << line << "IN" << frame.toString()
<< "--" << record.toString();
q->gotoLocation(file, line, true);
StackFrame f;
f.file = QString::fromLocal8Bit(frame.findChild("fullname").data());
f.line = frame.findChild("line").data().toInt();
f.address = _(frame.findChild("addr").data());
q->gotoLocation(f, true);
}
static bool isExitedReason(const QByteArray &reason)
@@ -1229,11 +1229,11 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
qq->notifyInferiorStopped();
q->showStatusMessage(tr("Run to Function finished. Stopped."));
GdbMi frame = data.findChild("frame");
QString file = QString::fromLocal8Bit(frame.findChild("fullname").data());
int line = frame.findChild("line").data().toInt();
qDebug() << "HIT:" << file << line << "IN" << frame.toString()
<< "--" << data.toString();
q->gotoLocation(file, line, true);
StackFrame f;
f.file = QString::fromLocal8Bit(frame.findChild("fullname").data());
f.line = frame.findChild("line").data().toInt();
f.address = _(frame.findChild("addr").data());
q->gotoLocation(f, true);
#endif
}
@@ -1853,6 +1853,9 @@ void GdbEngine::runToFunctionExec(const QString &functionName)
void GdbEngine::jumpToLineExec(const QString &fileName, int lineNumber)
{
StackFrame frame;
frame.file = fileName;
frame.line = lineNumber;
#if 1
// not available everywhere?
//sendCliCommand(_("tbreak ") + fileName + ':' + QString::number(lineNumber));
@@ -1864,11 +1867,11 @@ void GdbEngine::jumpToLineExec(const QString &fileName, int lineNumber)
// ~"run1 (argc=1, argv=0x7fffbf1f5538) at test1.cpp:242"
// ~"242\t x *= 2;"
// 23^done"
q->gotoLocation(fileName, lineNumber, true);
q->gotoLocation(frame, true);
//setBreakpoint();
//postCommand(_("jump ") + fileName + ':' + QString::number(lineNumber));
#else
q->gotoLocation(fileName, lineNumber, true);
q->gotoLocation(frame, true);
setBreakpoint(fileName, lineNumber);
postCommand(_("jump ") + fileName + ':' + QString::number(lineNumber));
#endif
@@ -2566,13 +2569,9 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record, const QVari
theDebuggerAction(ExpandStack)->setEnabled(canExpand);
qq->stackHandler()->setFrames(stackFrames, canExpand);
if (topFrame != -1) {
// updates of locals already triggered early
if (topFrame != -1 || theDebuggerBoolSetting(StepByInstruction)) {
const StackFrame &frame = qq->stackHandler()->currentFrame();
if (frame.isUsable())
q->gotoLocation(frame.file, frame.line, true);
else
qDebug() << "FULL NAME NOT USABLE 0:" << frame.file << topFrame;
q->gotoLocation(frame, true);
}
}
@@ -2622,7 +2621,7 @@ void GdbEngine::activateFrame(int frameIndex)
const StackFrame &frame = stackHandler->currentFrame();
if (frame.isUsable())
q->gotoLocation(frame.file, frame.line, true);
q->gotoLocation(frame, true);
else
qDebug() << "FULL NAME NOT USABLE:" << frame.file;
}
@@ -4004,6 +4003,18 @@ void GdbEngine::handleWatchPoint(const GdbResultRecord &record, const QVariant &
}
}
static QVariant agentCookie(void *agent)
{
return QVariant(quint64(quintptr(agent)));
}
void GdbEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length)
{
//qDebug() << "GDB MEMORY FETCH" << addr << length;
postCommand(_("-data-read-memory %1 x 1 1 %2").arg(addr).arg(length),
NeedsStop, CB(handleFetchMemory), agentCookie(agent));
}
void GdbEngine::handleFetchMemory(const GdbResultRecord &record,
const QVariant &cookie)
{
@@ -4017,7 +4028,7 @@ void GdbEngine::handleFetchMemory(const GdbResultRecord &record,
QTC_ASSERT(agent, return);
QByteArray ba;
GdbMi memory = record.data.findChild("memory");
QTC_ASSERT(memory.children().size() == 1, return);
QTC_ASSERT(memory.children().size() <= 1, return);
GdbMi memory0 = memory.children().at(0); // we asked for only one 'row'
quint64 addr = memory0.findChild("addr").data().toULongLong(&ok, 0);
QTC_ASSERT(ok, return);
@@ -4031,13 +4042,149 @@ void GdbEngine::handleFetchMemory(const GdbResultRecord &record,
agent->addLazyData(addr, ba);
}
void GdbEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length)
void GdbEngine::fetchDisassembler(DisassemblerViewAgent *agent,
const StackFrame &frame)
{
//qDebug() << "GDB MEMORY FETCH" << addr << length;
postCommand(_("-data-read-memory %1 x 1 1 %2").arg(addr).arg(length),
NeedsStop, CB(handleFetchMemory), QVariant(quint64(agent)));
if (frame.file.isEmpty()) {
fetchDisassemblerByAddress(agent, true);
} else {
// Disassemble full function:
QString cmd = _("-data-disassemble -f %1 -l %2 -n -1 -- 1");
postCommand(cmd.arg(frame.file).arg(frame.line),
Discardable, CB(handleFetchDisassemblerByLine), agentCookie(agent));
}
}
void GdbEngine::fetchDisassemblerByAddress(DisassemblerViewAgent *agent,
bool useMixedMode)
{
QTC_ASSERT(agent, return);
bool ok = true;
quint64 address = agent->address().toULongLong(&ok, 0);
quint64 start = address - 20;
quint64 end = address + 100;
// -data-disassemble [ -s start-addr -e end-addr ]
// | [ -f filename -l linenum [ -n lines ] ] -- mode
if (useMixedMode)
postCommand(_("-data-disassemble -s %1 -e %2 -- 1").arg(start).arg(end),
Discardable, CB(handleFetchDisassemblerByAddress1), agentCookie(agent));
else
postCommand(_("-data-disassemble -s %1 -e %2 -- 0").arg(start).arg(end),
Discardable, CB(handleFetchDisassemblerByAddress0), agentCookie(agent));
}
static QByteArray parseLine(const GdbMi &line)
{
QByteArray ba;
ba.reserve(200);
QByteArray address = line.findChild("address").data();
QByteArray funcName = line.findChild("func-name").data();
QByteArray offset = line.findChild("offset").data();
QByteArray inst = line.findChild("inst").data();
ba += address + QByteArray(15 - address.size(), ' ');
ba += funcName + "+" + offset + " ";
ba += QByteArray(30 - funcName.size() - offset.size(), ' ');
ba += inst;
ba += '\n';
return ba;
}
static QString parseDisassembler(const GdbMi &lines)
{
// ^done,data={asm_insns=[src_and_asm_line={line="1243",file=".../app.cpp",
// line_asm_insn=[{address="0x08054857",func-name="main",offset="27",
// inst="call 0x80545b0 <_Z13testQFileInfov>"}]},
// src_and_asm_line={line="1244",file=".../app.cpp",
// line_asm_insn=[{address="0x0805485c",func-name="main",offset="32",
//inst="call 0x804cba1 <_Z11testObject1v>"}]}]}
// - or -
// ^done,asm_insns=[
// {address="0x0805acf8",func-name="...",offset="25",inst="and $0xe8,%al"},
// {address="0x0805acfa",func-name="...",offset="27",inst="pop %esp"},
QList<QByteArray> fileContents;
bool fileLoaded = false;
QByteArray ba;
ba.reserve(200 * lines.children().size());
// FIXME: Performance?
foreach (const GdbMi &child, lines.children()) {
if (child.hasName("src_and_asm_line")) {
// mixed mode
int line = child.findChild("line").data().toInt();
QByteArray fileName = child.findChild("file").data();
if (!fileLoaded) {
QFile file(QFile::decodeName(fileName));
file.open(QIODevice::ReadOnly);
fileContents = file.readAll().split('\n');
fileLoaded = true;
}
if (line >= 0 && line < fileContents.size())
ba += " " + fileContents.at(line) + '\n';
GdbMi insn = child.findChild("line_asm_insn");
foreach (const GdbMi &line, insn.children())
ba += parseLine(line);
} else {
// the non-mixed version
ba += parseLine(child);
}
}
return _(ba);
}
void GdbEngine::handleFetchDisassemblerByLine(const GdbResultRecord &record,
const QVariant &cookie)
{
bool ok = true;
DisassemblerViewAgent *agent = (DisassemblerViewAgent *)cookie.toULongLong(&ok);
QTC_ASSERT(agent, return);
if (record.resultClass == GdbResultDone) {
GdbMi lines = record.data.findChild("asm_insns");
if (lines.children().isEmpty())
fetchDisassemblerByAddress(agent, true);
else
agent->setContents(parseDisassembler(lines));
} else if (record.resultClass == GdbResultError) {
//536^error,msg="mi_cmd_disassemble: Invalid line number"
QByteArray msg = record.data.findChild("msg").data();
if (msg == "mi_cmd_disassemble: Invalid line number")
fetchDisassemblerByAddress(agent, true);
}
}
void GdbEngine::handleFetchDisassemblerByAddress1(const GdbResultRecord &record,
const QVariant &cookie)
{
bool ok = true;
DisassemblerViewAgent *agent = (DisassemblerViewAgent *)cookie.toULongLong(&ok);
QTC_ASSERT(agent, return);
if (record.resultClass == GdbResultDone) {
GdbMi lines = record.data.findChild("asm_insns");
if (lines.children().isEmpty())
fetchDisassemblerByAddress(agent, false);
else
agent->setContents(parseDisassembler(lines));
}
}
void GdbEngine::handleFetchDisassemblerByAddress0(const GdbResultRecord &record,
const QVariant &cookie)
{
bool ok = true;
DisassemblerViewAgent *agent = (DisassemblerViewAgent *)cookie.toULongLong(&ok);
QTC_ASSERT(agent, return);
if (record.resultClass == GdbResultDone) {
GdbMi lines = record.data.findChild("asm_insns");
agent->setContents(parseDisassembler(lines));
}
}
IDebuggerEngine *createGdbEngine(DebuggerManager *parent, QList<Core::IOptionsPage*> *opts)
{
opts->push_back(new GdbOptionsPage);

View File

@@ -125,6 +125,17 @@ private:
void fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 length);
void handleFetchMemory(const GdbResultRecord &record, const QVariant &cookie);
void fetchDisassembler(DisassemblerViewAgent *agent,
const StackFrame &frame);
void fetchDisassemblerByAddress(DisassemblerViewAgent *agent,
bool useMixedMode);
void handleFetchDisassemblerByLine(const GdbResultRecord &record,
const QVariant &cookie);
void handleFetchDisassemblerByAddress1(const GdbResultRecord &record,
const QVariant &cookie);
void handleFetchDisassemblerByAddress0(const GdbResultRecord &record,
const QVariant &cookie);
Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
Q_SLOT void setUseDebuggingHelpers(const QVariant &on);

View File

@@ -46,10 +46,12 @@ class ITextEditor;
namespace Debugger {
namespace Internal {
class DebuggerStartParameters;
class DisassemblerViewAgent;
class MemoryViewAgent;
class StackFrame;
class Symbol;
class WatchData;
struct DebuggerStartParameters;
class MemoryViewAgent;
class IDebuggerEngine : public QObject
{
@@ -98,6 +100,8 @@ public:
virtual void watchPoint(const QPoint &) {}
virtual void fetchMemory(MemoryViewAgent *, quint64 addr, quint64 length)
{ Q_UNUSED(addr); Q_UNUSED(length); }
virtual void fetchDisassembler(DisassemblerViewAgent *, const StackFrame &frame)
{ Q_UNUSED(frame); }
};
} // namespace Internal

View File

@@ -76,6 +76,12 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const
const Register &reg = m_registers.at(index.row());
if (role == Qt::UserRole + 1) {
bool ok = true;
qulonglong value = reg.value.toULongLong(&ok, 0);
return QString::fromLatin1("0x") + QString::number(value, 16);
}
const QString padding = " ";
if (role == Qt::DisplayRole) {
switch (index.column()) {

View File

@@ -30,6 +30,7 @@
#include "registerwindow.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerconstants.h"
#include <QtCore/QDebug>
@@ -47,8 +48,9 @@
using namespace Debugger::Internal;
using namespace Debugger::Constants;
RegisterWindow::RegisterWindow()
: m_alwaysResizeColumnsToContents(true), m_alwaysReloadContents(false)
RegisterWindow::RegisterWindow(DebuggerManager *manager)
: m_manager(manager), m_alwaysResizeColumnsToContents(true),
m_alwaysReloadContents(false)
{
QAction *act = theDebuggerAction(UseAlternatingRowColors);
setWindowTitle(tr("Registers"));
@@ -81,6 +83,17 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
actAlwaysReload->setChecked(m_alwaysReloadContents);
menu.addSeparator();
QModelIndex idx = indexAt(ev->pos());
QString address = model()->data(idx, Qt::UserRole + 1).toString();
QAction *actShowMemory = menu.addAction(QString());
if (address.isEmpty()) {
actShowMemory->setText(tr("Open memory editor"));
actShowMemory->setEnabled(false);
} else {
actShowMemory->setText(tr("Open memory editor at %1").arg(address));
}
menu.addSeparator();
int base = model()->data(QModelIndex(), Qt::UserRole).toInt();
QAction *act16 = menu.addAction(tr("Hexadecimal"));
act16->setCheckable(true);
@@ -108,6 +121,8 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev)
reloadContents();
else if (act == actAlwaysReload)
setAlwaysReloadContents(!m_alwaysReloadContents);
else if (act == actShowMemory)
(void) new MemoryViewAgent(m_manager, address);
else if (act) {
base = (act == act10 ? 10 : act == act8 ? 8 : act == act2 ? 2 : 16);
QMetaObject::invokeMethod(model(), "setNumberBase", Q_ARG(int, base));

View File

@@ -35,12 +35,14 @@
namespace Debugger {
namespace Internal {
class DebuggerManager;
class RegisterWindow : public QTreeView
{
Q_OBJECT
public:
RegisterWindow();
explicit RegisterWindow(DebuggerManager *manager);
void setModel(QAbstractItemModel *model);
signals:
@@ -57,6 +59,8 @@ private:
void resizeEvent(QResizeEvent *ev);
void contextMenuEvent(QContextMenuEvent *ev);
DebuggerManager *m_manager;
bool m_alwaysResizeColumnsToContents;
bool m_alwaysReloadContents;
};

View File

@@ -565,7 +565,10 @@ void ScriptEngine::maybeBreakNow(bool byFunction)
}
qq->notifyInferiorStopped();
q->gotoLocation(fileName, lineNumber, true);
StackFrame frame;
frame.file = fileName;
frame.line = lineNumber;
q->gotoLocation(frame, true);
updateLocals();
}

View File

@@ -0,0 +1,60 @@
/**************************************************************************
**
** 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_STACKFRAME_H
#define DEBUGGER_STACKFRAME_H
#include <QtCore/QString>
#include <QtCore/QVariant>
namespace Debugger {
namespace Internal {
struct StackFrame
{
StackFrame(int level = 0);
bool isUsable() const;
QString toToolTip() const;
QString toString() const;
int level;
QString function;
QString file; // we try to put an absolute file name in there
QString from;
QString to;
int line;
QString address;
};
} // namespace Internal
} // namespace Debugger
Q_DECLARE_METATYPE(Debugger::Internal::StackFrame);
#endif // DEBUGGER_STACKFRAME_H

View File

@@ -29,6 +29,8 @@
#include "stackhandler.h"
#include "debuggeractions.h"
#include <utils/qtcassert.h>
#include <QtCore/QAbstractTableModel>
@@ -46,6 +48,19 @@ bool StackFrame::isUsable() const
return !file.isEmpty() && QFileInfo(file).isReadable();
}
QString StackFrame::toString() const
{
QString res;
QTextStream str(&res);
str << StackHandler::tr("Address:") << " " << address << " "
<< StackHandler::tr("Function:") << " " << function << " "
<< StackHandler::tr("File:") << " " << file << " "
<< StackHandler::tr("Line:") << " " << line << " "
<< StackHandler::tr("From:") << " " << from << " "
<< StackHandler::tr("To:") << " " << to;
return res;
}
QString StackFrame::toToolTip() const
{
QString res;
@@ -117,14 +132,22 @@ QVariant StackHandler::data(const QModelIndex &index, int role) const
case 4: // Address
return frame.address;
}
} else if (role == Qt::ToolTipRole) {
return QVariant();
}
if (role == Qt::ToolTipRole) {
//: Tooltip for variable
return frame.toToolTip();
} else if (role == Qt::DecorationRole && index.column() == 0) {
}
if (role == Qt::DecorationRole && index.column() == 0) {
// Return icon that indicates whether this is the active stack frame
return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon;
}
if (role == Qt::UserRole)
return QVariant::fromValue(frame);
return QVariant();
}
@@ -149,7 +172,8 @@ Qt::ItemFlags StackHandler::flags(const QModelIndex &index) const
if (index.row() == m_stackFrames.size())
return QAbstractTableModel::flags(index);
const StackFrame &frame = m_stackFrames.at(index.row());
const bool isValid = (!frame.file.isEmpty() && !frame.function.isEmpty());
const bool isValid = (!frame.file.isEmpty() && !frame.function.isEmpty())
|| theDebuggerBoolSetting(StepByInstruction);
return isValid ? QAbstractTableModel::flags(index) : Qt::ItemFlags(0);
}

View File

@@ -30,11 +30,14 @@
#ifndef DEBUGGER_STACKHANDLER_H
#define DEBUGGER_STACKHANDLER_H
#include "stackframe.h"
#include <QtCore/QAbstractTableModel>
#include <QtCore/QObject>
#include <QtGui/QIcon>
namespace Debugger {
namespace Internal {
@@ -44,21 +47,6 @@ namespace Internal {
//
////////////////////////////////////////////////////////////////////////
struct StackFrame
{
StackFrame(int level = 0);
bool isUsable() const;
QString toToolTip() const;
int level;
QString function;
QString file; // we try to put an absolute file name in there
QString from;
QString to;
int line;
QString address;
};
/*! A model to represent the stack in a QTreeView. */
class StackHandler : public QAbstractTableModel
{

View File

@@ -28,8 +28,10 @@
**************************************************************************/
#include "stackwindow.h"
#include "stackframe.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
#include <utils/qtcassert.h>
@@ -46,11 +48,14 @@
#include <QtGui/QVBoxLayout>
using Debugger::Internal::StackWindow;
namespace Debugger {
namespace Internal {
StackWindow::StackWindow(QWidget *parent)
: QTreeView(parent), m_alwaysResizeColumnsToContents(false)
StackWindow::StackWindow(DebuggerManager *manager, QWidget *parent)
: QTreeView(parent), m_manager(manager), m_alwaysResizeColumnsToContents(false)
{
m_disassemblerAgent = new DisassemblerViewAgent(manager);
QAction *act = theDebuggerAction(UseAlternatingRowColors);
setWindowTitle(tr("Stack"));
@@ -90,33 +95,60 @@ void StackWindow::rowActivated(const QModelIndex &index)
void StackWindow::contextMenuEvent(QContextMenuEvent *ev)
{
QModelIndex idx = indexAt(ev->pos());
StackFrame frame = model()->data(idx, Qt::UserRole).value<StackFrame>();
QString address = frame.address;
qDebug() << "RECV: " << frame.toToolTip();
QMenu menu;
QAction *act0 = new QAction(tr("Copy contents to clipboard"), &menu);
act0->setEnabled(model() != 0);
QAction *actAdjust = menu.addAction(tr("Adjust column widths to contents"));
QAction *act1 = new QAction(tr("Adjust column widths to contents"), &menu);
QAction *actAlwaysAdjust =
menu.addAction(tr("Always adjust column widths to contents"));
actAlwaysAdjust->setCheckable(true);
actAlwaysAdjust->setChecked(m_alwaysResizeColumnsToContents);
QAction *act2 = new QAction(tr("Always adjust column widths to contents"), &menu);
act2->setCheckable(true);
act2->setChecked(m_alwaysResizeColumnsToContents);
menu.addSeparator();
menu.addAction(theDebuggerAction(ExpandStack));
menu.addAction(act0);
menu.addSeparator();
menu.addAction(act1);
menu.addAction(act2);
QAction *actCopyContents = menu.addAction(tr("Copy contents to clipboard"));
actCopyContents->setEnabled(model() != 0);
QAction *actShowMemory = menu.addAction(QString());
if (address.isEmpty()) {
actShowMemory->setText(tr("Open memory editor"));
actShowMemory->setEnabled(false);
} else {
actShowMemory->setText(tr("Open memory editor at %1").arg(address));
}
QAction *actShowDisassembler = menu.addAction(QString());
if (address.isEmpty()) {
actShowDisassembler->setText(tr("Open disassembler"));
actShowDisassembler->setEnabled(false);
} else {
actShowDisassembler->setText(tr("Open disassembler at %1").arg(address));
}
menu.addSeparator();
menu.addAction(theDebuggerAction(SettingsDialog));
QAction *act = menu.exec(ev->globalPos());
if (act == act0)
if (act == actCopyContents)
copyContentsToClipboard();
else if (act == act1)
else if (act == actAdjust)
resizeColumnsToContents();
else if (act == act2)
else if (act == actAlwaysAdjust)
setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
else if (act == actShowMemory)
(void) new MemoryViewAgent(m_manager, address);
else if (act == actShowDisassembler)
m_disassemblerAgent->setFrame(frame);
}
void StackWindow::copyContentsToClipboard()
@@ -157,3 +189,6 @@ void StackWindow::setAlwaysResizeColumnsToContents(bool on)
header()->setResizeMode(2, mode);
header()->setResizeMode(3, mode);
}
} // namespace Internal
} // namespace Debugger

View File

@@ -40,13 +40,16 @@ QT_END_NAMESPACE
namespace Debugger {
namespace Internal {
class DebuggerManager;
class DisassemblerViewAgent;
class StackWindow : public QTreeView
{
Q_OBJECT
public:
StackWindow(QWidget *parent = 0);
StackWindow(DebuggerManager *manager, QWidget *parent = 0);
signals:
void frameActivated(int);
@@ -64,6 +67,8 @@ private:
void contextMenuEvent(QContextMenuEvent *ev);
void copyContentsToClipboard();
DebuggerManager *m_manager;
DisassemblerViewAgent *m_disassemblerAgent;
bool m_alwaysResizeColumnsToContents;
};

View File

@@ -297,9 +297,7 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
theDebuggerAction(WatchExpression)
->trigger(WatchHandler::watcherEditPlaceHolder());
} else if (act == actWatchKnownMemory) {
bool ok = true;
uint addr = address.toUInt(&ok, 0);
(void) new MemoryViewAgent(m_manager, addr);
(void) new MemoryViewAgent(m_manager, address);
} else if (act == actWatchUnknownMemory) {
QLabel *label = new QLabel("Enter an address: ");
QLineEdit *lineEdit = new QLineEdit;
@@ -310,11 +308,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
dialog.setWindowTitle("Select start address");
dialog.setLayout(layout);
connect(lineEdit, SIGNAL(returnPressed()), &dialog, SLOT(accept()));
if (dialog.exec() == QDialog::Accepted) {
bool ok = true;
uint addr = lineEdit->text().toUInt(&ok, 0);
(void) new MemoryViewAgent(m_manager, addr);
}
if (dialog.exec() == QDialog::Accepted)
(void) new MemoryViewAgent(m_manager, address);
} else if (act == actSelectWidgetToWatch) {
grabMouse(Qt::CrossCursor);
m_grabbing = true;