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:
fcasal 2018-07-31 18:16:05 +01:00 committed by xarkes
parent 08245a8694
commit cb173aa616
10 changed files with 385 additions and 143 deletions

View File

@ -884,9 +884,8 @@ void CutterCore::startDebug()
if (!currentlyDebugging) { if (!currentlyDebugging) {
offsetPriorDebugging = getOffset(); offsetPriorDebugging = getOffset();
} }
// FIXME: we do a 'ds' here since otherwise the continue until commands // FIXME: we do a 'dr' here since otherwise the process continues
// sometimes do not work in r2. cmd("ood; dr");
cmd("ood; ds");
emit registersChanged(); emit registersChanged();
if (!currentlyDebugging) { if (!currentlyDebugging) {
setConfig("asm.flags", false); setConfig("asm.flags", false);
@ -934,6 +933,8 @@ void CutterCore::attachDebug(int pid)
// prevent register flags from appearing during debug/emul // prevent register flags from appearing during debug/emul
setConfig("asm.flags", false); setConfig("asm.flags", false);
currentlyDebugging = true; currentlyDebugging = true;
currentlyOpenFile = getConfig("file.path");
currentlyAttachedToPID = pid;
emit flagsChanged(); emit flagsChanged();
emit changeDebugView(); emit changeDebugView();
} }
@ -945,9 +946,11 @@ void CutterCore::stopDebug()
if (currentlyEmulating) { if (currentlyEmulating) {
cmd("aeim-; aei-; wcr; .ar-"); cmd("aeim-; aei-; wcr; .ar-");
currentlyEmulating = false; currentlyEmulating = false;
} else if (currentlyAttachedToPID != -1) {
cmd(QString("dp- %1; o %2; .ar-").arg(QString::number(currentlyAttachedToPID), currentlyOpenFile));
currentlyAttachedToPID = -1;
} else { } else {
// we do a ds since otherwise the process does not die. cmd("dk 9; oo; .ar-");
cmd("dk 9; ds; oo; .ar-");
} }
seek(offsetPriorDebugging); seek(offsetPriorDebugging);
setConfig("asm.flags", true); setConfig("asm.flags", true);

View File

@ -528,6 +528,8 @@ public:
void setDebugPlugin(QString plugin); void setDebugPlugin(QString plugin);
bool currentlyDebugging = false; bool currentlyDebugging = false;
bool currentlyEmulating = false; bool currentlyEmulating = false;
int currentlyAttachedToPID = -1;
QString currentlyOpenFile;
QString getDecompiledCodePDC(RVA addr); QString getDecompiledCodePDC(RVA addr);
bool getR2DecAvailable(); bool getR2DecAvailable();

View File

@ -5,15 +5,29 @@
#include "utils/Helpers.h" #include "utils/Helpers.h"
ProcessModel::ProcessModel(QList<ProcessDescription> *processes, QObject *parent) #include <QScrollBar>
: QAbstractListModel(parent),
processes(processes) // ------------
// ProcessModel
// ------------
ProcessModel::ProcessModel(QObject *parent)
: QAbstractListModel(parent)
{ {
updateData();
}
void ProcessModel::updateData()
{
beginResetModel();
processes = Core()->getAllProcesses();
endResetModel();
} }
int ProcessModel::rowCount(const QModelIndex &) const int ProcessModel::rowCount(const QModelIndex &) const
{ {
return processes->count(); return processes.count();
} }
int ProcessModel::columnCount(const QModelIndex &) const 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 QVariant ProcessModel::data(const QModelIndex &index, int role) const
{ {
if (index.row() >= processes->count()) if (index.row() >= processes.count())
return QVariant(); return QVariant();
const ProcessDescription &proc = processes->at(index.row()); const ProcessDescription &proc = processes.at(index.row());
switch (role) { switch (role) {
case Qt::DisplayRole: 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) ProcessProxyModel::ProcessProxyModel(ProcessModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent) : QSortFilterProxyModel(parent)
{ {
@ -100,22 +165,12 @@ bool ProcessProxyModel::lessThan(const QModelIndex &left, const QModelIndex &rig
ProcessDescription rightProc = right.data( ProcessDescription rightProc = right.data(
ProcessModel::ProcDescriptionRole).value<ProcessDescription>(); ProcessModel::ProcDescriptionRole).value<ProcessDescription>();
switch (left.column()) { return ProcessModel::lessThan(leftProc, rightProc, 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::AttachProcDialog(QWidget *parent) : AttachProcDialog::AttachProcDialog(QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::AttachProcDialog) ui(new Ui::AttachProcDialog)
@ -123,22 +178,97 @@ AttachProcDialog::AttachProcDialog(QWidget *parent) :
ui->setupUi(this); ui->setupUi(this);
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
processes = Core()->getAllProcesses(); processModel = new ProcessModel(this);
processModel = new ProcessModel(&processes, this);
processProxyModel = new ProcessProxyModel(processModel, this); processProxyModel = new ProcessProxyModel(processModel, this);
ui->procTreeView->setModel(processProxyModel); processBeingAnalyzedProxyModel = new ProcessBeingAnalysedProxyModel(processModel, this);
ui->procTreeView->sortByColumn(ProcessModel::PidColumn, Qt::AscendingOrder);
connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), processProxyModel, // View of all processes
SLOT(setFilterWildcard(const QString &))); auto allView = ui->allProcView;
qhelpers::setVerticalScrollMode(ui->procTreeView); 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 // focus on filter line
ui->filterLineEdit->setFocus(); ui->filterLineEdit->setFocus();
// Event filter for capturing Ctrl/Cmd+Return connect(ui->filterLineEdit, SIGNAL(textChanged(const QString &)), processProxyModel,
ui->filterLineEdit->installEventFilter(this); 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() void AttachProcDialog::on_buttonBox_accepted()
{ {
@ -149,23 +279,16 @@ void AttachProcDialog::on_buttonBox_rejected()
close(); 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) bool AttachProcDialog::eventFilter(QObject *obj, QEvent *event)
{ {
Q_UNUSED(obj); if (event->type() == QEvent::FocusIn) {
if (event -> type() == QEvent::KeyPress) { if (obj == ui->allProcView) {
QKeyEvent *keyEvent = static_cast <QKeyEvent *> (event); ui->procBeingAnalyzedView->selectionModel()->clearSelection();
wasAllProcViewLastPressed = true;
// Confirm comment by pressing Ctrl/Cmd+Return return true;
if ((keyEvent -> modifiers() & Qt::ControlModifier) && } else if (obj == ui->procBeingAnalyzedView) {
((keyEvent -> key() == Qt::Key_Enter) || (keyEvent -> key() == Qt::Key_Return))) { ui->allProcView->selectionModel()->clearSelection();
this->accept(); wasAllProcViewLastPressed = false;
return true; return true;
} }
} }
@ -173,8 +296,37 @@ bool AttachProcDialog::eventFilter(QObject *obj, QEvent *event)
return false; 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(); accept();
} }

View File

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QTimer>
namespace Ui { namespace Ui {
class AttachProcDialog; class AttachProcDialog;
@ -20,22 +21,23 @@ class ProcessModel: public QAbstractListModel
Q_OBJECT Q_OBJECT
private: private:
QList<ProcessDescription> *processes; QList<ProcessDescription> processes;
public: public:
enum Column { PidColumn = 0, UidColumn, StatusColumn, PathColumn, ColumnCount }; enum Column { PidColumn = 0, UidColumn, StatusColumn, PathColumn, ColumnCount };
enum Role { ProcDescriptionRole = Qt::UserRole }; enum Role { ProcDescriptionRole = Qt::UserRole };
ProcessModel(QList<ProcessDescription> *processes, QObject *parent = 0); ProcessModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const; QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) 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(); public slots:
void endReloadProcess(); 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 class AttachProcDialog : public QDialog
{ {
@ -67,16 +86,21 @@ public:
private slots: private slots:
void on_buttonBox_accepted(); void on_buttonBox_accepted();
void on_buttonBox_rejected(); 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: private:
std::unique_ptr<Ui::AttachProcDialog> ui; std::unique_ptr<Ui::AttachProcDialog> ui;
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
ProcessModel *processModel; ProcessModel *processModel;
ProcessProxyModel *processProxyModel; 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;
}; };

View File

@ -30,42 +30,115 @@
<number>2</number> <number>2</number>
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QTreeView" name="procTreeView"> <widget class="QGroupBox" name="groupBox_2">
<property name="styleSheet"> <property name="maximumSize">
<string notr="true">QTreeView::item <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-top: 1px;
padding-bottom: 1px; padding-bottom: 1px;
}</string> }</string>
</property> </property>
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::NoFrame</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="lineWidth"> <property name="lineWidth">
<number>0</number> <number>0</number>
</property> </property>
<property name="indentation"> <property name="indentation">
<number>8</number> <number>8</number>
</property> </property>
<property name="sortingEnabled"> <property name="sortingEnabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </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> </item>
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="filterLineEdit"> <widget class="QLineEdit" name="filterLineEdit">
<property name="placeholderText"> <property name="placeholderText">
<string>Quick Filter</string> <string>Quick Filter</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation"> <property name="orientation">

View File

@ -13,11 +13,11 @@ BacktraceWidget::BacktraceWidget(MainWindow *main, QAction *action) :
// setup backtrace model // setup backtrace model
QString PC = Core()->getRegisterName("PC"); QString PC = Core()->getRegisterName("PC");
QString SP = Core()->getRegisterName("SP"); 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(1, new QStandardItem(SP));
modelBacktrace->setHorizontalHeaderItem(2, new QStandardItem(tr("Frame Size"))); modelBacktrace->setHorizontalHeaderItem(2, new QStandardItem(PC));
modelBacktrace->setHorizontalHeaderItem(3, new QStandardItem(tr("Func Name"))); modelBacktrace->setHorizontalHeaderItem(3, new QStandardItem(tr("Description")));
modelBacktrace->setHorizontalHeaderItem(4, new QStandardItem(tr("Description"))); modelBacktrace->setHorizontalHeaderItem(4, new QStandardItem(tr("Frame Size")));
viewBacktrace->setFont(Config()->getFont()); viewBacktrace->setFont(Config()->getFont());
viewBacktrace->setModel(modelBacktrace); viewBacktrace->setModel(modelBacktrace);
ui->verticalLayout->addWidget(viewBacktrace); ui->verticalLayout->addWidget(viewBacktrace);
@ -42,21 +42,21 @@ void BacktraceWidget::setBacktraceGrid()
QJsonObject backtraceItem = value.toObject(); QJsonObject backtraceItem = value.toObject();
QString progCounter = RAddressString(backtraceItem["pc"].toVariant().toULongLong()); QString progCounter = RAddressString(backtraceItem["pc"].toVariant().toULongLong());
QString stackPointer = RAddressString(backtraceItem["sp"].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 funcName = backtraceItem["fname"].toString();
QString desc = backtraceItem["desc"].toString(); QString desc = backtraceItem["desc"].toString();
QStandardItem *rowPC = new QStandardItem(progCounter); QStandardItem *rowPC = new QStandardItem(progCounter);
QStandardItem *rowSP = new QStandardItem(stackPointer); QStandardItem *rowSP = new QStandardItem(stackPointer);
QStandardItem *rowFrameSize = new QStandardItem(frameSize); QStandardItem *rowFrameSize = new QStandardItem(QString::number(frameSize));
QStandardItem *rowFuncName = new QStandardItem(funcName); QStandardItem *rowFuncName = new QStandardItem(funcName);
QStandardItem *rowDesc = new QStandardItem(desc); QStandardItem *rowDesc = new QStandardItem(desc);
modelBacktrace->setItem(i, 0, rowPC); modelBacktrace->setItem(i, 0, rowFuncName);
modelBacktrace->setItem(i, 1, rowSP); modelBacktrace->setItem(i, 1, rowSP);
modelBacktrace->setItem(i, 2, rowFrameSize); modelBacktrace->setItem(i, 2, rowPC);
modelBacktrace->setItem(i, 3, rowFuncName); modelBacktrace->setItem(i, 3, rowDesc);
modelBacktrace->setItem(i, 4, rowDesc); modelBacktrace->setItem(i, 4, rowFrameSize);
i++; i++;
} }
viewBacktrace->setModel(modelBacktrace); viewBacktrace->setModel(modelBacktrace);

View File

@ -29,7 +29,7 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
actionStart->setShortcut(QKeySequence(Qt::Key_F9)); actionStart->setShortcut(QKeySequence(Qt::Key_F9));
actionStartEmul = new QAction(startEmulIcon, tr("Start emulation"), parent); actionStartEmul = new QAction(startEmulIcon, tr("Start emulation"), parent);
actionAttach = new QAction(startAttachIcon, tr("Attach to process"), 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 = new QAction(continueIcon, tr("Continue"), parent);
actionContinue->setShortcut(QKeySequence(Qt::Key_F5)); actionContinue->setShortcut(QKeySequence(Qt::Key_F5));
actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent); actionContinueUntilMain = new QAction(continueUntilMainIcon, tr("Continue until main"), parent);
@ -82,18 +82,20 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
actionContinueUntilMain->setVisible(true); actionContinueUntilMain->setVisible(true);
actionStepOut->setVisible(true); actionStepOut->setVisible(true);
this->colorToolbar(false); this->colorToolbar(false);
actionStop->setText("Stop debug");
colorToolbar(false);
}); });
connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug); connect(actionStep, &QAction::triggered, Core(), &CutterCore::stepDebug);
connect(actionStart, &QAction::triggered, [ = ]() { connect(actionStart, &QAction::triggered, [=]() {
QString filename = Core()->getConfig("file.lastpath"); QString filename = Core()->getConfig("file.path").split(" ").first();
QFileInfo info(filename); QFileInfo info(filename);
if (!info.isExecutable()) { if (!Core()->currentlyDebugging && !info.isExecutable()) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setText(QString("File '%1' does not have executable permissions.").arg(filename)); msgBox.setText(QString("File '%1' does not have executable permissions.").arg(filename));
msgBox.exec(); msgBox.exec();
return; return;
} }
this->colorToolbar(true); colorToolbar(true);
actionAttach->setVisible(false); actionAttach->setVisible(false);
actionStartEmul->setVisible(false); actionStartEmul->setVisible(false);
Core()->startDebug(); Core()->startDebug();
@ -107,7 +109,8 @@ DebugToolbar::DebugToolbar(MainWindow *main, QWidget *parent) :
actionContinueUntilMain->setVisible(false); actionContinueUntilMain->setVisible(false);
actionStepOut->setVisible(false); actionStepOut->setVisible(false);
continueUntilButton->setDefaultAction(actionContinueUntilSyscall); continueUntilButton->setDefaultAction(actionContinueUntilSyscall);
this->colorToolbar(true); actionStop->setText("Stop emulation");
colorToolbar(true);
}); });
connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug); connect(actionStepOver, &QAction::triggered, Core(), &CutterCore::stepOverDebug);
connect(actionStepOut, &QAction::triggered, Core(), &CutterCore::stepOutDebug); connect(actionStepOut, &QAction::triggered, Core(), &CutterCore::stepOutDebug);
@ -125,28 +128,40 @@ void DebugToolbar::continueUntilMain()
void DebugToolbar::colorToolbar(bool p) void DebugToolbar::colorToolbar(bool p)
{ {
if (p) { if (p) {
this->setStyleSheet("QToolBar {background: green;}"); setStyleSheet("QToolBar {background: green;}");
} else { } else {
this->setStyleSheet(""); setStyleSheet("");
} }
} }
void DebugToolbar::attachProcessDialog() void DebugToolbar::attachProcessDialog()
{ {
AttachProcDialog *dialog = new AttachProcDialog(this); AttachProcDialog *dialog = new AttachProcDialog(this);
bool success = false;
if (dialog->exec()) { while (!success) {
int pid = dialog->getPID(); success = true;
attachProcess(pid); 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) void DebugToolbar::attachProcess(int pid)
{ {
// hide unwanted buttons // hide unwanted buttons
this->colorToolbar(true); colorToolbar(true);
this->actionStart->setVisible(false); actionStart->setVisible(false);
this->actionStartEmul->setVisible(false); actionStartEmul->setVisible(false);
actionStop->setText("Detach from process");
// attach // attach
Core()->attachDebug(pid); Core()->attachDebug(pid);
} }

View File

@ -21,6 +21,7 @@ public:
QAction *actionStep; QAction *actionStep;
QAction *actionStepOver; QAction *actionStepOver;
QAction *actionStepOut; QAction *actionStepOut;
QAction *actionStop;
private: private:
MainWindow *main; MainWindow *main;

View File

@ -3,7 +3,6 @@
#include "utils/JsonModel.h" #include "utils/JsonModel.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "QPushButton"
RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) : RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action), CutterDockWidget(main, action),
@ -12,12 +11,9 @@ RegistersWidget::RegistersWidget(MainWindow *main, QAction *action) :
ui->setupUi(this); ui->setupUi(this);
// setup register layout // setup register layout
registerLayout->setVerticalSpacing(0);
ui->verticalLayout->addLayout(registerLayout); 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::refreshAll, this, &RegistersWidget::updateContents);
connect(Core(), &CutterCore::registersChanged, this, &RegistersWidget::updateContents); connect(Core(), &CutterCore::registersChanged, this, &RegistersWidget::updateContents);
} }
@ -29,28 +25,6 @@ void RegistersWidget::updateContents()
setRegisterGrid(); 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() void RegistersWidget::setRegisterGrid()
{ {
int i = 0; int i = 0;

View File

@ -26,12 +26,10 @@ public:
private slots: private slots:
void updateContents(); void updateContents();
void setRegisterGrid(); void setRegisterGrid();
void handleButton();
private: private:
std::unique_ptr<Ui::RegistersWidget> ui; std::unique_ptr<Ui::RegistersWidget> ui;
QGridLayout *registerLayout = new QGridLayout; QGridLayout *registerLayout = new QGridLayout;
int numCols = 2; int numCols = 2;
int registerLen = 0; int registerLen = 0;
QPushButton *buttonSetRegisters;
}; };