mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-31 16:47:26 +00:00
Added emulation support (#553)
* emulation start button * add emul continue until syscall * reopen file after stopping debug * show debug context menu only when debugging * updated r2 * Attach to running process * fix bps issue in debug and attach mode * renamed signal and added attach icon
This commit is contained in:
parent
975e4c4a3d
commit
342fe77886
143
src/Cutter.cpp
143
src/Cutter.cpp
@ -777,65 +777,137 @@ void CutterCore::startDebug()
|
||||
cmd("ood");
|
||||
emit registersChanged();
|
||||
if (!currentlyDebugging) {
|
||||
setConfig("asm.flags", false);
|
||||
emit changeDebugView();
|
||||
emit flagsChanged();
|
||||
emit refreshCodeViews();
|
||||
currentlyDebugging = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::startEmulation()
|
||||
{
|
||||
if (!currentlyDebugging) {
|
||||
offsetPriorDebugging = getOffset();
|
||||
}
|
||||
// clear registers, init esil state, stack, progcounter at current seek
|
||||
cmd("ar0; aei; aeim; aeip");
|
||||
emit registersChanged();
|
||||
if (!currentlyDebugging || !currentlyEmulating) {
|
||||
// prevent register flags from appearing during debug/emul
|
||||
setConfig("asm.flags", false);
|
||||
// allows to view self-modifying code changes or other binary changes
|
||||
setConfig("io.cache", true);
|
||||
emit changeDebugView();
|
||||
emit flagsChanged();
|
||||
emit refreshCodeViews();
|
||||
currentlyDebugging = true;
|
||||
currentlyEmulating = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::attachDebug(int pid)
|
||||
{
|
||||
if (!currentlyDebugging) {
|
||||
offsetPriorDebugging = getOffset();
|
||||
}
|
||||
// attach to process with dbg plugin
|
||||
cmd("o-*; e cfg.debug = true; o+ dbg://" + QString::number(pid));
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
if (!currentlyDebugging || !currentlyEmulating) {
|
||||
// prevent register flags from appearing during debug/emul
|
||||
setConfig("asm.flags", false);
|
||||
emit changeDebugView();
|
||||
emit flagsChanged();
|
||||
currentlyDebugging = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::stopDebug()
|
||||
{
|
||||
// @TODO should first obtain correct signal to send.
|
||||
// Also, we do a ds since otherwise the process does not die.
|
||||
if (currentlyDebugging) {
|
||||
cmd("dk 9; ds; e cfg.debug = false; oo");
|
||||
if (currentlyEmulating) {
|
||||
cmd("aeim-; aei-; wcr; .ar-");
|
||||
currentlyEmulating = false;
|
||||
} else {
|
||||
// we do a ds since otherwise the process does not die.
|
||||
cmd("dk 9; ds; oo; .ar-");
|
||||
}
|
||||
seek(offsetPriorDebugging);
|
||||
emit changeDefinedView();
|
||||
setConfig("asm.flags", true);
|
||||
setConfig("io.cache", false);
|
||||
currentlyDebugging = false;
|
||||
emit changeDefinedView();
|
||||
emit flagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::continueDebug()
|
||||
{
|
||||
cmd("dc");
|
||||
emit registersChanged();
|
||||
if (currentlyDebugging) {
|
||||
cmd("dc");
|
||||
emit registersChanged();
|
||||
emit refreshCodeViews();
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::continueUntilDebug(QString offset)
|
||||
{
|
||||
cmd("dcu " + offset);
|
||||
emit registersChanged();
|
||||
if (currentlyDebugging) {
|
||||
if (!currentlyEmulating) {
|
||||
cmd("dcu " + offset);
|
||||
} else {
|
||||
cmd("aecu " + offset);
|
||||
}
|
||||
emit registersChanged();
|
||||
emit refreshCodeViews();
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::continueUntilCall()
|
||||
{
|
||||
cmd("dcc");
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
if (currentlyDebugging) {
|
||||
cmd("dcc");
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::continueUntilSyscall()
|
||||
{
|
||||
cmd("dcs");
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
if (currentlyDebugging) {
|
||||
if (currentlyEmulating) {
|
||||
cmd("aecs");
|
||||
} else {
|
||||
cmd("dcs");
|
||||
}
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::stepDebug()
|
||||
{
|
||||
cmd("ds");
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
if (currentlyDebugging) {
|
||||
cmd("ds");
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CutterCore::stepOverDebug()
|
||||
{
|
||||
cmd("dso");
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
if (currentlyDebugging) {
|
||||
cmd("dso");
|
||||
QString programCounterValue = cmd("dr?`drn PC`").trimmed();
|
||||
seek(programCounterValue);
|
||||
emit registersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QStringList CutterCore::getDebugPlugins()
|
||||
@ -885,7 +957,7 @@ void CutterCore::delBreakpoint(RVA addr)
|
||||
void CutterCore::delAllBreakpoints()
|
||||
{
|
||||
cmd("db-*");
|
||||
emit deletedAllBreakpoints();
|
||||
emit refreshCodeViews();
|
||||
}
|
||||
|
||||
void CutterCore::enableBreakpoint(RVA addr)
|
||||
@ -930,6 +1002,27 @@ QJsonDocument CutterCore::getBacktrace()
|
||||
return cmdj("dbtj");
|
||||
}
|
||||
|
||||
QList<ProcessDescription> CutterCore::getAllProcesses()
|
||||
{
|
||||
QList<ProcessDescription> ret;
|
||||
QJsonArray ProcessArray = cmdj("dplj").array();
|
||||
|
||||
for (QJsonValue value : ProcessArray) {
|
||||
QJsonObject procObject = value.toObject();
|
||||
|
||||
ProcessDescription proc;
|
||||
|
||||
proc.pid = procObject["pid"].toVariant().toInt();
|
||||
proc.uid = procObject["uid"].toVariant().toInt();
|
||||
proc.status = procObject["status"].toString();
|
||||
proc.path = procObject["path"].toString();
|
||||
|
||||
ret << proc;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<MemoryMapDescription> CutterCore::getMemoryMap()
|
||||
{
|
||||
QList<MemoryMapDescription> ret;
|
||||
|
14
src/Cutter.h
14
src/Cutter.h
@ -312,6 +312,13 @@ struct BreakpointDescription {
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct ProcessDescription {
|
||||
int pid;
|
||||
int uid;
|
||||
QString status;
|
||||
QString path;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FunctionDescription)
|
||||
Q_DECLARE_METATYPE(ImportDescription)
|
||||
Q_DECLARE_METATYPE(ExportDescription)
|
||||
@ -342,6 +349,7 @@ Q_DECLARE_METATYPE(SearchDescription)
|
||||
Q_DECLARE_METATYPE(SectionDescription)
|
||||
Q_DECLARE_METATYPE(MemoryMapDescription)
|
||||
Q_DECLARE_METATYPE(BreakpointDescription)
|
||||
Q_DECLARE_METATYPE(ProcessDescription)
|
||||
|
||||
class CutterCore: public QObject
|
||||
{
|
||||
@ -480,6 +488,8 @@ public:
|
||||
QJsonDocument getStack(int size = 0x40);
|
||||
QJsonDocument getBacktrace();
|
||||
void startDebug();
|
||||
void startEmulation();
|
||||
void attachDebug(int pid);
|
||||
void stopDebug();
|
||||
void continueDebug();
|
||||
void continueUntilCall();
|
||||
@ -497,6 +507,7 @@ public:
|
||||
QStringList getDebugPlugins();
|
||||
void setDebugPlugin(QString plugin);
|
||||
bool currentlyDebugging = false;
|
||||
bool currentlyEmulating = false;
|
||||
|
||||
RVA getOffsetJump(RVA addr);
|
||||
QString getDecompiledCode(RVA addr);
|
||||
@ -554,6 +565,7 @@ public:
|
||||
QList<SearchDescription> getAllSearch(QString search_for, QString space);
|
||||
BlockStatistics getBlockStatistics(unsigned int blocksCount);
|
||||
QList<BreakpointDescription> getBreakpoints();
|
||||
QList<ProcessDescription> getAllProcesses();
|
||||
|
||||
QList<XrefDescription> getXRefs(RVA addr, bool to, bool whole_function,
|
||||
const QString &filterType = QString::null);
|
||||
@ -584,7 +596,7 @@ signals:
|
||||
void registersChanged();
|
||||
void instructionChanged(RVA offset);
|
||||
void breakpointsChanged();
|
||||
void deletedAllBreakpoints();
|
||||
void refreshCodeViews();
|
||||
|
||||
void notesChanged(const QString ¬es);
|
||||
void projectSaved(const QString &name);
|
||||
|
@ -180,7 +180,8 @@ SOURCES += \
|
||||
widgets/MemoryMapWidget.cpp \
|
||||
dialogs/preferences/DebugOptionsWidget.cpp \
|
||||
widgets/BreakpointWidget.cpp \
|
||||
dialogs/BreakpointsDialog.cpp
|
||||
dialogs/BreakpointsDialog.cpp \
|
||||
dialogs/AttachProcDialog.cpp
|
||||
|
||||
HEADERS += \
|
||||
Cutter.h \
|
||||
@ -272,7 +273,8 @@ HEADERS += \
|
||||
widgets/MemoryMapWidget.h \
|
||||
dialogs/preferences/DebugOptionsWidget.h \
|
||||
widgets/BreakpointWidget.h \
|
||||
dialogs/BreakpointsDialog.h
|
||||
dialogs/BreakpointsDialog.h \
|
||||
dialogs/AttachProcDialog.h
|
||||
|
||||
FORMS += \
|
||||
dialogs/AboutDialog.ui \
|
||||
@ -325,7 +327,8 @@ FORMS += \
|
||||
widgets/MemoryMapWidget.ui \
|
||||
dialogs/preferences/DebugOptionsWidget.ui \
|
||||
widgets/BreakpointWidget.ui \
|
||||
dialogs/BreakpointsDialog.ui
|
||||
dialogs/BreakpointsDialog.ui \
|
||||
dialogs/AttachProcDialog.ui
|
||||
|
||||
RESOURCES += \
|
||||
resources.qrc \
|
||||
|
178
src/dialogs/AttachProcDialog.cpp
Normal file
178
src/dialogs/AttachProcDialog.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "MainWindow.h"
|
||||
#include "Cutter.h"
|
||||
#include "AttachProcDialog.h"
|
||||
#include "ui_AttachProcDialog.h"
|
||||
|
||||
#include "utils/Helpers.h"
|
||||
|
||||
ProcessModel::ProcessModel(QList<ProcessDescription> *processes, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
processes(processes)
|
||||
{
|
||||
}
|
||||
|
||||
int ProcessModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return processes->count();
|
||||
}
|
||||
|
||||
int ProcessModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return ProcessModel::ColumnCount;
|
||||
}
|
||||
|
||||
QVariant ProcessModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.row() >= processes->count())
|
||||
return QVariant();
|
||||
|
||||
const ProcessDescription &proc = processes->at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case PidColumn:
|
||||
return proc.pid;
|
||||
case UidColumn:
|
||||
return proc.uid;
|
||||
case StatusColumn:
|
||||
return proc.status;
|
||||
case PathColumn:
|
||||
return proc.path;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
case ProcDescriptionRole:
|
||||
return QVariant::fromValue(proc);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant ProcessModel::headerData(int section, Qt::Orientation, int role) const
|
||||
{
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (section) {
|
||||
case PidColumn:
|
||||
return tr("PID");
|
||||
case UidColumn:
|
||||
return tr("UID");
|
||||
case StatusColumn:
|
||||
return tr("Status");
|
||||
case PathColumn:
|
||||
return tr("Path");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessModel::beginReloadProcess()
|
||||
{
|
||||
beginResetModel();
|
||||
}
|
||||
|
||||
void ProcessModel::endReloadProcess()
|
||||
{
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
ProcessProxyModel::ProcessProxyModel(ProcessModel *sourceModel, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
setSourceModel(sourceModel);
|
||||
}
|
||||
|
||||
bool ProcessProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
{
|
||||
QModelIndex index = sourceModel()->index(row, 0, parent);
|
||||
ProcessDescription item = index.data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
return item.path.contains(filterRegExp());
|
||||
}
|
||||
|
||||
bool ProcessProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
ProcessDescription leftProc = left.data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
ProcessDescription rightProc = right.data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
|
||||
switch (left.column()) {
|
||||
case ProcessModel::PidColumn:
|
||||
return leftProc.pid < rightProc.pid;
|
||||
case ProcessModel::UidColumn:
|
||||
return leftProc.uid < rightProc.uid;
|
||||
case ProcessModel::StatusColumn:
|
||||
return leftProc.status < rightProc.status;
|
||||
case ProcessModel::PathColumn:
|
||||
return leftProc.path < rightProc.path;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return leftProc.pid < rightProc.pid;
|
||||
}
|
||||
|
||||
AttachProcDialog::AttachProcDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AttachProcDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
||||
processes = Core()->getAllProcesses();
|
||||
processModel = new ProcessModel(&processes, this);
|
||||
processProxyModel = new ProcessProxyModel(processModel, this);
|
||||
ui->procTreeView->setModel(processProxyModel);
|
||||
ui->procTreeView->sortByColumn(ProcessModel::PidColumn, Qt::AscendingOrder);
|
||||
connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), processProxyModel,
|
||||
SLOT(setFilterWildcard(const QString &)));
|
||||
qhelpers::setVerticalScrollMode(ui->procTreeView);
|
||||
|
||||
// focus on filter line
|
||||
ui->filterLineEdit->setFocus();
|
||||
// Event filter for capturing Ctrl/Cmd+Return
|
||||
ui->filterLineEdit->installEventFilter(this);
|
||||
}
|
||||
|
||||
AttachProcDialog::~AttachProcDialog() {}
|
||||
|
||||
void AttachProcDialog::on_buttonBox_accepted()
|
||||
{
|
||||
}
|
||||
|
||||
void AttachProcDialog::on_buttonBox_rejected()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
int AttachProcDialog::getPID()
|
||||
{
|
||||
ProcessDescription proc = ui->procTreeView->selectionModel()->currentIndex().data(
|
||||
ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
return proc.pid;
|
||||
}
|
||||
|
||||
bool AttachProcDialog::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
Q_UNUSED(obj);
|
||||
if (event -> type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast <QKeyEvent *> (event);
|
||||
|
||||
// Confirm comment by pressing Ctrl/Cmd+Return
|
||||
if ((keyEvent -> modifiers() & Qt::ControlModifier) &&
|
||||
((keyEvent -> key() == Qt::Key_Enter) || (keyEvent -> key() == Qt::Key_Return))) {
|
||||
this->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AttachProcDialog::on_procTreeView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
ProcessDescription proc = index.data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
accept();
|
||||
}
|
82
src/dialogs/AttachProcDialog.h
Normal file
82
src/dialogs/AttachProcDialog.h
Normal file
@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cutter.h"
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace Ui {
|
||||
class AttachProcDialog;
|
||||
}
|
||||
|
||||
class MainWindow;
|
||||
class QTreeWidget;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
|
||||
class ProcessModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QList<ProcessDescription> *processes;
|
||||
|
||||
public:
|
||||
enum Column { PidColumn = 0, UidColumn, StatusColumn, PathColumn, ColumnCount };
|
||||
enum Role { ProcDescriptionRole = Qt::UserRole };
|
||||
|
||||
ProcessModel(QList<ProcessDescription> *processes, QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
void beginReloadProcess();
|
||||
void endReloadProcess();
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ProcessProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ProcessProxyModel(ProcessModel *sourceModel, QObject *parent = nullptr);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AttachProcDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AttachProcDialog(QWidget *parent = nullptr);
|
||||
~AttachProcDialog();
|
||||
|
||||
int getPID();
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_rejected();
|
||||
void on_procTreeView_doubleClicked(const QModelIndex &index);
|
||||
|
||||
signals:
|
||||
void attachProcess(int pid);
|
||||
private:
|
||||
std::unique_ptr<Ui::AttachProcDialog> ui;
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
ProcessModel *processModel;
|
||||
ProcessProxyModel *processProxyModel;
|
||||
QList<ProcessDescription> processes;
|
||||
|
||||
};
|
116
src/dialogs/AttachProcDialog.ui
Normal file
116
src/dialogs/AttachProcDialog.ui
Normal file
@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AttachProcDialog</class>
|
||||
<widget class="QDialog" name="AttachProcDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select process to attach...</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeView" name="procTreeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeView::item
|
||||
{
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="filterLineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Quick Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>AttachProcDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>AttachProcDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
5
src/img/icons/play_light_attach.svg
Normal file
5
src/img/icons/play_light_attach.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
|
||||
<svg style="enable-background:new 0 0 24 32" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="32px" width="24px" version="1.1" y="0px" x="0px" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 32">
|
||||
<polygon points="0 0 24 16 0 32" fill="#aaacaf"/>
|
||||
<text x="15" y="10" font-family="Helvetica, Arial, sans-serif" font-size="13" stroke-width="2" stroke="#aaacaf" fill="#aaacaf" >A</text>
|
||||
</svg>
|
After Width: | Height: | Size: 521 B |
5
src/img/icons/play_light_debug.svg
Normal file
5
src/img/icons/play_light_debug.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
|
||||
<svg style="enable-background:new 0 0 24 32" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="32px" width="24px" version="1.1" y="0px" x="0px" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 32">
|
||||
<polygon points="0 0 24 16 0 32" fill="#aaacaf"/>
|
||||
<text x="15" y="10" font-family="Helvetica, Arial, sans-serif" font-size="13" stroke-width="2" stroke="#aaacaf" fill="#aaacaf" >D</text>
|
||||
</svg>
|
After Width: | Height: | Size: 521 B |
5
src/img/icons/play_light_emul.svg
Normal file
5
src/img/icons/play_light_emul.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
|
||||
<svg style="enable-background:new 0 0 24 32" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="32px" width="24px" version="1.1" y="0px" x="0px" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 32">
|
||||
<polygon points="0 0 24 16 0 32" fill="#aaacaf"/>
|
||||
<text x="15" y="10" font-family="Helvetica, Arial, sans-serif" font-size="13" stroke-width="2" stroke="#aaacaf" fill="#aaacaf" >E</text>
|
||||
</svg>
|
After Width: | Height: | Size: 521 B |
@ -237,10 +237,12 @@ void DisassemblyContextMenu::aboutToShowSlot()
|
||||
// decide to show Reverse jmp option
|
||||
showReverseJmpQuery();
|
||||
|
||||
// show debug options
|
||||
// @TODO determine if we are being debugged and only show the menu in those cases
|
||||
// maybe using dpt command
|
||||
debugMenuAction->setVisible(true);
|
||||
// only show debug options if we are currently debugging
|
||||
debugMenuAction->setVisible(Core()->currentlyDebugging);
|
||||
// currently there are is no breakpoint support in ESIL so
|
||||
// we dont show the option in case we are emulating
|
||||
actionAddBreakpoint.setVisible(!Core()->currentlyEmulating);
|
||||
|
||||
}
|
||||
|
||||
QKeySequence DisassemblyContextMenu::getCopySequence() const
|
||||
|
@ -19,7 +19,9 @@
|
||||
<file>img/icons/spin.svg</file>
|
||||
<file>img/icons/plus.svg</file>
|
||||
<file>img/icons/play.svg</file>
|
||||
<file>img/icons/play_light.svg</file>
|
||||
<file>img/icons/play_light_debug.svg</file>
|
||||
<file>img/icons/play_light_emul.svg</file>
|
||||
<file>img/icons/play_light_attach.svg</file>
|
||||
<file>img/icons/media-stop_light.svg</file>
|
||||
<file>img/icons/media-skip-forward_light.svg</file>
|
||||
<file>img/icons/continue_until_main.svg</file>
|
||||
|
@ -136,7 +136,7 @@ BreakpointWidget::BreakpointWidget(MainWindow *main, QAction *action) :
|
||||
connect(actionToggleBreakpoint, &QAction::triggered, this, &BreakpointWidget::toggleBreakpoint);
|
||||
connect(Core(), &CutterCore::refreshAll, this, &BreakpointWidget::refreshBreakpoint);
|
||||
connect(Core(), &CutterCore::breakpointsChanged, this, &BreakpointWidget::refreshBreakpoint);
|
||||
connect(Core(), &CutterCore::deletedAllBreakpoints, this, &BreakpointWidget::refreshBreakpoint);
|
||||
connect(Core(), &CutterCore::refreshCodeViews, this, &BreakpointWidget::refreshBreakpoint);
|
||||
connect(ui->addBreakpoint, &QAbstractButton::clicked, this, &BreakpointWidget::addBreakpointDialog);
|
||||
connect(ui->delBreakpoint, &QAbstractButton::clicked, this, &BreakpointWidget::delBreakpoint);
|
||||
connect(ui->delAllBreakpoints, &QAbstractButton::clicked, Core(), &CutterCore::delAllBreakpoints);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "DebugToolbar.h"
|
||||
#include "MainWindow.h"
|
||||
#include "dialogs/AttachProcDialog.cpp"
|
||||
|
||||
#include <QAction>
|
||||
#include <QPainter>
|
||||
@ -11,7 +12,9 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
main(main)
|
||||
{
|
||||
setObjectName("debugToolbar");
|
||||
QIcon startIcon = QIcon(":/img/icons/play_light.svg");
|
||||
QIcon startDebugIcon = QIcon(":/img/icons/play_light_debug.svg");
|
||||
QIcon startEmulIcon = QIcon(":/img/icons/play_light_emul.svg");
|
||||
QIcon startAttachIcon = QIcon(":/img/icons/play_light_attach.svg");
|
||||
QIcon stopIcon = QIcon(":/img/icons/media-stop_light.svg");
|
||||
QIcon continueIcon = QIcon(":/img/icons/media-skip-forward_light.svg");
|
||||
QIcon continueUntilMainIcon = QIcon(":/img/icons/continue_until_main.svg");
|
||||
@ -20,7 +23,9 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
QIcon stepIcon = QIcon(":/img/icons/step_light.svg");
|
||||
QIcon stepOverIcon = QIcon(":/img/icons/step_over_light.svg");
|
||||
|
||||
QAction *actionStart = new QAction(startIcon, tr("Start debug"), parent);
|
||||
actionStart = new QAction(startDebugIcon, tr("Start debug"), parent);
|
||||
actionStartEmul = new QAction(startEmulIcon, tr("Start emulation"), parent);
|
||||
QAction *actionAttach = new QAction(startAttachIcon, tr("Attach to process"), parent);
|
||||
QAction *actionStop = new QAction(stopIcon, tr("Stop debug"), parent);
|
||||
QAction *actionContinue = new QAction(continueIcon, tr("Continue"), parent);
|
||||
QAction *actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent);
|
||||
@ -29,10 +34,19 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
QAction *actionStep = new QAction(stepIcon, tr("Step"), parent);
|
||||
QAction *actionStepOver = new QAction(stepOverIcon, tr("Step over"), parent);
|
||||
|
||||
QToolButton *startButton = new QToolButton;
|
||||
startButton->setPopupMode(QToolButton::MenuButtonPopup);
|
||||
connect(startButton, &QToolButton::triggered, startButton, &QToolButton::setDefaultAction);
|
||||
QMenu *startMenu = new QMenu;
|
||||
startMenu->addAction(actionStart);
|
||||
startMenu->addAction(actionStartEmul);
|
||||
startMenu->addAction(actionAttach);
|
||||
startButton->setDefaultAction(actionStart);
|
||||
startButton->setMenu(startMenu);
|
||||
|
||||
QToolButton *continueUntilButton = new QToolButton;
|
||||
continueUntilButton->setPopupMode(QToolButton::MenuButtonPopup);
|
||||
connect(continueUntilButton, &QToolButton::triggered, continueUntilButton, &QToolButton::setDefaultAction);
|
||||
|
||||
QMenu *continueUntilMenu = new QMenu;
|
||||
continueUntilMenu->addAction(actionContinueUntilMain);
|
||||
continueUntilMenu->addAction(actionContinueUntilCall);
|
||||
@ -40,7 +54,7 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
continueUntilButton->setMenu(continueUntilMenu);
|
||||
continueUntilButton->setDefaultAction(actionContinueUntilMain);
|
||||
|
||||
addAction(actionStart);
|
||||
addWidget(startButton);
|
||||
addAction(actionStop);
|
||||
addAction(actionContinue);
|
||||
addWidget(continueUntilButton);
|
||||
@ -48,10 +62,33 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
addAction(actionStepOver);
|
||||
|
||||
connect(actionStop, &QAction::triggered, Core(), &CutterCore::stopDebug);
|
||||
connect(actionStop, &QAction::triggered, [=](){ this->colorToolbar(false); });
|
||||
connect(actionStop, &QAction::triggered, [=](){
|
||||
actionContinue->setVisible(true);
|
||||
actionStart->setVisible(true);
|
||||
actionStartEmul->setVisible(true);
|
||||
actionAttach->setVisible(true);
|
||||
actionContinueUntilMain->setVisible(true);
|
||||
actionContinueUntilCall->setVisible(true);
|
||||
this->colorToolbar(false);
|
||||
});
|
||||
connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug);
|
||||
connect(actionStart, &QAction::triggered, Core(), &CutterCore::startDebug);
|
||||
connect(actionStart, &QAction::triggered, [=](){ this->colorToolbar(true); });
|
||||
connect(actionStart, &QAction::triggered, [=](){
|
||||
this->colorToolbar(true);
|
||||
actionAttach->setVisible(false);
|
||||
actionStartEmul->setVisible(false);
|
||||
});
|
||||
connect(actionAttach, &QAction::triggered, this, &DebugToolbar::attachProcessDialog);
|
||||
connect(actionStartEmul, &QAction::triggered, Core(), &CutterCore::startEmulation);
|
||||
connect(actionStartEmul, &QAction::triggered, [=](){
|
||||
actionContinue->setVisible(false);
|
||||
actionStart->setVisible(false);
|
||||
actionAttach->setVisible(false);
|
||||
actionContinueUntilMain->setVisible(false);
|
||||
actionContinueUntilCall->setVisible(false);
|
||||
continueUntilButton->setDefaultAction(actionContinueUntilSyscall);
|
||||
this->colorToolbar(true);
|
||||
});
|
||||
connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug);
|
||||
connect(actionContinue, &QAction::triggered, Core(), &CutterCore::continueDebug);
|
||||
connect(actionContinueUntilMain, &QAction::triggered, this, &DebugToolbar::continueUntilMain);
|
||||
@ -71,4 +108,24 @@ void DebugToolbar::colorToolbar(bool p)
|
||||
} else {
|
||||
this->setStyleSheet("");
|
||||
}
|
||||
}
|
||||
|
||||
void DebugToolbar::attachProcessDialog()
|
||||
{
|
||||
AttachProcDialog *dialog = new AttachProcDialog(this);
|
||||
|
||||
if (dialog->exec()) {
|
||||
int pid = dialog->getPID();
|
||||
attachProcess(pid);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugToolbar::attachProcess(int pid)
|
||||
{
|
||||
// hide unwanted buttons
|
||||
this->colorToolbar(true);
|
||||
this->actionStart->setVisible(false);
|
||||
this->actionStartEmul->setVisible(false);
|
||||
// attach
|
||||
Core()->attachDebug(pid);
|
||||
}
|
@ -14,9 +14,12 @@ public:
|
||||
|
||||
private:
|
||||
MainWindow *main;
|
||||
QAction *actionStart;
|
||||
QAction *actionStartEmul;
|
||||
|
||||
private slots:
|
||||
void continueUntilMain();
|
||||
void colorToolbar(bool p);
|
||||
|
||||
void attachProcessDialog();
|
||||
void attachProcess(int pid);
|
||||
};
|
@ -36,7 +36,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
|
||||
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshView()));
|
||||
connect(Core(), SIGNAL(graphOptionsChanged()), this, SLOT(refreshView()));
|
||||
connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshView()));
|
||||
connect(Core(), SIGNAL(deletedAllBreakpoints()), this, SLOT(refreshView()));
|
||||
connect(Core(), SIGNAL(refreshCodeViews()), this, SLOT(refreshView()));
|
||||
|
||||
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
|
||||
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot()));
|
||||
|
@ -119,7 +119,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
|
||||
refreshDisasm();
|
||||
}
|
||||
});
|
||||
connect(Core(), SIGNAL(deletedAllBreakpoints()), this, SLOT(refreshDisasm()));
|
||||
connect(Core(), SIGNAL(refreshCodeViews()), this, SLOT(refreshDisasm()));
|
||||
|
||||
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot()));
|
||||
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
|
||||
|
Loading…
Reference in New Issue
Block a user