mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-20 03:46:11 +00:00
Attach update (#603)
* Handle process detaching * List procs wth current filename in separate table; * Refresh proc list every second * Fixed restarting debug executable check * Update r2 * Added option to break esil execution on invalid instructions (#597) * Added continue until call in esil * Remove set registers button * Reordered backtrace widget columns
This commit is contained in:
parent
08245a8694
commit
cb173aa616
@ -884,9 +884,8 @@ void CutterCore::startDebug()
|
||||
if (!currentlyDebugging) {
|
||||
offsetPriorDebugging = getOffset();
|
||||
}
|
||||
// FIXME: we do a 'ds' here since otherwise the continue until commands
|
||||
// sometimes do not work in r2.
|
||||
cmd("ood; ds");
|
||||
// FIXME: we do a 'dr' here since otherwise the process continues
|
||||
cmd("ood; dr");
|
||||
emit registersChanged();
|
||||
if (!currentlyDebugging) {
|
||||
setConfig("asm.flags", false);
|
||||
@ -934,6 +933,8 @@ void CutterCore::attachDebug(int pid)
|
||||
// prevent register flags from appearing during debug/emul
|
||||
setConfig("asm.flags", false);
|
||||
currentlyDebugging = true;
|
||||
currentlyOpenFile = getConfig("file.path");
|
||||
currentlyAttachedToPID = pid;
|
||||
emit flagsChanged();
|
||||
emit changeDebugView();
|
||||
}
|
||||
@ -945,9 +946,11 @@ void CutterCore::stopDebug()
|
||||
if (currentlyEmulating) {
|
||||
cmd("aeim-; aei-; wcr; .ar-");
|
||||
currentlyEmulating = false;
|
||||
} else if (currentlyAttachedToPID != -1) {
|
||||
cmd(QString("dp- %1; o %2; .ar-").arg(QString::number(currentlyAttachedToPID), currentlyOpenFile));
|
||||
currentlyAttachedToPID = -1;
|
||||
} else {
|
||||
// we do a ds since otherwise the process does not die.
|
||||
cmd("dk 9; ds; oo; .ar-");
|
||||
cmd("dk 9; oo; .ar-");
|
||||
}
|
||||
seek(offsetPriorDebugging);
|
||||
setConfig("asm.flags", true);
|
||||
|
@ -528,6 +528,8 @@ public:
|
||||
void setDebugPlugin(QString plugin);
|
||||
bool currentlyDebugging = false;
|
||||
bool currentlyEmulating = false;
|
||||
int currentlyAttachedToPID = -1;
|
||||
QString currentlyOpenFile;
|
||||
|
||||
QString getDecompiledCodePDC(RVA addr);
|
||||
bool getR2DecAvailable();
|
||||
|
@ -5,15 +5,29 @@
|
||||
|
||||
#include "utils/Helpers.h"
|
||||
|
||||
ProcessModel::ProcessModel(QList<ProcessDescription> *processes, QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
processes(processes)
|
||||
#include <QScrollBar>
|
||||
|
||||
// ------------
|
||||
// ProcessModel
|
||||
// ------------
|
||||
ProcessModel::ProcessModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
updateData();
|
||||
}
|
||||
|
||||
void ProcessModel::updateData()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
processes = Core()->getAllProcesses();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int ProcessModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return processes->count();
|
||||
return processes.count();
|
||||
}
|
||||
|
||||
int ProcessModel::columnCount(const QModelIndex &) const
|
||||
@ -23,10 +37,10 @@ int ProcessModel::columnCount(const QModelIndex &) const
|
||||
|
||||
QVariant ProcessModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.row() >= processes->count())
|
||||
if (index.row() >= processes.count())
|
||||
return QVariant();
|
||||
|
||||
const ProcessDescription &proc = processes->at(index.row());
|
||||
const ProcessDescription &proc = processes.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
@ -70,16 +84,67 @@ QVariant ProcessModel::headerData(int section, Qt::Orientation, int role) const
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessModel::beginReloadProcess()
|
||||
bool ProcessModel::lessThan(const ProcessDescription &leftProc, const ProcessDescription &rightProc,
|
||||
int column)
|
||||
{
|
||||
beginResetModel();
|
||||
switch (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;
|
||||
}
|
||||
|
||||
void ProcessModel::endReloadProcess()
|
||||
// ------------------------------
|
||||
// ProcessBeingAnalysedProxyModel
|
||||
// ------------------------------
|
||||
ProcessBeingAnalysedProxyModel::ProcessBeingAnalysedProxyModel(ProcessModel *sourceModel,
|
||||
QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
endResetModel();
|
||||
setSourceModel(sourceModel);
|
||||
|
||||
// @SEE: Should there be a getFilename() in Core()? Not the first time I use this
|
||||
processBeingAnalysedFilename = processPathToFilename(Core()->getConfig("file.path"));
|
||||
}
|
||||
|
||||
QString ProcessBeingAnalysedProxyModel::processPathToFilename(const QString &path) const
|
||||
{
|
||||
// removes the arguments and gets filename from the process path
|
||||
return path.split(" ").first().split("/").last();
|
||||
}
|
||||
|
||||
bool ProcessBeingAnalysedProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
{
|
||||
QModelIndex index = sourceModel()->index(row, 0, parent);
|
||||
ProcessDescription item = index.data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
|
||||
QString procFilename = processPathToFilename(item.path);
|
||||
return procFilename == processBeingAnalysedFilename;
|
||||
}
|
||||
|
||||
bool ProcessBeingAnalysedProxyModel::lessThan(const QModelIndex &left,
|
||||
const QModelIndex &right) const
|
||||
{
|
||||
ProcessDescription leftProc = left.data(
|
||||
ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
ProcessDescription rightProc = right.data(
|
||||
ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
|
||||
return ProcessModel::lessThan(leftProc, rightProc, left.column());
|
||||
}
|
||||
|
||||
// -----------------
|
||||
// ProcessProxyModel
|
||||
// -----------------
|
||||
ProcessProxyModel::ProcessProxyModel(ProcessModel *sourceModel, QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
@ -100,22 +165,12 @@ bool ProcessProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
|
||||
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;
|
||||
return ProcessModel::lessThan(leftProc, rightProc, left.column());
|
||||
}
|
||||
|
||||
// ----------------
|
||||
// AttachProcDialog
|
||||
// ----------------
|
||||
AttachProcDialog::AttachProcDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AttachProcDialog)
|
||||
@ -123,22 +178,97 @@ AttachProcDialog::AttachProcDialog(QWidget *parent) :
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
||||
processes = Core()->getAllProcesses();
|
||||
processModel = new ProcessModel(&processes, this);
|
||||
processModel = new ProcessModel(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);
|
||||
processBeingAnalyzedProxyModel = new ProcessBeingAnalysedProxyModel(processModel, this);
|
||||
|
||||
// View of all processes
|
||||
auto allView = ui->allProcView;
|
||||
allView->setModel(processProxyModel);
|
||||
allView->sortByColumn(ProcessModel::PidColumn, Qt::DescendingOrder);
|
||||
|
||||
// View of the processes with the same name as the one being analyzed
|
||||
auto smallView = ui->procBeingAnalyzedView;
|
||||
smallView->setModel(processBeingAnalyzedProxyModel);
|
||||
smallView->setCurrentIndex(smallView->model()->index(0, 0));
|
||||
|
||||
// To get the 'FocusIn' events
|
||||
allView->installEventFilter(this);
|
||||
smallView->installEventFilter(this);
|
||||
|
||||
// focus on filter line
|
||||
ui->filterLineEdit->setFocus();
|
||||
// Event filter for capturing Ctrl/Cmd+Return
|
||||
ui->filterLineEdit->installEventFilter(this);
|
||||
connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), processProxyModel,
|
||||
SLOT(setFilterWildcard(const QString &)));
|
||||
|
||||
// Update the processes every 'updateIntervalMs' seconds
|
||||
timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(updateModelData()));
|
||||
timer->start(updateIntervalMs);
|
||||
}
|
||||
|
||||
AttachProcDialog::~AttachProcDialog() {}
|
||||
AttachProcDialog::~AttachProcDialog()
|
||||
{
|
||||
timer->stop();
|
||||
delete timer;
|
||||
delete processBeingAnalyzedProxyModel;
|
||||
delete processProxyModel;
|
||||
delete processModel;
|
||||
}
|
||||
|
||||
void AttachProcDialog::updateModelData()
|
||||
{
|
||||
auto allView = ui->allProcView;
|
||||
auto smallView = ui->procBeingAnalyzedView;
|
||||
|
||||
// Save the old selection and scroll position so that we can update and
|
||||
// model and then restore it.
|
||||
bool allViewHadSelection = allView->selectionModel()->hasSelection();
|
||||
bool smallViewHadSelection = smallView->selectionModel()->hasSelection();
|
||||
int allViewPrevScrollPos = 0;
|
||||
int smallViewPrevScrollPos = 0;
|
||||
int allViewPrevPID = 0;
|
||||
int smallViewPrevPID = 0;
|
||||
|
||||
if (allViewHadSelection) {
|
||||
allViewPrevScrollPos = allView->verticalScrollBar()->value();
|
||||
allViewPrevPID = allView->selectionModel()->currentIndex().data(
|
||||
ProcessModel::ProcDescriptionRole).value<ProcessDescription>().pid;
|
||||
}
|
||||
if (smallViewHadSelection) {
|
||||
smallViewPrevScrollPos = smallView->verticalScrollBar()->value();
|
||||
smallViewPrevPID = smallView->selectionModel()->currentIndex().data(
|
||||
ProcessModel::ProcDescriptionRole).value<ProcessDescription>().pid;
|
||||
}
|
||||
|
||||
// Let the model update
|
||||
processModel->updateData();
|
||||
|
||||
// Restore the selection and scroll position
|
||||
if (allViewHadSelection) {
|
||||
QModelIndexList idx = allView->model()->match(
|
||||
allView->model()->index(0, 0), Qt::DisplayRole, QVariant::fromValue(allViewPrevPID));
|
||||
if (!idx.isEmpty()) {
|
||||
allView->setCurrentIndex(idx.first());
|
||||
allView->verticalScrollBar()->setValue(allViewPrevScrollPos);
|
||||
}
|
||||
}
|
||||
if (smallViewHadSelection) {
|
||||
QModelIndexList idx = smallView->model()->match(
|
||||
smallView->model()->index(0, 0), Qt::DisplayRole, QVariant::fromValue(smallViewPrevPID));
|
||||
|
||||
if (!idx.isEmpty()) {
|
||||
smallView->setCurrentIndex(idx.first());
|
||||
smallView->verticalScrollBar()->setValue(smallViewPrevScrollPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Init selection if nothing was ever selected yet, and a new process with the same name
|
||||
// as the one being analysed was launched.
|
||||
if (!allView->selectionModel()->hasSelection() && !smallView->selectionModel()->hasSelection()) {
|
||||
smallView->setCurrentIndex(smallView->model()->index(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void AttachProcDialog::on_buttonBox_accepted()
|
||||
{
|
||||
@ -149,23 +279,16 @@ 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();
|
||||
if (event->type() == QEvent::FocusIn) {
|
||||
if (obj == ui->allProcView) {
|
||||
ui->procBeingAnalyzedView->selectionModel()->clearSelection();
|
||||
wasAllProcViewLastPressed = true;
|
||||
return true;
|
||||
} else if (obj == ui->procBeingAnalyzedView) {
|
||||
ui->allProcView->selectionModel()->clearSelection();
|
||||
wasAllProcViewLastPressed = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -173,8 +296,37 @@ bool AttachProcDialog::eventFilter(QObject *obj, QEvent *event)
|
||||
return false;
|
||||
}
|
||||
|
||||
void AttachProcDialog::on_procTreeView_doubleClicked(const QModelIndex &index)
|
||||
int AttachProcDialog::getPID()
|
||||
{
|
||||
ProcessDescription proc = index.data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
|
||||
int pid;
|
||||
|
||||
// Here we need to know which table was selected last to get the proper PID
|
||||
if (wasAllProcViewLastPressed && ui->allProcView->selectionModel()->hasSelection()) {
|
||||
pid = ui->allProcView->selectionModel()->currentIndex().
|
||||
data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>().pid;
|
||||
} else if (!wasAllProcViewLastPressed
|
||||
&& ui->procBeingAnalyzedView->selectionModel()->hasSelection()) {
|
||||
pid = ui->procBeingAnalyzedView->selectionModel()->currentIndex().
|
||||
data(ProcessModel::ProcDescriptionRole).value<ProcessDescription>().pid;
|
||||
} else {
|
||||
// Error attaching. No process selected! Happens when you press ENTER but
|
||||
// there was no process with the same name as the one being analyzed.
|
||||
pid = -1;
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
void AttachProcDialog::on_allProcView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void AttachProcDialog::on_procBeingAnalyzedView_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
|
||||
accept();
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Ui {
|
||||
class AttachProcDialog;
|
||||
@ -20,22 +21,23 @@ class ProcessModel: public QAbstractListModel
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QList<ProcessDescription> *processes;
|
||||
QList<ProcessDescription> processes;
|
||||
|
||||
public:
|
||||
enum Column { PidColumn = 0, UidColumn, StatusColumn, PathColumn, ColumnCount };
|
||||
enum Role { ProcDescriptionRole = Qt::UserRole };
|
||||
|
||||
ProcessModel(QList<ProcessDescription> *processes, QObject *parent = 0);
|
||||
ProcessModel(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;
|
||||
static bool lessThan(const ProcessDescription &left, const ProcessDescription &right, int column);
|
||||
|
||||
void beginReloadProcess();
|
||||
void endReloadProcess();
|
||||
public slots:
|
||||
void updateData();
|
||||
};
|
||||
|
||||
|
||||
@ -53,6 +55,23 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class ProcessBeingAnalysedProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ProcessBeingAnalysedProxyModel(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;
|
||||
|
||||
private:
|
||||
QString processBeingAnalysedFilename;
|
||||
QString processPathToFilename(const QString &path) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AttachProcDialog : public QDialog
|
||||
{
|
||||
@ -67,16 +86,21 @@ public:
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_rejected();
|
||||
void on_procTreeView_doubleClicked(const QModelIndex &index);
|
||||
void on_allProcView_doubleClicked(const QModelIndex &index);
|
||||
void on_procBeingAnalyzedView_doubleClicked(const QModelIndex &index);
|
||||
void updateModelData();
|
||||
|
||||
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;
|
||||
ProcessBeingAnalysedProxyModel *processBeingAnalyzedProxyModel;
|
||||
|
||||
// whether the 'small table' or 'table with all procs' was last focused
|
||||
bool wasAllProcViewLastPressed = false;
|
||||
|
||||
QTimer *timer;
|
||||
const int updateIntervalMs = 1000;
|
||||
};
|
||||
|
@ -30,42 +30,115 @@
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeView" name="procTreeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QTreeView::item
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Processes with same name as currently open file:</string>
|
||||
</property>
|
||||
<widget class="QTreeView" name="procBeingAnalyzedView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>30</y>
|
||||
<width>794</width>
|
||||
<height>111</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<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>
|
||||
</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>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>All processes:</string>
|
||||
</property>
|
||||
<widget class="QTreeView" name="allProcView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>50</y>
|
||||
<width>794</width>
|
||||
<height>331</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<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>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="filterLineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Quick Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</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">
|
||||
|
@ -13,11 +13,11 @@ BacktraceWidget::BacktraceWidget(MainWindow *main, QAction *action) :
|
||||
// setup backtrace model
|
||||
QString PC = Core()->getRegisterName("PC");
|
||||
QString SP = Core()->getRegisterName("SP");
|
||||
modelBacktrace->setHorizontalHeaderItem(0, new QStandardItem(PC));
|
||||
modelBacktrace->setHorizontalHeaderItem(0, new QStandardItem(tr("Func Name")));
|
||||
modelBacktrace->setHorizontalHeaderItem(1, new QStandardItem(SP));
|
||||
modelBacktrace->setHorizontalHeaderItem(2, new QStandardItem(tr("Frame Size")));
|
||||
modelBacktrace->setHorizontalHeaderItem(3, new QStandardItem(tr("Func Name")));
|
||||
modelBacktrace->setHorizontalHeaderItem(4, new QStandardItem(tr("Description")));
|
||||
modelBacktrace->setHorizontalHeaderItem(2, new QStandardItem(PC));
|
||||
modelBacktrace->setHorizontalHeaderItem(3, new QStandardItem(tr("Description")));
|
||||
modelBacktrace->setHorizontalHeaderItem(4, new QStandardItem(tr("Frame Size")));
|
||||
viewBacktrace->setFont(Config()->getFont());
|
||||
viewBacktrace->setModel(modelBacktrace);
|
||||
ui->verticalLayout->addWidget(viewBacktrace);
|
||||
@ -42,21 +42,21 @@ void BacktraceWidget::setBacktraceGrid()
|
||||
QJsonObject backtraceItem = value.toObject();
|
||||
QString progCounter = RAddressString(backtraceItem["pc"].toVariant().toULongLong());
|
||||
QString stackPointer = RAddressString(backtraceItem["sp"].toVariant().toULongLong());
|
||||
int frameSize = backtraceItem["frame_size"].toInt();
|
||||
int frameSize = backtraceItem["frame_size"].toVariant().toInt();
|
||||
QString funcName = backtraceItem["fname"].toString();
|
||||
QString desc = backtraceItem["desc"].toString();
|
||||
|
||||
QStandardItem *rowPC = new QStandardItem(progCounter);
|
||||
QStandardItem *rowSP = new QStandardItem(stackPointer);
|
||||
QStandardItem *rowFrameSize = new QStandardItem(frameSize);
|
||||
QStandardItem *rowFrameSize = new QStandardItem(QString::number(frameSize));
|
||||
QStandardItem *rowFuncName = new QStandardItem(funcName);
|
||||
QStandardItem *rowDesc = new QStandardItem(desc);
|
||||
|
||||
modelBacktrace->setItem(i, 0, rowPC);
|
||||
modelBacktrace->setItem(i, 0, rowFuncName);
|
||||
modelBacktrace->setItem(i, 1, rowSP);
|
||||
modelBacktrace->setItem(i, 2, rowFrameSize);
|
||||
modelBacktrace->setItem(i, 3, rowFuncName);
|
||||
modelBacktrace->setItem(i, 4, rowDesc);
|
||||
modelBacktrace->setItem(i, 2, rowPC);
|
||||
modelBacktrace->setItem(i, 3, rowDesc);
|
||||
modelBacktrace->setItem(i, 4, rowFrameSize);
|
||||
i++;
|
||||
}
|
||||
viewBacktrace->setModel(modelBacktrace);
|
||||
|
@ -29,7 +29,7 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
actionStart->setShortcut(QKeySequence(Qt::Key_F9));
|
||||
actionStartEmul = new QAction(startEmulIcon, tr("Start emulation"), parent);
|
||||
actionAttach = new QAction(startAttachIcon, tr("Attach to process"), parent);
|
||||
QAction *actionStop = new QAction(stopIcon, tr("Stop debug"), parent);
|
||||
actionStop = new QAction(stopIcon, tr("Stop debug"), parent);
|
||||
actionContinue = new QAction(continueIcon, tr("Continue"), parent);
|
||||
actionContinue->setShortcut(QKeySequence(Qt::Key_F5));
|
||||
actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent);
|
||||
@ -82,18 +82,20 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
actionContinueUntilMain->setVisible(true);
|
||||
actionStepOut->setVisible(true);
|
||||
this->colorToolbar(false);
|
||||
actionStop->setText("Stop debug");
|
||||
colorToolbar(false);
|
||||
});
|
||||
connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug);
|
||||
connect(actionStart, &QAction::triggered, [ = ]() {
|
||||
QString filename = Core()->getConfig("file.lastpath");
|
||||
connect(actionStart, &QAction::triggered, [=]() {
|
||||
QString filename = Core()->getConfig("file.path").split(" ").first();
|
||||
QFileInfo info(filename);
|
||||
if (!info.isExecutable()) {
|
||||
if (!Core()->currentlyDebugging && !info.isExecutable()) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText(QString("File '%1' does not have executable permissions.").arg(filename));
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
this->colorToolbar(true);
|
||||
colorToolbar(true);
|
||||
actionAttach->setVisible(false);
|
||||
actionStartEmul->setVisible(false);
|
||||
Core()->startDebug();
|
||||
@ -107,7 +109,8 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
|
||||
actionContinueUntilMain->setVisible(false);
|
||||
actionStepOut->setVisible(false);
|
||||
continueUntilButton->setDefaultAction(actionContinueUntilSyscall);
|
||||
this->colorToolbar(true);
|
||||
actionStop->setText("Stop emulation");
|
||||
colorToolbar(true);
|
||||
});
|
||||
connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug);
|
||||
connect(actionStepOut, &QAction::triggered, Core(), &CutterCore::stepOutDebug);
|
||||
@ -125,28 +128,40 @@ void DebugToolbar::continueUntilMain()
|
||||
void DebugToolbar::colorToolbar(bool p)
|
||||
{
|
||||
if (p) {
|
||||
this->setStyleSheet("QToolBar {background: green;}");
|
||||
setStyleSheet("QToolBar {background: green;}");
|
||||
} else {
|
||||
this->setStyleSheet("");
|
||||
setStyleSheet("");
|
||||
}
|
||||
}
|
||||
|
||||
void DebugToolbar::attachProcessDialog()
|
||||
{
|
||||
AttachProcDialog *dialog = new AttachProcDialog(this);
|
||||
|
||||
if (dialog->exec()) {
|
||||
int pid = dialog->getPID();
|
||||
attachProcess(pid);
|
||||
bool success = false;
|
||||
while (!success) {
|
||||
success = true;
|
||||
if (dialog->exec()) {
|
||||
int pid = dialog->getPID();
|
||||
if (pid >= 0) {
|
||||
attachProcess(pid);
|
||||
} else {
|
||||
success = false;
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("Error attaching. No process selected!");
|
||||
msgBox.exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
delete dialog;
|
||||
}
|
||||
|
||||
void DebugToolbar::attachProcess(int pid)
|
||||
{
|
||||
// hide unwanted buttons
|
||||
this->colorToolbar(true);
|
||||
this->actionStart->setVisible(false);
|
||||
this->actionStartEmul->setVisible(false);
|
||||
colorToolbar(true);
|
||||
actionStart->setVisible(false);
|
||||
actionStartEmul->setVisible(false);
|
||||
actionStop->setText("Detach from process");
|
||||
// attach
|
||||
Core()->attachDebug(pid);
|
||||
}
|
@ -21,6 +21,7 @@ public:
|
||||
QAction *actionStep;
|
||||
QAction *actionStepOver;
|
||||
QAction *actionStepOut;
|
||||
QAction *actionStop;
|
||||
|
||||
private:
|
||||
MainWindow *main;
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "utils/JsonModel.h"
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "QPushButton"
|
||||
|
||||
RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) :
|
||||
CutterDockWidget(main, action),
|
||||
@ -12,12 +11,9 @@ RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) :
|
||||
ui->setupUi(this);
|
||||
|
||||
// setup register layout
|
||||
registerLayout->setVerticalSpacing(0);
|
||||
ui->verticalLayout->addLayout(registerLayout);
|
||||
|
||||
buttonSetRegisters = new QPushButton("Set registers", this);
|
||||
connect(buttonSetRegisters, &QPushButton::clicked, this, &RegistersWidget::handleButton);
|
||||
|
||||
ui->verticalLayout->addWidget(buttonSetRegisters);
|
||||
connect(Core(), &CutterCore::refreshAll, this, &RegistersWidget::updateContents);
|
||||
connect(Core(), &CutterCore::registersChanged, this, &RegistersWidget::updateContents);
|
||||
}
|
||||
@ -29,28 +25,6 @@ void RegistersWidget::updateContents()
|
||||
setRegisterGrid();
|
||||
}
|
||||
|
||||
void RegistersWidget::handleButton()
|
||||
{
|
||||
int j = 0;
|
||||
int i = 0;
|
||||
int col = 0;
|
||||
for (j = 0; j < registerLen; j++) {
|
||||
QWidget *regName = registerLayout->itemAtPosition(i, col)->widget();
|
||||
QWidget *regValue = registerLayout->itemAtPosition(i, col + 1)->widget();
|
||||
QLabel *regLabel = qobject_cast<QLabel *>(regName);
|
||||
QLineEdit *regLine = qobject_cast<QLineEdit *>(regValue);
|
||||
QString regNameString = regLabel->text();
|
||||
QString regValueString = regLine->text();
|
||||
Core()->setRegister(regNameString, regValueString);
|
||||
i++;
|
||||
if (i >= registerLen / numCols + 1) {
|
||||
i = 0;
|
||||
col += 2;
|
||||
}
|
||||
}
|
||||
setRegisterGrid();
|
||||
}
|
||||
|
||||
void RegistersWidget::setRegisterGrid()
|
||||
{
|
||||
int i = 0;
|
||||
|
@ -26,12 +26,10 @@ public:
|
||||
private slots:
|
||||
void updateContents();
|
||||
void setRegisterGrid();
|
||||
void handleButton();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::RegistersWidget> ui;
|
||||
QGridLayout *registerLayout = new QGridLayout;
|
||||
int numCols = 2;
|
||||
int registerLen = 0;
|
||||
QPushButton *buttonSetRegisters;
|
||||
};
|
Loading…
Reference in New Issue
Block a user