mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-24 05:45:27 +00:00
Breakpoint editor dialog (#1975)
* Add breakpoint dialog for editing breakpoint properties * Allow editing breakpoint using context menu from breakpointWidget and disassembly menu.
This commit is contained in:
parent
32be76fabc
commit
90c7bfab1e
@ -104,16 +104,18 @@ Graph view shortcuts
|
|||||||
Debug shortcuts
|
Debug shortcuts
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
+-----------------+----------------+
|
+-----------------+------------------------------------------+
|
||||||
| Shortcut | Function |
|
| Shortcut | Function |
|
||||||
+=================+================+
|
+=================+==========================================+
|
||||||
| F9 | Start debug |
|
| F9 | Start debug |
|
||||||
+-----------------+----------------+
|
+-----------------+------------------------------------------+
|
||||||
| F7 | Step into |
|
| F7 | Step into |
|
||||||
+-----------------+----------------+
|
+-----------------+------------------------------------------+
|
||||||
| F8 | Step over |
|
| F8 | Step over |
|
||||||
+-----------------+----------------+
|
+-----------------+------------------------------------------+
|
||||||
| F5 | Continue |
|
| F5 | Continue |
|
||||||
+-----------------+----------------+
|
+-----------------+------------------------------------------+
|
||||||
| F2/(Ctrl/Cmd)+B | Add breakpoint |
|
| F2/(Ctrl/Cmd)+B | Add or Remove breakpoint |
|
||||||
+-----------------+----------------+
|
+-----------------+------------------------------------------+
|
||||||
|
| (Ctrl/Cmd)+F2 | Edit or open Advanced breakpoint dialog |
|
||||||
|
+-----------------+------------------------------------------+
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <QAbstractButton>
|
#include <QAbstractButton>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
static QAbstractItemView::ScrollMode scrollMode()
|
static QAbstractItemView::ScrollMode scrollMode()
|
||||||
{
|
{
|
||||||
@ -257,5 +258,16 @@ qreal devicePixelRatio(const QPaintDevice *p)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void selectIndexByData(QComboBox *widget, QVariant data, int defaultIndex)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < widget->count(); i++) {
|
||||||
|
if (widget->itemData(i) == data) {
|
||||||
|
widget->setCurrentIndex(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
widget->setCurrentIndex(defaultIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
@ -19,6 +19,7 @@ class QTreeView;
|
|||||||
class QAction;
|
class QAction;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
class QPaintDevice;
|
class QPaintDevice;
|
||||||
|
class QComboBox;
|
||||||
|
|
||||||
namespace qhelpers {
|
namespace qhelpers {
|
||||||
QString formatBytecount(const uint64_t bytecount);
|
QString formatBytecount(const uint64_t bytecount);
|
||||||
@ -55,6 +56,13 @@ void setThemeIcons(QList<QPair<void*, QString>> supportedIconsNames, std::functi
|
|||||||
|
|
||||||
void prependQAction(QAction *action, QMenu *menu);
|
void prependQAction(QAction *action, QMenu *menu);
|
||||||
qreal devicePixelRatio(const QPaintDevice *p);
|
qreal devicePixelRatio(const QPaintDevice *p);
|
||||||
|
/**
|
||||||
|
* @brief Select comboBox item by value in Qt::UserRole.
|
||||||
|
* @param comboBox
|
||||||
|
* @param data - value to search in combobox item data
|
||||||
|
* @param defaultIndex - item to select in case no match
|
||||||
|
*/
|
||||||
|
void selectIndexByData(QComboBox *comboBox, QVariant data, int defaultIndex = -1);
|
||||||
|
|
||||||
} // qhelpers
|
} // qhelpers
|
||||||
|
|
||||||
|
@ -104,6 +104,13 @@ namespace RJsonKey {
|
|||||||
|
|
||||||
#undef R_JSON_KEY
|
#undef R_JSON_KEY
|
||||||
|
|
||||||
|
static void updateOwnedCharPtr(char *&variable, const QString &newValue)
|
||||||
|
{
|
||||||
|
auto data = newValue.toUtf8();
|
||||||
|
R_FREE(variable)
|
||||||
|
variable = strdup(data.data());
|
||||||
|
}
|
||||||
|
|
||||||
RCoreLocked::RCoreLocked(CutterCore *core)
|
RCoreLocked::RCoreLocked(CutterCore *core)
|
||||||
: core(core)
|
: core(core)
|
||||||
{
|
{
|
||||||
@ -457,7 +464,7 @@ QStringList CutterCore::autocomplete(const QString &cmd, RLinePromptType promptT
|
|||||||
|
|
||||||
QStringList r;
|
QStringList r;
|
||||||
r.reserve(r_pvector_len(&completion.args));
|
r.reserve(r_pvector_len(&completion.args));
|
||||||
for (size_t i = 0; i< r_pvector_len(&completion.args); i++) {
|
for (size_t i = 0; i < r_pvector_len(&completion.args); i++) {
|
||||||
r.push_back(QString::fromUtf8(reinterpret_cast<const char *>(r_pvector_at(&completion.args, i))));
|
r.push_back(QString::fromUtf8(reinterpret_cast<const char *>(r_pvector_at(&completion.args, i))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1749,6 +1756,73 @@ void CutterCore::addBreakpoint(QString addr)
|
|||||||
emit breakpointsChanged();
|
emit breakpointsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CutterCore::addBreakpoint(const BreakpointDescription &config)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
RBreakpointItem *breakpoint = nullptr;
|
||||||
|
int watchpoint_prot = 0;
|
||||||
|
if (config.hw) {
|
||||||
|
watchpoint_prot = config.permission & ~(R_BP_PROT_EXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto address = config.addr;
|
||||||
|
char *module = nullptr;
|
||||||
|
QByteArray moduleNameData;
|
||||||
|
if (config.type == BreakpointDescription::Named) {
|
||||||
|
address = Core()->math(config.positionExpression);
|
||||||
|
} else if (config.type == BreakpointDescription::Module) {
|
||||||
|
address = 0;
|
||||||
|
moduleNameData = config.positionExpression.toUtf8();
|
||||||
|
module = moduleNameData.data();
|
||||||
|
}
|
||||||
|
breakpoint = r_debug_bp_add(core->dbg, address, (config.hw && watchpoint_prot == 0),
|
||||||
|
watchpoint_prot, watchpoint_prot,
|
||||||
|
module, config.moduleDelta);
|
||||||
|
if (config.type == BreakpointDescription::Named) {
|
||||||
|
updateOwnedCharPtr(breakpoint->expr, config.positionExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.hw) {
|
||||||
|
breakpoint->size = config.size;
|
||||||
|
}
|
||||||
|
if (config.type == BreakpointDescription::Named) {
|
||||||
|
updateOwnedCharPtr(breakpoint->name, config.positionExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!breakpoint) {
|
||||||
|
QMessageBox::critical(nullptr, tr("Breakpoint error"), tr("Failed to create breakpoint"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int index = std::find(core->dbg->bp->bps_idx,
|
||||||
|
core->dbg->bp->bps_idx + core->dbg->bp->bps_idx_count,
|
||||||
|
breakpoint) - core->dbg->bp->bps_idx;
|
||||||
|
|
||||||
|
breakpoint->enabled = config.enabled;
|
||||||
|
if (config.trace) {
|
||||||
|
setBreakpointTrace(index, config.trace);
|
||||||
|
}
|
||||||
|
if (!config.condition.isEmpty()) {
|
||||||
|
updateOwnedCharPtr(breakpoint->cond, config.condition);
|
||||||
|
}
|
||||||
|
if (!config.command.isEmpty()) {
|
||||||
|
updateOwnedCharPtr(breakpoint->data, config.command);
|
||||||
|
}
|
||||||
|
emit instructionChanged(breakpoint->addr);
|
||||||
|
emit breakpointsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterCore::updateBreakpoint(int index, const BreakpointDescription &config)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
if (auto bp = r_bp_get_index(core->dbg->bp, index)) {
|
||||||
|
r_bp_del(core->dbg->bp, bp->addr);
|
||||||
|
}
|
||||||
|
// Delete by index currently buggy,
|
||||||
|
// required for breakpoints with non address based position
|
||||||
|
//r_bp_del_index(core->dbg->bp, index);
|
||||||
|
addBreakpoint(config);
|
||||||
|
}
|
||||||
|
|
||||||
void CutterCore::delBreakpoint(RVA addr)
|
void CutterCore::delBreakpoint(RVA addr)
|
||||||
{
|
{
|
||||||
cmd("db- " + RAddressString(addr));
|
cmd("db- " + RAddressString(addr));
|
||||||
@ -1785,24 +1859,52 @@ void CutterCore::setBreakpointTrace(int index, bool enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BreakpointDescription breakpointDescriptionFromR2(int index, r_bp_item_t *bpi)
|
||||||
|
{
|
||||||
|
BreakpointDescription bp;
|
||||||
|
bp.addr = bpi->addr;
|
||||||
|
bp.index = index;
|
||||||
|
bp.size = bpi->size;
|
||||||
|
if (bpi->expr) {
|
||||||
|
bp.positionExpression = bpi->expr;
|
||||||
|
bp.type = BreakpointDescription::Named;
|
||||||
|
}
|
||||||
|
bp.name = bpi->name;
|
||||||
|
bp.permission = bpi->perm;
|
||||||
|
bp.command = bpi->data;
|
||||||
|
bp.condition = bpi->cond;
|
||||||
|
bp.hw = bpi->hw;
|
||||||
|
bp.trace = bpi->trace;
|
||||||
|
bp.enabled = bpi->enabled;
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CutterCore::breakpointIndexAt(RVA addr)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
return r_bp_get_index_at(core->dbg->bp, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
BreakpointDescription CutterCore::getBreakpointAt(RVA addr)
|
||||||
|
{
|
||||||
|
CORE_LOCK();
|
||||||
|
int index = breakpointIndexAt(addr);
|
||||||
|
auto bp = r_bp_get_index(core->dbg->bp, index);
|
||||||
|
if (bp) {
|
||||||
|
return breakpointDescriptionFromR2(index, bp);
|
||||||
|
}
|
||||||
|
return BreakpointDescription();
|
||||||
|
}
|
||||||
|
|
||||||
QList<BreakpointDescription> CutterCore::getBreakpoints()
|
QList<BreakpointDescription> CutterCore::getBreakpoints()
|
||||||
{
|
{
|
||||||
|
CORE_LOCK();
|
||||||
QList<BreakpointDescription> ret;
|
QList<BreakpointDescription> ret;
|
||||||
QJsonArray breakpointArray = cmdj("dbj").array();
|
//TODO: use higher level API, don't touch r2 bps_idx directly
|
||||||
|
for (int i = 0; i < core->dbg->bp->bps_idx_count; i++) {
|
||||||
for (const QJsonValue &value : breakpointArray) {
|
if (auto bpi = core->dbg->bp->bps_idx[i]) {
|
||||||
QJsonObject bpObject = value.toObject();
|
ret.push_back(breakpointDescriptionFromR2(i, bpi));
|
||||||
|
}
|
||||||
BreakpointDescription bp;
|
|
||||||
|
|
||||||
bp.addr = bpObject[RJsonKey::addr].toVariant().toULongLong();
|
|
||||||
bp.size = bpObject[RJsonKey::size].toInt();
|
|
||||||
bp.permission = bpObject[RJsonKey::prot].toString();
|
|
||||||
bp.hw = bpObject[RJsonKey::hw].toBool();
|
|
||||||
bp.trace = bpObject[RJsonKey::trace].toBool();
|
|
||||||
bp.enabled = bpObject[RJsonKey::enabled].toBool();
|
|
||||||
|
|
||||||
ret << bp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -319,7 +319,10 @@ public:
|
|||||||
void stepDebug();
|
void stepDebug();
|
||||||
void stepOverDebug();
|
void stepOverDebug();
|
||||||
void stepOutDebug();
|
void stepOutDebug();
|
||||||
|
|
||||||
void addBreakpoint(QString addr);
|
void addBreakpoint(QString addr);
|
||||||
|
void addBreakpoint(const BreakpointDescription &config);
|
||||||
|
void updateBreakpoint(int index, const BreakpointDescription &config);
|
||||||
void toggleBreakpoint(RVA addr);
|
void toggleBreakpoint(RVA addr);
|
||||||
void toggleBreakpoint(QString addr);
|
void toggleBreakpoint(QString addr);
|
||||||
void delBreakpoint(RVA addr);
|
void delBreakpoint(RVA addr);
|
||||||
@ -332,6 +335,8 @@ public:
|
|||||||
* @param enabled - true if tracing should be enabled
|
* @param enabled - true if tracing should be enabled
|
||||||
*/
|
*/
|
||||||
void setBreakpointTrace(int index, bool enabled);
|
void setBreakpointTrace(int index, bool enabled);
|
||||||
|
int breakpointIndexAt(RVA addr);
|
||||||
|
BreakpointDescription getBreakpointAt(RVA addr);
|
||||||
|
|
||||||
bool isBreakpoint(const QList<RVA> &breakpoints, RVA addr);
|
bool isBreakpoint(const QList<RVA> &breakpoints, RVA addr);
|
||||||
QList<RVA> getBreakpointsAddresses();
|
QList<RVA> getBreakpointsAddresses();
|
||||||
|
@ -276,12 +276,25 @@ struct MemoryMapDescription {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BreakpointDescription {
|
struct BreakpointDescription {
|
||||||
RVA addr;
|
enum PositionType {
|
||||||
int size;
|
Address,
|
||||||
QString permission;
|
Named,
|
||||||
bool hw;
|
Module,
|
||||||
bool trace;
|
};
|
||||||
bool enabled;
|
|
||||||
|
RVA addr = 0;
|
||||||
|
int64_t moduleDelta = 0;
|
||||||
|
int index = -1;
|
||||||
|
PositionType type = Address;
|
||||||
|
int size = 0;
|
||||||
|
int permission = 0;
|
||||||
|
QString positionExpression;
|
||||||
|
QString name;
|
||||||
|
QString command;
|
||||||
|
QString condition;
|
||||||
|
bool hw = false;
|
||||||
|
bool trace = false;
|
||||||
|
bool enabled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProcessDescription {
|
struct ProcessDescription {
|
||||||
@ -338,6 +351,7 @@ Q_DECLARE_METATYPE(SectionDescription)
|
|||||||
Q_DECLARE_METATYPE(SegmentDescription)
|
Q_DECLARE_METATYPE(SegmentDescription)
|
||||||
Q_DECLARE_METATYPE(MemoryMapDescription)
|
Q_DECLARE_METATYPE(MemoryMapDescription)
|
||||||
Q_DECLARE_METATYPE(BreakpointDescription)
|
Q_DECLARE_METATYPE(BreakpointDescription)
|
||||||
|
Q_DECLARE_METATYPE(BreakpointDescription::PositionType)
|
||||||
Q_DECLARE_METATYPE(ProcessDescription)
|
Q_DECLARE_METATYPE(ProcessDescription)
|
||||||
Q_DECLARE_METATYPE(RegisterRefDescription)
|
Q_DECLARE_METATYPE(RegisterRefDescription)
|
||||||
Q_DECLARE_METATYPE(VariableDescription)
|
Q_DECLARE_METATYPE(VariableDescription)
|
||||||
|
@ -1,47 +1,213 @@
|
|||||||
#include "BreakpointsDialog.h"
|
#include "BreakpointsDialog.h"
|
||||||
#include "ui_BreakpointsDialog.h"
|
#include "ui_BreakpointsDialog.h"
|
||||||
|
#include "Cutter.h"
|
||||||
|
#include "Helpers.h"
|
||||||
|
|
||||||
BreakpointsDialog::BreakpointsDialog(QWidget *parent) :
|
#include <QPushButton>
|
||||||
|
#include <QCompleter>
|
||||||
|
#include <QCheckBox>
|
||||||
|
|
||||||
|
BreakpointsDialog::BreakpointsDialog(bool editMode, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::BreakpointsDialog)
|
ui(new Ui::BreakpointsDialog),
|
||||||
|
editMode(editMode)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||||
|
|
||||||
// Event filter for capturing Ctrl/Cmd+Return
|
connect(ui->breakpointPosition, &QLineEdit::textChanged, this, &BreakpointsDialog::refreshOkButton);
|
||||||
ui->textEdit->installEventFilter(this);
|
refreshOkButton();
|
||||||
|
|
||||||
|
if (editMode) {
|
||||||
|
setWindowTitle(tr("Edit breakpoint"));
|
||||||
|
} else {
|
||||||
|
setWindowTitle(tr("New breakpoint"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct {
|
||||||
|
QString label;
|
||||||
|
QString tooltip;
|
||||||
|
BreakpointDescription::PositionType type;
|
||||||
|
} positionTypes[] = {
|
||||||
|
{tr("Address"), tr("Address or expression calculated when creating breakpoint"), BreakpointDescription::Address},
|
||||||
|
{tr("Named"), tr("Expression - stored as expression"), BreakpointDescription::Named},
|
||||||
|
{tr("Module offset"), tr("Offset relative to module"), BreakpointDescription::Module},
|
||||||
|
};
|
||||||
|
int index = 0;
|
||||||
|
for (auto &item : positionTypes) {
|
||||||
|
ui->positionType->addItem(item.label, item.type);
|
||||||
|
ui->positionType->setItemData(index, item.tooltip, Qt::ToolTipRole);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(ui->positionType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
this, &BreakpointsDialog::onTypeChanged);
|
||||||
|
onTypeChanged();
|
||||||
|
|
||||||
|
auto modules = Core()->getMemoryMap();
|
||||||
|
QSet<QString> moduleNames;
|
||||||
|
for (const auto &module : modules) {
|
||||||
|
moduleNames.insert(module.fileName);
|
||||||
|
}
|
||||||
|
for (const auto& module : moduleNames) {
|
||||||
|
ui->moduleName->addItem(module);
|
||||||
|
}
|
||||||
|
ui->moduleName->setCurrentText("");
|
||||||
|
// Suggest completion when user tries to enter file name not only full path
|
||||||
|
ui->moduleName->completer()->setFilterMode(Qt::MatchContains);
|
||||||
|
|
||||||
|
ui->breakpointCondition->setCompleter(nullptr); // Don't use examples for completing
|
||||||
|
configureCheckboxRestrictions();
|
||||||
|
}
|
||||||
|
|
||||||
|
BreakpointsDialog::BreakpointsDialog(const BreakpointDescription &breakpoint, QWidget *parent)
|
||||||
|
: BreakpointsDialog(true, parent)
|
||||||
|
{
|
||||||
|
switch (breakpoint.type) {
|
||||||
|
case BreakpointDescription::Address:
|
||||||
|
ui->breakpointPosition->setText(RAddressString(breakpoint.addr));
|
||||||
|
break;
|
||||||
|
case BreakpointDescription::Named:
|
||||||
|
ui->breakpointPosition->setText(breakpoint.positionExpression);
|
||||||
|
break;
|
||||||
|
case BreakpointDescription::Module:
|
||||||
|
ui->breakpointPosition->setText(QString::number(breakpoint.moduleDelta));
|
||||||
|
ui->moduleName->setCurrentText(breakpoint.positionExpression);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ui->positionType->count(); i++) {
|
||||||
|
if (ui->positionType->itemData(i) == breakpoint.type) {
|
||||||
|
ui->positionType->setCurrentIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui->breakpointCommand->setPlainText(breakpoint.command);
|
||||||
|
ui->breakpointCondition->setEditText(breakpoint.condition);
|
||||||
|
if (breakpoint.hw) {
|
||||||
|
ui->radioHardware->setChecked(true);
|
||||||
|
ui->hwRead->setChecked(breakpoint.permission & R_BP_PROT_READ);
|
||||||
|
ui->hwWrite->setChecked(breakpoint.permission & R_BP_PROT_WRITE);
|
||||||
|
ui->hwExecute->setChecked(breakpoint.permission & R_BP_PROT_EXEC);
|
||||||
|
ui->breakpointSize->setCurrentText(QString::number(breakpoint.size));
|
||||||
|
} else {
|
||||||
|
ui->radioSoftware->setChecked(true);
|
||||||
|
}
|
||||||
|
ui->checkTrace->setChecked(breakpoint.trace);
|
||||||
|
ui->checkEnabled->setChecked(breakpoint.enabled);
|
||||||
|
refreshOkButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
BreakpointsDialog::BreakpointsDialog(RVA address, QWidget *parent)
|
||||||
|
: BreakpointsDialog(false, parent)
|
||||||
|
{
|
||||||
|
if (address != RVA_INVALID) {
|
||||||
|
ui->breakpointPosition->setText(RAddressString(address));
|
||||||
|
}
|
||||||
|
refreshOkButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakpointsDialog::~BreakpointsDialog() {}
|
BreakpointsDialog::~BreakpointsDialog() {}
|
||||||
|
|
||||||
void BreakpointsDialog::on_buttonBox_accepted()
|
BreakpointDescription BreakpointsDialog::getDescription()
|
||||||
{
|
{
|
||||||
}
|
BreakpointDescription breakpoint;
|
||||||
|
auto positionType = ui->positionType->currentData().value<BreakpointDescription::PositionType>();
|
||||||
void BreakpointsDialog::on_buttonBox_rejected()
|
switch (positionType) {
|
||||||
{
|
case BreakpointDescription::Address:
|
||||||
close();
|
breakpoint.addr = Core()->math(ui->breakpointPosition->text());
|
||||||
}
|
break;
|
||||||
|
case BreakpointDescription::Named:
|
||||||
QString BreakpointsDialog::getBreakpoints()
|
breakpoint.positionExpression = ui->breakpointPosition->text().trimmed();
|
||||||
{
|
break;
|
||||||
QString ret = ui->textEdit->document()->toPlainText();
|
case BreakpointDescription::Module:
|
||||||
return ret;
|
breakpoint.moduleDelta = static_cast<int64_t>(Core()->math(ui->breakpointPosition->text()));
|
||||||
}
|
breakpoint.positionExpression = ui->moduleName->currentText().trimmed();
|
||||||
|
break;
|
||||||
bool BreakpointsDialog::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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
breakpoint.type = positionType;
|
||||||
|
|
||||||
return false;
|
breakpoint.size = Core()->num(ui->breakpointSize->currentText());
|
||||||
|
breakpoint.condition = ui->breakpointCondition->currentText().trimmed();
|
||||||
|
breakpoint.command = ui->breakpointCommand->toPlainText().trimmed();
|
||||||
|
if (ui->radioHardware->isChecked()) {
|
||||||
|
breakpoint.hw = true;
|
||||||
|
breakpoint.permission = getHwPermissions();
|
||||||
|
} else {
|
||||||
|
breakpoint.hw = false;
|
||||||
|
}
|
||||||
|
breakpoint.trace = ui->checkTrace->isChecked();
|
||||||
|
breakpoint.enabled = ui->checkEnabled->isChecked();
|
||||||
|
return breakpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BreakpointsDialog::createNewBreakpoint(RVA address, QWidget *parent)
|
||||||
|
{
|
||||||
|
BreakpointsDialog editDialog(address, parent);
|
||||||
|
if (editDialog.exec() == QDialog::Accepted) {
|
||||||
|
Core()->addBreakpoint(editDialog.getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BreakpointsDialog::editBreakpoint(const BreakpointDescription &breakpoint, QWidget *parent)
|
||||||
|
{
|
||||||
|
BreakpointsDialog editDialog(breakpoint, parent);
|
||||||
|
if (editDialog.exec() == QDialog::Accepted) {
|
||||||
|
Core()->updateBreakpoint(breakpoint.index, editDialog.getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BreakpointsDialog::refreshOkButton()
|
||||||
|
{
|
||||||
|
auto button = ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok);
|
||||||
|
button->setDisabled(ui->breakpointPosition->text().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BreakpointsDialog::onTypeChanged()
|
||||||
|
{
|
||||||
|
bool moduleEnabled = ui->positionType->currentData() == QVariant(BreakpointDescription::Module);
|
||||||
|
ui->moduleLabel->setEnabled(moduleEnabled);
|
||||||
|
ui->moduleName->setEnabled(moduleEnabled);
|
||||||
|
ui->breakpointPosition->setPlaceholderText(ui->positionType->currentData(Qt::ToolTipRole).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BreakpointsDialog::configureCheckboxRestrictions()
|
||||||
|
{
|
||||||
|
auto atLeastOneChecked = [this]() {
|
||||||
|
if (this->getHwPermissions() == 0) {
|
||||||
|
this->ui->hwExecute->setChecked(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto rwRule = [this, atLeastOneChecked](bool checked) {
|
||||||
|
if (checked) {
|
||||||
|
this->ui->hwExecute->setChecked(false);
|
||||||
|
} else {
|
||||||
|
atLeastOneChecked();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
connect(ui->hwRead, &QCheckBox::toggled, this, rwRule);
|
||||||
|
connect(ui->hwWrite, &QCheckBox::toggled, this, rwRule);
|
||||||
|
auto execRule = [this, atLeastOneChecked](bool checked) {
|
||||||
|
if (checked) {
|
||||||
|
this->ui->hwRead->setChecked(false);
|
||||||
|
this->ui->hwWrite->setChecked(false);
|
||||||
|
} else {
|
||||||
|
atLeastOneChecked();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
connect(ui->hwExecute, &QCheckBox::toggled, this, execRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BreakpointsDialog::getHwPermissions()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
if (ui->hwRead->isChecked()) {
|
||||||
|
result |= R_BP_PROT_READ;
|
||||||
|
}
|
||||||
|
if (ui->hwWrite->isChecked()) {
|
||||||
|
result |= R_BP_PROT_WRITE;
|
||||||
|
}
|
||||||
|
if (ui->hwExecute->isChecked()) {
|
||||||
|
result |= R_BP_PROT_EXEC;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "CutterDescriptions.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class BreakpointsDialog;
|
class BreakpointsDialog;
|
||||||
@ -12,17 +13,21 @@ class BreakpointsDialog : public QDialog
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BreakpointsDialog(QWidget *parent = nullptr);
|
explicit BreakpointsDialog(bool editMode = false, QWidget *parent = nullptr);
|
||||||
|
BreakpointsDialog(const BreakpointDescription &editableBreakpoint, QWidget *parent = nullptr);
|
||||||
|
BreakpointsDialog(RVA address, QWidget *parent = nullptr);
|
||||||
~BreakpointsDialog();
|
~BreakpointsDialog();
|
||||||
|
|
||||||
QString getBreakpoints();
|
BreakpointDescription getDescription();
|
||||||
|
|
||||||
private slots:
|
|
||||||
void on_buttonBox_accepted();
|
|
||||||
void on_buttonBox_rejected();
|
|
||||||
|
|
||||||
|
static void createNewBreakpoint(RVA address = RVA_INVALID, QWidget *parent = nullptr);
|
||||||
|
static void editBreakpoint(const BreakpointDescription& breakpoint, QWidget *parent = nullptr);
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::BreakpointsDialog> ui;
|
std::unique_ptr<Ui::BreakpointsDialog> ui;
|
||||||
|
bool editMode = false;
|
||||||
|
|
||||||
bool eventFilter(QObject *obj, QEvent *event);
|
void refreshOkButton();
|
||||||
|
void onTypeChanged();
|
||||||
|
void configureCheckboxRestrictions();
|
||||||
|
int getHwPermissions();
|
||||||
};
|
};
|
||||||
|
@ -6,36 +6,287 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>400</width>
|
<width>610</width>
|
||||||
<height>118</height>
|
<height>437</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Add breakpoints</string>
|
<string>Add/Edit breakpoint</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="topGroup">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Position</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>breakpointPosition</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>2</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>2</number>
|
<number>0</number>
|
||||||
</property>
|
</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">
|
<property name="topMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="textEdit"/>
|
<widget class="QComboBox" name="positionType"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="breakpointPosition"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Condition</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>breakpointCondition</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QComboBox" name="breakpointCondition">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="currentText">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="insertPolicy">
|
||||||
|
<enum>QComboBox::NoInsert</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frame">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>?v $.rax-0x6 # break when rax is 6</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="moduleLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Module</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>moduleName</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="moduleName">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Type/Options</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkEnabled">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enabled</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radioSoftware">
|
||||||
|
<property name="text">
|
||||||
|
<string>Software</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radioHardware">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hardware</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="hwConfigBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="hwRead">
|
||||||
|
<property name="text">
|
||||||
|
<string>Read</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="hwWrite">
|
||||||
|
<property name="text">
|
||||||
|
<string>Write</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="hwExecute">
|
||||||
|
<property name="text">
|
||||||
|
<string>Execute</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Size</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>breakpointSize</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="breakpointSize">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>1</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>2</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>4</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>8</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Action</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkTrace">
|
||||||
|
<property name="text">
|
||||||
|
<string>Trace</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Command</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>breakpointCommand</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QPlainTextEdit" name="breakpointCommand"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
@ -51,6 +302,17 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>positionType</tabstop>
|
||||||
|
<tabstop>breakpointPosition</tabstop>
|
||||||
|
<tabstop>moduleName</tabstop>
|
||||||
|
<tabstop>breakpointCondition</tabstop>
|
||||||
|
<tabstop>checkEnabled</tabstop>
|
||||||
|
<tabstop>radioSoftware</tabstop>
|
||||||
|
<tabstop>radioHardware</tabstop>
|
||||||
|
<tabstop>checkTrace</tabstop>
|
||||||
|
<tabstop>breakpointCommand</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
@ -60,8 +322,8 @@
|
|||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>248</x>
|
<x>260</x>
|
||||||
<y>254</y>
|
<y>450</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
@ -76,8 +338,8 @@
|
|||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>316</x>
|
<x>328</x>
|
||||||
<y>260</y>
|
<y>450</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>286</x>
|
<x>286</x>
|
||||||
@ -85,5 +347,21 @@
|
|||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>radioHardware</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>hwConfigBox</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>77</x>
|
||||||
|
<y>246</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>77</x>
|
||||||
|
<y>320</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "dialogs/EditFunctionDialog.h"
|
#include "dialogs/EditFunctionDialog.h"
|
||||||
#include "dialogs/LinkTypeDialog.h"
|
#include "dialogs/LinkTypeDialog.h"
|
||||||
#include "dialogs/EditStringDialog.h"
|
#include "dialogs/EditStringDialog.h"
|
||||||
|
#include "dialogs/BreakpointsDialog.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
@ -56,6 +57,7 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
|||||||
actionSetBits64(this),
|
actionSetBits64(this),
|
||||||
actionContinueUntil(this),
|
actionContinueUntil(this),
|
||||||
actionAddBreakpoint(this),
|
actionAddBreakpoint(this),
|
||||||
|
actionAdvancedBreakpoint(this),
|
||||||
actionSetPC(this),
|
actionSetPC(this),
|
||||||
actionSetToCode(this),
|
actionSetToCode(this),
|
||||||
actionSetAsStringAuto(this),
|
actionSetAsStringAuto(this),
|
||||||
@ -292,6 +294,9 @@ void DisassemblyContextMenu::addDebugMenu()
|
|||||||
initAction(&actionAddBreakpoint, tr("Add/remove breakpoint"),
|
initAction(&actionAddBreakpoint, tr("Add/remove breakpoint"),
|
||||||
SLOT(on_actionAddBreakpoint_triggered()), getAddBPSequence());
|
SLOT(on_actionAddBreakpoint_triggered()), getAddBPSequence());
|
||||||
debugMenu->addAction(&actionAddBreakpoint);
|
debugMenu->addAction(&actionAddBreakpoint);
|
||||||
|
initAction(&actionAdvancedBreakpoint, tr("Advanced breakpoint"),
|
||||||
|
SLOT(on_actionAdvancedBreakpoint_triggered()), QKeySequence(Qt::CTRL+Qt::Key_F2));
|
||||||
|
debugMenu->addAction(&actionAdvancedBreakpoint);
|
||||||
|
|
||||||
initAction(&actionContinueUntil, tr("Continue until line"),
|
initAction(&actionContinueUntil, tr("Continue until line"),
|
||||||
SLOT(on_actionContinueUntil_triggered()));
|
SLOT(on_actionContinueUntil_triggered()));
|
||||||
@ -503,9 +508,13 @@ void DisassemblyContextMenu::aboutToShowSlot()
|
|||||||
|
|
||||||
// Only show debug options if we are currently debugging
|
// Only show debug options if we are currently debugging
|
||||||
debugMenu->menuAction()->setVisible(Core()->currentlyDebugging);
|
debugMenu->menuAction()->setVisible(Core()->currentlyDebugging);
|
||||||
|
bool hasBreakpoint = Core()->breakpointIndexAt(offset) > -1;
|
||||||
|
actionAddBreakpoint.setText(hasBreakpoint ?
|
||||||
|
tr("Remove breakpoint") : tr("Add breakpoint"));
|
||||||
|
actionAdvancedBreakpoint.setText(hasBreakpoint ?
|
||||||
|
tr("Edit breakpoint") : tr("Advanced breakpoint"));
|
||||||
QString progCounterName = Core()->getRegisterName("PC").toUpper();
|
QString progCounterName = Core()->getRegisterName("PC").toUpper();
|
||||||
actionSetPC.setText("Set " + progCounterName + " here");
|
actionSetPC.setText("Set " + progCounterName + " here");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QKeySequence DisassemblyContextMenu::getCopySequence() const
|
QKeySequence DisassemblyContextMenu::getCopySequence() const
|
||||||
@ -731,6 +740,16 @@ void DisassemblyContextMenu::on_actionAddBreakpoint_triggered()
|
|||||||
Core()->toggleBreakpoint(offset);
|
Core()->toggleBreakpoint(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisassemblyContextMenu::on_actionAdvancedBreakpoint_triggered()
|
||||||
|
{
|
||||||
|
int index = Core()->breakpointIndexAt(offset);
|
||||||
|
if (index >= 0) {
|
||||||
|
BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(offset), this);
|
||||||
|
} else {
|
||||||
|
BreakpointsDialog::createNewBreakpoint(offset, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DisassemblyContextMenu::on_actionContinueUntil_triggered()
|
void DisassemblyContextMenu::on_actionContinueUntil_triggered()
|
||||||
{
|
{
|
||||||
Core()->continueUntilDebug(RAddressString(offset));
|
Core()->continueUntilDebug(RAddressString(offset));
|
||||||
|
@ -53,6 +53,7 @@ private slots:
|
|||||||
void on_actionDeleteFunction_triggered();
|
void on_actionDeleteFunction_triggered();
|
||||||
|
|
||||||
void on_actionAddBreakpoint_triggered();
|
void on_actionAddBreakpoint_triggered();
|
||||||
|
void on_actionAdvancedBreakpoint_triggered();
|
||||||
void on_actionContinueUntil_triggered();
|
void on_actionContinueUntil_triggered();
|
||||||
void on_actionSetPC_triggered();
|
void on_actionSetPC_triggered();
|
||||||
|
|
||||||
@ -157,6 +158,7 @@ private:
|
|||||||
QMenu *debugMenu;
|
QMenu *debugMenu;
|
||||||
QAction actionContinueUntil;
|
QAction actionContinueUntil;
|
||||||
QAction actionAddBreakpoint;
|
QAction actionAddBreakpoint;
|
||||||
|
QAction actionAdvancedBreakpoint;
|
||||||
QAction actionSetPC;
|
QAction actionSetPC;
|
||||||
|
|
||||||
QAction actionSetToCode;
|
QAction actionSetToCode;
|
||||||
|
@ -30,6 +30,20 @@ int BreakpointModel::columnCount(const QModelIndex &) const
|
|||||||
return BreakpointModel::ColumnCount;
|
return BreakpointModel::ColumnCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QString formatHwBreakpoint(int permission) {
|
||||||
|
char data[] = "rwx";
|
||||||
|
if ((permission & (R_BP_PROT_READ | R_BP_PROT_ACCESS)) == 0) {
|
||||||
|
data[0] = '-';
|
||||||
|
}
|
||||||
|
if ((permission & (R_BP_PROT_WRITE | R_BP_PROT_ACCESS)) == 0) {
|
||||||
|
data[1] = '-';
|
||||||
|
}
|
||||||
|
if ((permission & R_BP_PROT_EXEC) == 0) {
|
||||||
|
data[2] = '-';
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant BreakpointModel::data(const QModelIndex &index, int role) const
|
QVariant BreakpointModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (index.row() >= breakpoints.count())
|
if (index.row() >= breakpoints.count())
|
||||||
@ -42,10 +56,15 @@ QVariant BreakpointModel::data(const QModelIndex &index, int role) const
|
|||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case AddrColumn:
|
case AddrColumn:
|
||||||
return RAddressString(breakpoint.addr);
|
return RAddressString(breakpoint.addr);
|
||||||
case PermColumn:
|
case NameColumn:
|
||||||
return breakpoint.permission;
|
return breakpoint.name;
|
||||||
case HwColumn:
|
case TypeColumn:
|
||||||
return breakpoint.hw;
|
|
||||||
|
if (breakpoint.hw) {
|
||||||
|
return tr("HW %1").arg(formatHwBreakpoint(breakpoint.permission));
|
||||||
|
} else {
|
||||||
|
return tr("SW");
|
||||||
|
}
|
||||||
case TraceColumn:
|
case TraceColumn:
|
||||||
return breakpoint.trace;
|
return breakpoint.trace;
|
||||||
case EnabledColumn:
|
case EnabledColumn:
|
||||||
@ -55,6 +74,8 @@ QVariant BreakpointModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
case Qt::EditRole:
|
case Qt::EditRole:
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
|
case AddrColumn:
|
||||||
|
return breakpoint.addr;
|
||||||
case TraceColumn:
|
case TraceColumn:
|
||||||
return breakpoint.trace;
|
return breakpoint.trace;
|
||||||
case EnabledColumn:
|
case EnabledColumn:
|
||||||
@ -76,14 +97,14 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation, int role) con
|
|||||||
switch (section) {
|
switch (section) {
|
||||||
case AddrColumn:
|
case AddrColumn:
|
||||||
return tr("Offset");
|
return tr("Offset");
|
||||||
case PermColumn:
|
case NameColumn:
|
||||||
return tr("Permissions");
|
return tr("Name");
|
||||||
case HwColumn:
|
case TypeColumn:
|
||||||
return tr("Hardware bp");
|
return tr("Type");
|
||||||
case TraceColumn:
|
case TraceColumn:
|
||||||
return tr("Tracing");
|
return tr("Tracing");
|
||||||
case EnabledColumn:
|
case EnabledColumn:
|
||||||
return tr("Active");
|
return tr("Enabled");
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -104,7 +125,7 @@ bool BreakpointModel::setData(const QModelIndex &index, const QVariant &value, i
|
|||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case TraceColumn:
|
case TraceColumn:
|
||||||
breakpoint.trace = value.toBool();
|
breakpoint.trace = value.toBool();
|
||||||
Core()->setBreakpointTrace(index.row(), breakpoint.trace);
|
Core()->setBreakpointTrace(breakpoint.index, breakpoint.trace);
|
||||||
emit dataChanged(index, index, {role, Qt::DisplayRole});
|
emit dataChanged(index, index, {role, Qt::DisplayRole});
|
||||||
return true;
|
return true;
|
||||||
case EnabledColumn:
|
case EnabledColumn:
|
||||||
@ -148,37 +169,8 @@ RVA BreakpointModel::address(const QModelIndex &index) const
|
|||||||
BreakpointProxyModel::BreakpointProxyModel(BreakpointModel *sourceModel, QObject *parent)
|
BreakpointProxyModel::BreakpointProxyModel(BreakpointModel *sourceModel, QObject *parent)
|
||||||
: AddressableFilterProxyModel(sourceModel, parent)
|
: AddressableFilterProxyModel(sourceModel, parent)
|
||||||
{
|
{
|
||||||
}
|
// Use numeric values instead of numbers converted to strings if available
|
||||||
|
this->setSortRole(Qt::EditRole);
|
||||||
bool BreakpointProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
QModelIndex index = sourceModel()->index(row, 0, parent);
|
|
||||||
BreakpointDescription item = index.data(
|
|
||||||
BreakpointModel::BreakpointDescriptionRole).value<BreakpointDescription>();
|
|
||||||
return item.permission.contains(filterRegExp());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BreakpointProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
|
||||||
{
|
|
||||||
BreakpointDescription leftBreakpt = left.data(
|
|
||||||
BreakpointModel::BreakpointDescriptionRole).value<BreakpointDescription>();
|
|
||||||
BreakpointDescription rightBreakpt = right.data(
|
|
||||||
BreakpointModel::BreakpointDescriptionRole).value<BreakpointDescription>();
|
|
||||||
|
|
||||||
switch (left.column()) {
|
|
||||||
case BreakpointModel::AddrColumn:
|
|
||||||
return leftBreakpt.addr < rightBreakpt.addr;
|
|
||||||
case BreakpointModel::HwColumn:
|
|
||||||
return leftBreakpt.hw < rightBreakpt.hw;
|
|
||||||
case BreakpointModel::PermColumn:
|
|
||||||
return leftBreakpt.permission < rightBreakpt.permission;
|
|
||||||
case BreakpointModel::EnabledColumn:
|
|
||||||
return leftBreakpt.enabled < rightBreakpt.enabled;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return leftBreakpt.addr < rightBreakpt.addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakpointWidget::BreakpointWidget(MainWindow *main, QAction *action) :
|
BreakpointWidget::BreakpointWidget(MainWindow *main, QAction *action) :
|
||||||
@ -212,7 +204,11 @@ BreakpointWidget::BreakpointWidget(MainWindow *main, QAction *action) :
|
|||||||
connect(actionToggleBreakpoint, &QAction::triggered, this, &BreakpointWidget::toggleBreakpoint);
|
connect(actionToggleBreakpoint, &QAction::triggered, this, &BreakpointWidget::toggleBreakpoint);
|
||||||
ui->breakpointTreeView->addAction(actionToggleBreakpoint);
|
ui->breakpointTreeView->addAction(actionToggleBreakpoint);
|
||||||
|
|
||||||
|
actionEditBreakpoint = new QAction(tr("Edit"), this);
|
||||||
|
connect(actionEditBreakpoint, &QAction::triggered, this, &BreakpointWidget::editBreakpoint);
|
||||||
|
|
||||||
auto contextMenu = ui->breakpointTreeView->getItemContextMenu();
|
auto contextMenu = ui->breakpointTreeView->getItemContextMenu();
|
||||||
|
contextMenu->addAction(actionEditBreakpoint);
|
||||||
contextMenu->addAction(actionToggleBreakpoint);
|
contextMenu->addAction(actionToggleBreakpoint);
|
||||||
contextMenu->addAction(actionDelBreakpoint);
|
contextMenu->addAction(actionDelBreakpoint);
|
||||||
|
|
||||||
@ -247,17 +243,7 @@ void BreakpointWidget::setScrollMode()
|
|||||||
|
|
||||||
void BreakpointWidget::addBreakpointDialog()
|
void BreakpointWidget::addBreakpointDialog()
|
||||||
{
|
{
|
||||||
BreakpointsDialog dialog(this);
|
BreakpointsDialog::createNewBreakpoint(RVA_INVALID, this);
|
||||||
|
|
||||||
if (dialog.exec()) {
|
|
||||||
QString bps = dialog.getBreakpoints();
|
|
||||||
if (!bps.isEmpty()) {
|
|
||||||
QStringList bpList = bps.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
|
||||||
for (const QString &bp : bpList) {
|
|
||||||
Core()->addBreakpoint(bp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<RVA> BreakpointWidget::getSelectedAddresses() const
|
QVector<RVA> BreakpointWidget::getSelectedAddresses() const
|
||||||
@ -289,3 +275,15 @@ void BreakpointWidget::toggleBreakpoint()
|
|||||||
}
|
}
|
||||||
editing = false;
|
editing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BreakpointWidget::editBreakpoint()
|
||||||
|
{
|
||||||
|
auto index = ui->breakpointTreeView->currentIndex();
|
||||||
|
if (index.isValid()) {
|
||||||
|
auto data = breakpointProxyModel->data(index, BreakpointModel::BreakpointDescriptionRole);
|
||||||
|
if (!data.isNull()) {
|
||||||
|
auto breakpoint = data.value<BreakpointDescription>();
|
||||||
|
BreakpointsDialog::editBreakpoint(breakpoint, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -31,7 +31,7 @@ private:
|
|||||||
QList<BreakpointDescription> breakpoints;
|
QList<BreakpointDescription> breakpoints;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Column { AddrColumn = 0, PermColumn, HwColumn, TraceColumn, EnabledColumn, ColumnCount };
|
enum Column { AddrColumn = 0, NameColumn, TypeColumn, TraceColumn, EnabledColumn, ColumnCount };
|
||||||
enum Role { BreakpointDescriptionRole = Qt::UserRole };
|
enum Role { BreakpointDescriptionRole = Qt::UserRole };
|
||||||
|
|
||||||
BreakpointModel(QObject *parent = nullptr);
|
BreakpointModel(QObject *parent = nullptr);
|
||||||
@ -60,9 +60,6 @@ class BreakpointProxyModel : public AddressableFilterProxyModel
|
|||||||
public:
|
public:
|
||||||
BreakpointProxyModel(BreakpointModel *sourceModel, QObject *parent = nullptr);
|
BreakpointProxyModel(BreakpointModel *sourceModel, QObject *parent = nullptr);
|
||||||
|
|
||||||
protected:
|
|
||||||
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
|
|
||||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -78,6 +75,7 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void delBreakpoint();
|
void delBreakpoint();
|
||||||
void toggleBreakpoint();
|
void toggleBreakpoint();
|
||||||
|
void editBreakpoint();
|
||||||
void addBreakpointDialog();
|
void addBreakpointDialog();
|
||||||
void refreshBreakpoint();
|
void refreshBreakpoint();
|
||||||
|
|
||||||
@ -89,6 +87,7 @@ private:
|
|||||||
QList<BreakpointDescription> breakpoints;
|
QList<BreakpointDescription> breakpoints;
|
||||||
QAction *actionDelBreakpoint = nullptr;
|
QAction *actionDelBreakpoint = nullptr;
|
||||||
QAction *actionToggleBreakpoint = nullptr;
|
QAction *actionToggleBreakpoint = nullptr;
|
||||||
|
QAction *actionEditBreakpoint = nullptr;
|
||||||
|
|
||||||
void setScrollMode();
|
void setScrollMode();
|
||||||
QVector<RVA> getSelectedAddresses() const;
|
QVector<RVA> getSelectedAddresses() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user