2017-10-03 16:43:44 +00:00
|
|
|
// Copyright 2017 Dolphin Emulator Project
|
2021-07-05 01:22:19 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2017-10-03 16:43:44 +00:00
|
|
|
|
2018-07-06 22:40:15 +00:00
|
|
|
#include "DolphinQt/Debugger/NewBreakpointDialog.h"
|
2017-10-03 16:43:44 +00:00
|
|
|
|
2022-01-31 18:12:55 +00:00
|
|
|
#include <QButtonGroup>
|
2017-10-03 16:43:44 +00:00
|
|
|
#include <QCheckBox>
|
|
|
|
#include <QDialogButtonBox>
|
|
|
|
#include <QGridLayout>
|
|
|
|
#include <QGroupBox>
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
#include <QLabel>
|
|
|
|
#include <QLineEdit>
|
|
|
|
#include <QRadioButton>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
2018-07-06 22:40:15 +00:00
|
|
|
#include "DolphinQt/Debugger/BreakpointWidget.h"
|
2019-03-04 19:49:00 +00:00
|
|
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
2017-10-03 16:43:44 +00:00
|
|
|
|
|
|
|
NewBreakpointDialog::NewBreakpointDialog(BreakpointWidget* parent)
|
|
|
|
: QDialog(parent), m_parent(parent)
|
|
|
|
{
|
2021-08-13 08:56:11 +00:00
|
|
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
2017-10-03 16:43:44 +00:00
|
|
|
setWindowTitle(tr("New Breakpoint"));
|
|
|
|
CreateWidgets();
|
|
|
|
ConnectWidgets();
|
|
|
|
|
|
|
|
OnBPTypeChanged();
|
|
|
|
OnAddressTypeChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NewBreakpointDialog::CreateWidgets()
|
|
|
|
{
|
|
|
|
m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
2022-01-31 18:12:55 +00:00
|
|
|
auto* type_group = new QButtonGroup(this);
|
2017-10-03 16:43:44 +00:00
|
|
|
|
|
|
|
// Instruction BP
|
|
|
|
m_instruction_bp = new QRadioButton(tr("Instruction Breakpoint"));
|
|
|
|
m_instruction_bp->setChecked(true);
|
2022-01-31 18:12:55 +00:00
|
|
|
type_group->addButton(m_instruction_bp);
|
2017-10-03 16:43:44 +00:00
|
|
|
m_instruction_box = new QGroupBox;
|
|
|
|
m_instruction_address = new QLineEdit;
|
|
|
|
|
|
|
|
auto* instruction_layout = new QHBoxLayout;
|
|
|
|
m_instruction_box->setLayout(instruction_layout);
|
|
|
|
instruction_layout->addWidget(new QLabel(tr("Address:")));
|
|
|
|
instruction_layout->addWidget(m_instruction_address);
|
|
|
|
|
|
|
|
// Memory BP
|
|
|
|
m_memory_bp = new QRadioButton(tr("Memory Breakpoint"));
|
2022-01-31 18:12:55 +00:00
|
|
|
type_group->addButton(m_memory_bp);
|
2017-10-03 16:43:44 +00:00
|
|
|
m_memory_box = new QGroupBox;
|
2022-01-31 18:12:55 +00:00
|
|
|
auto* memory_type_group = new QButtonGroup(this);
|
2017-10-03 16:43:44 +00:00
|
|
|
m_memory_use_address = new QRadioButton(tr("Address"));
|
|
|
|
m_memory_use_address->setChecked(true);
|
2022-01-31 18:12:55 +00:00
|
|
|
memory_type_group->addButton(m_memory_use_address);
|
2018-01-21 15:25:58 +00:00
|
|
|
// i18n: A range of memory addresses
|
2017-10-03 16:43:44 +00:00
|
|
|
m_memory_use_range = new QRadioButton(tr("Range"));
|
2022-01-31 18:12:55 +00:00
|
|
|
memory_type_group->addButton(m_memory_use_range);
|
2017-10-03 16:43:44 +00:00
|
|
|
m_memory_address_from = new QLineEdit;
|
|
|
|
m_memory_address_to = new QLineEdit;
|
|
|
|
m_memory_address_from_label = new QLabel; // Set by OnAddressTypeChanged
|
|
|
|
m_memory_address_to_label = new QLabel(tr("To:"));
|
2018-01-21 15:25:58 +00:00
|
|
|
// i18n: This is a selectable condition when adding a breakpoint
|
2017-10-03 16:43:44 +00:00
|
|
|
m_memory_on_read = new QRadioButton(tr("Read"));
|
2018-01-21 15:25:58 +00:00
|
|
|
// i18n: This is a selectable condition when adding a breakpoint
|
2017-10-03 16:43:44 +00:00
|
|
|
m_memory_on_write = new QRadioButton(tr("Write"));
|
2018-01-21 15:25:58 +00:00
|
|
|
// i18n: This is a selectable condition when adding a breakpoint
|
2017-10-03 16:43:44 +00:00
|
|
|
m_memory_on_read_and_write = new QRadioButton(tr("Read or Write"));
|
|
|
|
m_memory_on_write->setChecked(true);
|
2018-01-21 15:25:58 +00:00
|
|
|
// i18n: This is a selectable action when adding a breakpoint
|
2020-07-06 22:16:32 +00:00
|
|
|
m_do_log = new QRadioButton(tr("Write to Log"));
|
2018-01-21 15:25:58 +00:00
|
|
|
// i18n: This is a selectable action when adding a breakpoint
|
2020-07-06 22:16:32 +00:00
|
|
|
m_do_break = new QRadioButton(tr("Break"));
|
2018-01-21 15:25:58 +00:00
|
|
|
// i18n: This is a selectable action when adding a breakpoint
|
2020-07-06 22:16:32 +00:00
|
|
|
m_do_log_and_break = new QRadioButton(tr("Write to Log and Break"));
|
|
|
|
m_do_log_and_break->setChecked(true);
|
2017-10-03 16:43:44 +00:00
|
|
|
|
|
|
|
auto* memory_layout = new QGridLayout;
|
|
|
|
m_memory_box->setLayout(memory_layout);
|
|
|
|
memory_layout->addWidget(m_memory_use_address, 0, 0);
|
|
|
|
memory_layout->addWidget(m_memory_use_range, 0, 3);
|
|
|
|
memory_layout->addWidget(m_memory_address_from_label, 1, 0);
|
|
|
|
memory_layout->addWidget(m_memory_address_from, 1, 1);
|
|
|
|
memory_layout->addWidget(m_memory_address_to_label, 1, 2);
|
|
|
|
memory_layout->addWidget(m_memory_address_to, 1, 3);
|
2018-01-31 18:28:44 +00:00
|
|
|
QGroupBox* condition_box = new QGroupBox(tr("Condition"));
|
|
|
|
auto* condition_layout = new QHBoxLayout;
|
|
|
|
condition_box->setLayout(condition_layout);
|
|
|
|
|
|
|
|
memory_layout->addWidget(condition_box, 2, 0, 1, -1);
|
|
|
|
condition_layout->addWidget(m_memory_on_read);
|
|
|
|
condition_layout->addWidget(m_memory_on_write);
|
|
|
|
condition_layout->addWidget(m_memory_on_read_and_write);
|
|
|
|
|
|
|
|
QGroupBox* action_box = new QGroupBox(tr("Action"));
|
|
|
|
auto* action_layout = new QHBoxLayout;
|
|
|
|
action_box->setLayout(action_layout);
|
2020-07-06 22:16:32 +00:00
|
|
|
action_layout->addWidget(m_do_log);
|
|
|
|
action_layout->addWidget(m_do_break);
|
|
|
|
action_layout->addWidget(m_do_log_and_break);
|
2017-10-03 16:43:44 +00:00
|
|
|
|
|
|
|
auto* layout = new QVBoxLayout;
|
|
|
|
|
|
|
|
layout->addWidget(m_instruction_bp);
|
|
|
|
layout->addWidget(m_instruction_box);
|
|
|
|
layout->addWidget(m_memory_bp);
|
|
|
|
layout->addWidget(m_memory_box);
|
2020-07-06 22:16:32 +00:00
|
|
|
layout->addWidget(action_box);
|
2017-10-03 16:43:44 +00:00
|
|
|
layout->addWidget(m_buttons);
|
|
|
|
|
|
|
|
setLayout(layout);
|
2021-08-13 08:56:11 +00:00
|
|
|
|
|
|
|
m_instruction_address->setFocus();
|
2017-10-03 16:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NewBreakpointDialog::ConnectWidgets()
|
|
|
|
{
|
|
|
|
connect(m_buttons, &QDialogButtonBox::accepted, this, &NewBreakpointDialog::accept);
|
|
|
|
connect(m_buttons, &QDialogButtonBox::rejected, this, &NewBreakpointDialog::reject);
|
|
|
|
|
|
|
|
connect(m_instruction_bp, &QRadioButton::toggled, this, &NewBreakpointDialog::OnBPTypeChanged);
|
|
|
|
connect(m_memory_bp, &QRadioButton::toggled, this, &NewBreakpointDialog::OnBPTypeChanged);
|
|
|
|
|
|
|
|
connect(m_memory_use_address, &QRadioButton::toggled, this,
|
|
|
|
&NewBreakpointDialog::OnAddressTypeChanged);
|
|
|
|
connect(m_memory_use_range, &QRadioButton::toggled, this,
|
|
|
|
&NewBreakpointDialog::OnAddressTypeChanged);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NewBreakpointDialog::OnBPTypeChanged()
|
|
|
|
{
|
|
|
|
m_instruction_box->setEnabled(m_instruction_bp->isChecked());
|
|
|
|
m_memory_box->setEnabled(m_memory_bp->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
void NewBreakpointDialog::OnAddressTypeChanged()
|
|
|
|
{
|
|
|
|
bool ranged = m_memory_use_range->isChecked();
|
|
|
|
|
|
|
|
m_memory_address_to->setHidden(!ranged);
|
|
|
|
m_memory_address_to_label->setHidden(!ranged);
|
|
|
|
|
|
|
|
m_memory_address_from_label->setText(ranged ? tr("From:") : tr("Address:"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void NewBreakpointDialog::accept()
|
|
|
|
{
|
|
|
|
auto invalid_input = [this](QString field) {
|
2019-03-04 19:49:00 +00:00
|
|
|
ModalMessageBox::critical(this, tr("Error"),
|
|
|
|
tr("Invalid input for the field \"%1\"").arg(field));
|
2017-10-03 16:43:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
bool instruction = m_instruction_bp->isChecked();
|
|
|
|
bool ranged = m_memory_use_range->isChecked();
|
|
|
|
|
|
|
|
// Triggers
|
|
|
|
bool on_read = m_memory_on_read->isChecked() || m_memory_on_read_and_write->isChecked();
|
|
|
|
bool on_write = m_memory_on_write->isChecked() || m_memory_on_read_and_write->isChecked();
|
|
|
|
|
|
|
|
// Actions
|
2020-07-06 22:16:32 +00:00
|
|
|
bool do_log = m_do_log->isChecked() || m_do_log_and_break->isChecked();
|
|
|
|
bool do_break = m_do_break->isChecked() || m_do_log_and_break->isChecked();
|
2017-10-03 16:43:44 +00:00
|
|
|
|
|
|
|
bool good;
|
|
|
|
|
|
|
|
if (instruction)
|
|
|
|
{
|
|
|
|
u32 address = m_instruction_address->text().toUInt(&good, 16);
|
|
|
|
|
|
|
|
if (!good)
|
|
|
|
{
|
2018-01-21 15:25:58 +00:00
|
|
|
invalid_input(tr("Address"));
|
2017-10-03 16:43:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-06 22:16:32 +00:00
|
|
|
m_parent->AddBP(address, false, do_break, do_log);
|
2017-10-03 16:43:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u32 from = m_memory_address_from->text().toUInt(&good, 16);
|
|
|
|
|
|
|
|
if (!good)
|
|
|
|
{
|
2018-01-21 15:25:58 +00:00
|
|
|
invalid_input(ranged ? tr("From") : tr("Address"));
|
2017-10-03 16:43:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ranged)
|
|
|
|
{
|
|
|
|
u32 to = m_memory_address_to->text().toUInt(&good, 16);
|
|
|
|
if (!good)
|
|
|
|
{
|
2018-01-21 15:25:58 +00:00
|
|
|
invalid_input(tr("To"));
|
2017-10-03 16:43:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_parent->AddRangedMBP(from, to, on_read, on_write, do_log, do_break);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_parent->AddAddressMBP(from, on_read, on_write, do_log, do_break);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QDialog::accept();
|
|
|
|
}
|