forked from qt-creator/qt-creator
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:
@@ -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();
|
||||
|
||||
47
src/plugins/debugger/cpptools.cpp
Normal file
47
src/plugins/debugger/cpptools.cpp
Normal 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
|
||||
44
src/plugins/debugger/cpptools.h
Normal file
44
src/plugins/debugger/cpptools.h
Normal 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
|
||||
@@ -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(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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#ifndef DEBUGGER_DEBUGGERTOOLTIP_H
|
||||
#define DEBUGGER_DEBUGGERTOOLTIP_H
|
||||
|
||||
#include <qglobal.h>
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAbstractItemModel;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -76,6 +76,12 @@ QVariant RegisterHandler::data(const QModelIndex &index, int role) const
|
||||
|
||||
const Register ® = 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()) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
60
src/plugins/debugger/stackframe.h
Normal file
60
src/plugins/debugger/stackframe.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user