2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2010-12-08 12:43:11 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2010-12-08 12:43:11 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2010-12-08 12:43:11 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2010-12-08 12:43:11 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 17:14:20 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2010-12-08 12:43:11 +01:00
|
|
|
|
|
|
|
|
#include "memoryagent.h"
|
|
|
|
|
|
2012-06-03 23:05:58 +02:00
|
|
|
#include "breakhandler.h"
|
2010-12-08 12:43:11 +01:00
|
|
|
#include "debuggerengine.h"
|
2011-04-08 16:18:47 +02:00
|
|
|
#include "debuggerstartparameters.h"
|
2010-12-08 12:43:11 +01:00
|
|
|
#include "debuggercore.h"
|
2011-04-21 15:52:51 +02:00
|
|
|
#include "debuggerinternalconstants.h"
|
2016-07-14 10:00:15 +02:00
|
|
|
#include "registerhandler.h"
|
|
|
|
|
|
|
|
|
|
#include <bineditor/bineditorservice.h>
|
2010-12-08 12:43:11 +01:00
|
|
|
|
|
|
|
|
#include <coreplugin/coreconstants.h>
|
2013-03-26 11:32:14 +01:00
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
2010-12-08 12:43:11 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2016-08-03 22:19:34 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2015-02-26 13:38:54 +01:00
|
|
|
#include <coreplugin/idocument.h>
|
2014-11-25 13:08:18 +01:00
|
|
|
#include <coreplugin/messagebox.h>
|
2010-12-08 12:43:11 +01:00
|
|
|
|
|
|
|
|
#include <utils/qtcassert.h>
|
2011-04-19 12:17:48 +02:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
#include <extensionsystem/invoker.h>
|
2010-12-08 12:43:11 +01:00
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
|
2011-04-08 16:18:47 +02:00
|
|
|
#include <cstring>
|
2010-12-08 12:43:11 +01:00
|
|
|
|
|
|
|
|
using namespace Core;
|
2016-07-14 10:00:15 +02:00
|
|
|
using namespace ProjectExplorer;
|
2010-12-08 12:43:11 +01:00
|
|
|
|
|
|
|
|
namespace Debugger {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
enum { BinBlockSize = 1024 };
|
|
|
|
|
enum { DataRange = 1024 * 1024 };
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Debugger::Internal::MemoryView
|
|
|
|
|
\brief The MemoryView class is a base class for memory view tool windows.
|
|
|
|
|
|
|
|
|
|
This class is a small tool-window that stays on top and displays a chunk
|
|
|
|
|
of memory based on the widget provided by the BinEditor plugin.
|
|
|
|
|
|
|
|
|
|
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class MemoryView : public QWidget
|
|
|
|
|
{
|
|
|
|
|
public:
|
2016-08-03 22:19:34 +02:00
|
|
|
explicit MemoryView(BinEditor::EditorService *service)
|
|
|
|
|
: QWidget(ICore::dialogParent(), Qt::Tool), m_service(service)
|
2016-07-14 10:00:15 +02:00
|
|
|
{
|
|
|
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
2016-08-03 22:19:34 +02:00
|
|
|
auto layout = new QVBoxLayout(this);
|
|
|
|
|
layout->addWidget(service->widget());
|
2016-07-14 10:00:15 +02:00
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
setMinimumWidth(400);
|
|
|
|
|
resize(800, 200);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
2016-08-03 22:19:34 +02:00
|
|
|
void setMarkup(const QList<MemoryMarkup> &markup)
|
2016-07-14 10:00:15 +02:00
|
|
|
{
|
2016-08-03 22:19:34 +02:00
|
|
|
if (m_service) {
|
|
|
|
|
m_service->clearMarkup();
|
|
|
|
|
for (const MemoryMarkup &m : markup)
|
|
|
|
|
m_service->addMarkup(m.address, m.length, m.color, m.toolTip);
|
|
|
|
|
m_service->commitMarkup();
|
|
|
|
|
}
|
2016-07-14 10:00:15 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 22:19:34 +02:00
|
|
|
protected:
|
|
|
|
|
BinEditor::EditorService *m_service;
|
2016-07-14 10:00:15 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Debugger::Internal::RegisterMemoryView
|
|
|
|
|
\brief The RegisterMemoryView class provides a memory view that shows the
|
|
|
|
|
memory around the contents of a register (such as stack pointer,
|
|
|
|
|
program counter), tracking changes of the register value.
|
|
|
|
|
|
|
|
|
|
Connects to Debugger::Internal::RegisterHandler to listen for changes
|
|
|
|
|
of the register value.
|
|
|
|
|
|
|
|
|
|
\note Some registers might switch to 0 (for example, 'rsi','rbp'
|
|
|
|
|
while stepping out of a function with parameters).
|
|
|
|
|
This must be handled gracefully.
|
|
|
|
|
|
|
|
|
|
\sa Debugger::Internal::RegisterHandler, Debugger::Internal::RegisterWindow
|
|
|
|
|
\sa Debugger::Internal::MemoryAgent, Debugger::DebuggerEngine
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class RegisterMemoryView : public MemoryView
|
|
|
|
|
{
|
|
|
|
|
public:
|
2016-08-03 22:19:34 +02:00
|
|
|
RegisterMemoryView(BinEditor::EditorService *service, quint64 addr, const QString ®Name,
|
|
|
|
|
RegisterHandler *rh)
|
|
|
|
|
: MemoryView(service), m_registerName(regName), m_registerAddress(addr)
|
2016-07-14 10:00:15 +02:00
|
|
|
{
|
|
|
|
|
connect(rh, &QAbstractItemModel::modelReset, this, &QWidget::close);
|
|
|
|
|
connect(rh, &RegisterHandler::registerChanged, this, &RegisterMemoryView::onRegisterChanged);
|
2016-08-03 22:19:34 +02:00
|
|
|
m_service->updateContents();
|
2016-07-14 10:00:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void onRegisterChanged(const QString &name, quint64 value)
|
|
|
|
|
{
|
|
|
|
|
if (name == m_registerName)
|
|
|
|
|
setRegisterAddress(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setRegisterAddress(quint64 v)
|
|
|
|
|
{
|
|
|
|
|
if (v == m_registerAddress) {
|
2016-08-03 22:19:34 +02:00
|
|
|
if (m_service)
|
|
|
|
|
m_service->updateContents();
|
2016-07-14 10:00:15 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_registerAddress = v;
|
2016-08-03 22:19:34 +02:00
|
|
|
if (m_service)
|
|
|
|
|
m_service->setSizes(v, DataRange, BinBlockSize);
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
setWindowTitle(registerViewTitle(m_registerName, v));
|
|
|
|
|
if (v)
|
|
|
|
|
setMarkup(registerViewMarkup(v, m_registerName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString m_registerName;
|
|
|
|
|
quint64 m_registerAddress;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QString registerViewTitle(const QString ®isterName, quint64 addr)
|
|
|
|
|
{
|
|
|
|
|
return MemoryAgent::tr("Memory at Register \"%1\" (0x%2)").arg(registerName).arg(addr, 0, 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<MemoryMarkup> registerViewMarkup(quint64 a, const QString ®Name)
|
|
|
|
|
{
|
|
|
|
|
return { MemoryMarkup(a, 1, QColor(Qt::blue).lighter(),
|
|
|
|
|
MemoryAgent::tr("Register \"%1\"").arg(regName)) };
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-08 12:43:11 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
2010-12-14 12:29:32 +01:00
|
|
|
// MemoryAgent
|
2010-12-08 12:43:11 +01:00
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
/*!
|
2011-01-26 17:22:25 +01:00
|
|
|
\class Debugger::Internal::MemoryAgent
|
2010-12-08 12:43:11 +01:00
|
|
|
|
|
|
|
|
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.
|
2011-04-19 12:17:48 +02:00
|
|
|
|
|
|
|
|
Memory can be shown as
|
|
|
|
|
\list
|
2013-02-06 08:50:23 +01:00
|
|
|
\li Editor: Create an IEditor using the normal editor factory
|
2011-04-19 12:17:48 +02:00
|
|
|
interface (m_editors)
|
2013-02-06 08:50:23 +01:00
|
|
|
\li View: Separate top-level view consisting of a Bin Editor widget
|
2011-04-19 12:17:48 +02:00
|
|
|
(m_view).
|
|
|
|
|
\endlist
|
|
|
|
|
|
2015-05-22 08:58:39 +02:00
|
|
|
Views are asked to update themselves directly by the owning
|
|
|
|
|
DebuggerEngine.
|
2011-04-19 12:17:48 +02:00
|
|
|
An exception are views of class Debugger::RegisterMemoryView tracking the
|
|
|
|
|
content pointed to by a register (eg stack pointer, instruction pointer).
|
|
|
|
|
They are connected to the set/changed signals of
|
|
|
|
|
the engine's register handler.
|
|
|
|
|
|
|
|
|
|
\sa Debugger::MemoryView, Debugger::RegisterMemoryView
|
2010-12-08 12:43:11 +01:00
|
|
|
*/
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
BinEditor::FactoryService *binEditorFactory()
|
2010-12-08 12:43:11 +01:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
static auto theBinEditorFactory = ExtensionSystem::PluginManager::getObject<BinEditor::FactoryService>();
|
|
|
|
|
return theBinEditorFactory;
|
2010-12-08 12:43:11 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
bool MemoryAgent::hasBinEditor()
|
2010-12-08 12:43:11 +01:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
return binEditorFactory() != nullptr;
|
2011-04-19 12:17:48 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
MemoryAgent::MemoryAgent(const MemoryViewSetupData &data, DebuggerEngine *engine)
|
2016-08-03 22:19:34 +02:00
|
|
|
: m_engine(engine), m_trackRegisters(data.trackRegisters)
|
2011-04-19 12:17:48 +02:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
auto factory = binEditorFactory();
|
|
|
|
|
if (!factory)
|
2011-04-19 12:17:48 +02:00
|
|
|
return;
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
QString title = data.title.isEmpty() ? tr("Memory at 0x%1").arg(data.startAddress, 0, 16) : data.title;
|
2016-08-03 22:19:34 +02:00
|
|
|
if (!data.separateView && !title.endsWith('$'))
|
2016-07-14 10:00:15 +02:00
|
|
|
title.append(" $");
|
2010-12-08 12:43:11 +01:00
|
|
|
|
2016-08-03 22:19:34 +02:00
|
|
|
if (data.separateView) {
|
2016-07-14 10:00:15 +02:00
|
|
|
// Ask BIN editor plugin for factory service and have it create a bin editor widget.
|
|
|
|
|
m_service = factory->createEditorService(title, false);
|
|
|
|
|
} else {
|
|
|
|
|
// Editor: Register tracking not supported.
|
|
|
|
|
m_service = factory->createEditorService(title, true);
|
|
|
|
|
}
|
2011-04-08 16:18:47 +02:00
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
if (!m_service)
|
|
|
|
|
return;
|
2011-04-08 16:18:47 +02:00
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
m_service->setNewRangeRequestHandler([this](quint64 address) {
|
|
|
|
|
m_service->setSizes(address, DataRange, BinBlockSize);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_service->setFetchDataHandler([this](quint64 address) {
|
|
|
|
|
m_engine->fetchMemory(this, address, BinBlockSize);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_service->setNewWindowRequestHandler([this](quint64 address) {
|
|
|
|
|
MemoryViewSetupData data;
|
|
|
|
|
data.startAddress = address;
|
|
|
|
|
auto agent = new MemoryAgent(data, m_engine);
|
|
|
|
|
if (!agent->isUsable())
|
|
|
|
|
delete agent;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_service->setDataChangedHandler([this](quint64 address, const QByteArray &data) {
|
|
|
|
|
m_engine->changeMemory(this, address, data);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_service->setWatchPointRequestHandler([this](quint64 address, uint size) {
|
|
|
|
|
m_engine->breakHandler()->setWatchpointAtAddress(address, size);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_service->setAboutToBeDestroyedHandler([this] { m_service = nullptr; });
|
2011-04-08 16:18:47 +02:00
|
|
|
|
2011-04-19 12:17:48 +02:00
|
|
|
// Separate view?
|
2016-08-03 22:19:34 +02:00
|
|
|
if (data.separateView) {
|
2011-04-19 12:17:48 +02:00
|
|
|
// Memory view tracking register value, providing its own updating mechanism.
|
2016-08-03 22:19:34 +02:00
|
|
|
if (data.trackRegisters) {
|
|
|
|
|
auto view = new RegisterMemoryView(m_service, data.startAddress, data.registerName,
|
|
|
|
|
m_engine->registerHandler());
|
2016-07-14 10:00:15 +02:00
|
|
|
view->show();
|
2011-04-19 12:17:48 +02:00
|
|
|
} else {
|
|
|
|
|
// Ordinary memory view
|
2016-08-03 22:19:34 +02:00
|
|
|
auto view = new MemoryView(m_service);
|
2016-07-14 10:00:15 +02:00
|
|
|
view->setWindowTitle(title);
|
|
|
|
|
view->show();
|
2011-04-19 12:17:48 +02:00
|
|
|
}
|
2016-07-14 10:00:15 +02:00
|
|
|
} else {
|
|
|
|
|
m_service->editor()->document()->setTemporary(true);
|
|
|
|
|
m_service->editor()->document()->setProperty(Constants::OPENED_BY_DEBUGGER, QVariant(true));
|
2011-04-19 12:17:48 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 22:19:34 +02:00
|
|
|
m_service->setReadOnly(data.readOnly);
|
2016-07-14 10:00:15 +02:00
|
|
|
m_service->setNewWindowRequestAllowed(true);
|
|
|
|
|
m_service->setSizes(data.startAddress, DataRange, BinBlockSize);
|
2016-08-03 22:19:34 +02:00
|
|
|
m_service->clearMarkup();
|
|
|
|
|
for (const MemoryMarkup &m : data.markup)
|
|
|
|
|
m_service->addMarkup(m.address, m.length, m.color, m.toolTip);
|
|
|
|
|
m_service->commitMarkup();
|
2010-12-08 12:43:11 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
MemoryAgent::~MemoryAgent()
|
2010-12-08 12:43:11 +01:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
if (m_service) {
|
|
|
|
|
if (m_service->editor())
|
|
|
|
|
EditorManager::closeDocument(m_service->editor()->document());
|
|
|
|
|
if (m_service->widget())
|
|
|
|
|
m_service->widget()->close();
|
|
|
|
|
}
|
2010-12-08 12:43:11 +01:00
|
|
|
}
|
|
|
|
|
|
2010-12-14 12:29:32 +01:00
|
|
|
void MemoryAgent::updateContents()
|
2010-12-13 18:17:31 +01:00
|
|
|
{
|
2011-04-19 12:17:48 +02:00
|
|
|
// Update all views except register views, which trigger on
|
|
|
|
|
// register value set/changed.
|
2016-08-03 22:19:34 +02:00
|
|
|
if (!m_trackRegisters && m_service)
|
2016-07-14 10:00:15 +02:00
|
|
|
m_service->updateContents();
|
2010-12-13 18:17:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
void MemoryAgent::addData(quint64 address, const QByteArray &a)
|
2010-12-16 10:44:21 +01:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
QTC_ASSERT(m_service, return);
|
|
|
|
|
m_service->addData(address, a);
|
2010-12-16 10:44:21 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
void MemoryAgent::setFinished()
|
2011-04-19 12:17:48 +02:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
if (m_service)
|
|
|
|
|
m_service->setFinished();
|
2011-04-08 16:18:47 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-14 10:00:15 +02:00
|
|
|
bool MemoryAgent::isUsable()
|
2011-04-08 16:18:47 +02:00
|
|
|
{
|
2016-07-14 10:00:15 +02:00
|
|
|
return m_service != nullptr;
|
2011-04-08 16:18:47 +02:00
|
|
|
}
|
|
|
|
|
|
2010-12-08 12:43:11 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Debugger
|
2015-06-11 17:53:38 +03:00
|
|
|
|