Debugger quality of life improvements

- CTRL+G in code view or memory view toggles address box, comparable with other debuggers
- Memory search box alignment option
- Memory search auto breakpoint setting helping search for large number of constants in memory and associated code: 0x41f00000 for example
- Disassembler copy whole line option in the right click menu copying address, code and memory pointed to in clipboard all in one go making it easier to research and document
This commit is contained in:
Nitch2024 2025-03-25 17:42:49 -07:00
parent 1981f22228
commit c519875d41
8 changed files with 124 additions and 9 deletions

View file

@ -578,6 +578,8 @@ void CodeViewWidget::OnContextMenu()
menu->addAction(tr("Copy &Function"), this, &CodeViewWidget::OnCopyFunction);
auto* copy_line_action =
menu->addAction(tr("Copy Code &Line"), this, &CodeViewWidget::OnCopyCode);
auto* copy_whole_line_action =
menu->addAction(tr("Copy &Whole Line"), this, &CodeViewWidget::OnCopyWholeLine);
auto* copy_hex_action = menu->addAction(tr("Copy &Hex"), this, &CodeViewWidget::OnCopyHex);
menu->addAction(tr("Show in &Memory"), this, &CodeViewWidget::OnShowInMemory);
@ -646,7 +648,7 @@ void CodeViewWidget::OnContextMenu()
follow_branch_action->setEnabled(follow_branch_enabled);
for (auto* action :
{copy_address_action, copy_line_action, copy_hex_action, function_action, run_to_action,
{copy_address_action, copy_line_action, copy_whole_line_action, copy_hex_action, function_action, run_to_action,
ppc_action, insert_blr_action, insert_nop_action, replace_action, assemble_action})
{
action->setEnabled(running);
@ -826,6 +828,34 @@ void CodeViewWidget::OnCopyCode()
QApplication::clipboard()->setText(QString::fromStdString(text));
}
void CodeViewWidget::OnCopyWholeLine()
{
const u32 addr = GetContextAddress();
const QString textAddress = QStringLiteral("%1").arg(addr, 8, 16, QLatin1Char('0'));
const std::string textCode = [this, addr] {
Core::CPUThreadGuard guard(m_system);
return m_system.GetPowerPC().GetDebugInterface().Disassemble(&guard, addr);
}();
QString textTarget = QStringLiteral( "" );
if (IsInstructionLoadStore(textCode))
{
const std::optional<u32> target_addr =
m_system.GetPowerPC().GetDebugInterface().GetMemoryAddressFromInstruction(textCode);
if (target_addr)
{
textTarget = QStringLiteral(" targetting ") + QStringLiteral("%1").arg(*target_addr, 8, 16, QLatin1Char('0'));
}
}
QApplication::clipboard()->setText(textAddress + QString::fromStdString(std::string(" ")) +
QString::fromStdString(textCode) + textTarget );
}
void CodeViewWidget::OnCopyFunction()
{
const u32 address = GetContextAddress();
@ -1085,6 +1115,11 @@ void CodeViewWidget::keyPressEvent(QKeyEvent* event)
m_address += rowCount() * sizeof(u32);
Update();
return;
case Qt::Key_G:
if (event->modifiers() == Qt::ControlModifier)
{
emit ActivateSearch();
}
default:
QWidget::keyPressEvent(event);
break;

View file

@ -58,6 +58,7 @@ signals:
void RequestPPCComparison(u32 address, bool translate_address);
void ShowMemory(u32 address);
void UpdateCodeWidget();
void ActivateSearch();
private:
enum class ReplaceWith
@ -85,6 +86,7 @@ private:
void OnShowTargetInMemory();
void OnCopyFunction();
void OnCopyCode();
void OnCopyWholeLine();
void OnCopyHex();
void OnRenameSymbol();
void OnSelectionChanged();

View file

@ -208,6 +208,7 @@ void CodeWidget::ConnectWidgets()
connect(Host::GetInstance(), &Host::PPCSymbolsChanged, this, &CodeWidget::OnPPCSymbolsChanged);
connect(m_code_view, &CodeViewWidget::UpdateCodeWidget, this, &CodeWidget::Update);
connect(m_code_view, &CodeViewWidget::ActivateSearch, this, &CodeWidget::ActivateSearchAddress);
connect(m_code_view, &CodeViewWidget::RequestPPCComparison, this,
&CodeWidget::RequestPPCComparison);
@ -243,6 +244,11 @@ void CodeWidget::OnPPCSymbolsChanged()
}
}
void CodeWidget::ActivateSearchAddress()
{
m_search_address->setFocus();
}
void CodeWidget::OnSearchAddress()
{
bool good = true;

View file

@ -50,6 +50,7 @@ public:
void Update();
void UpdateSymbols();
void ActivateSearchAddress();
signals:
void RequestPPCComparison(u32 address, bool translate_address);
void ShowMemory(u32 address);

View file

@ -123,6 +123,11 @@ public:
case Qt::Key_PageDown:
m_view->m_address += this->rowCount() * m_view->m_bytes_per_row;
break;
case Qt::Key_G:
if (event->modifiers() == Qt::ControlModifier)
{
m_view->TriggerActivateSearch();
}
default:
QWidget::keyPressEvent(event);
return;
@ -252,6 +257,11 @@ void MemoryViewWidget::UpdateFont(const QFont& font)
UpdateDispatcher(UpdateType::Full);
}
void MemoryViewWidget::TriggerActivateSearch()
{
emit ActivateSearch();
}
constexpr int GetTypeSize(MemoryViewWidget::Type type)
{
switch (type)
@ -973,6 +983,11 @@ void MemoryViewWidget::SetAddress(u32 address)
UpdateDispatcher(UpdateType::Addresses);
}
u32 MemoryViewWidget::GetAddress()
{
return m_address;
}
void MemoryViewWidget::SetBPLoggingEnabled(bool enabled)
{
m_do_log = enabled;

View file

@ -97,6 +97,7 @@ public:
void SetHighlightColor();
void SetBPType(BPType type);
void SetAddress(u32 address);
u32 GetAddress();
void SetFocus() const;
void SetBPLoggingEnabled(bool enabled);
@ -105,12 +106,14 @@ signals:
void AutoUpdate();
void ShowCode(u32 address);
void RequestWatch(QString name, u32 address);
void ActivateSearch();
private:
void OnContextMenu(const QPoint& pos);
void OnCopyAddress(u32 addr);
void OnCopyHex(u32 addr);
void UpdateBreakpointTags();
void TriggerActivateSearch();
void UpdateColumns();
void ScrollbarActionTriggered(int action);
void ScrollbarSliderReleased();

View file

@ -31,6 +31,8 @@
#include "Common/IOFile.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/PowerPC/BreakPoints.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/HW/AddressSpace.h"
#include "Core/System.h"
#include "DolphinQt/Debugger/MemoryViewWidget.h"
@ -73,6 +75,7 @@ MemoryWidget::MemoryWidget(Core::System& system, QWidget* parent)
else
RemoveAfterFrameEventCallback();
});
LoadSettings();
ConnectWidgets();
@ -156,10 +159,26 @@ void MemoryWidget::CreateWidgets()
m_find_next = new QPushButton(tr("Find &Next"));
m_find_previous = new QPushButton(tr("Find &Previous"));
m_find_align = new QComboBox;
m_find_align->addItem(tr("No alignment"), 0);
m_find_align->addItem(tr("2 Bytes"), 2);
m_find_align->addItem(tr("4 Bytes"), 4);
m_find_align->addItem(tr("8 Bytes"), 8);
m_find_align->addItem(tr("16 Bytes"), 16);
m_result_label = new QLabel;
auto* search_bp_group = new QHBoxLayout;
auto *auto_bp_label = new QLabel(tr("Auto BP"));
m_find_auto_mem_bp = new QCheckBox(tr("Mem"));
m_find_auto_code_bp = new QCheckBox(tr("Code"));
search_bp_group->addWidget(auto_bp_label);
search_bp_group->addWidget(m_find_auto_mem_bp);
search_bp_group->addWidget(m_find_auto_code_bp);
search_layout->addWidget(m_find_next);
search_layout->addWidget(m_find_previous);
search_layout->addWidget(m_find_align);
search_layout->addLayout(search_bp_group);
search_layout->addWidget(m_result_label);
search_layout->setSpacing(1);
@ -347,11 +366,13 @@ void MemoryWidget::ConnectWidgets()
{
connect(radio, &QRadioButton::toggled, this, &MemoryWidget::OnAddressSpaceChanged);
}
for (auto* combo : {m_display_combo, m_align_combo, m_row_length_combo})
for (auto* combo : {m_display_combo, m_align_combo, m_row_length_combo, m_find_align })
{
connect(combo, &QComboBox::currentIndexChanged, this, &MemoryWidget::OnDisplayChanged);
}
connect(m_find_auto_mem_bp, &QCheckBox::toggled, this, &MemoryWidget::OnDisplayChanged);
connect(m_find_auto_code_bp, &QCheckBox::toggled, this, &MemoryWidget::OnDisplayChanged);
connect(m_dual_check, &QCheckBox::toggled, this, &MemoryWidget::OnDisplayChanged);
for (auto* radio : {m_bp_read_write, m_bp_read_only, m_bp_write_only})
@ -361,6 +382,8 @@ void MemoryWidget::ConnectWidgets()
connect(m_bp_log_check, &QCheckBox::toggled, this, &MemoryWidget::OnBPLogChanged);
connect(m_memory_view, &MemoryViewWidget::ShowCode, this, &MemoryWidget::ShowCode);
connect(m_memory_view, &MemoryViewWidget::RequestWatch, this, &MemoryWidget::RequestWatch);
connect(m_memory_view, &MemoryViewWidget::ActivateSearch, this, &MemoryWidget::ActivateSearchAddress);
}
void MemoryWidget::closeEvent(QCloseEvent*)
@ -565,6 +588,11 @@ void MemoryWidget::SetAddress(u32 address)
m_memory_view->setFocus();
}
void MemoryWidget::ActivateSearchAddress()
{
m_search_address->setFocus();
}
void MemoryWidget::OnSearchAddress()
{
const auto target_addr = GetTargetAddress();
@ -849,20 +877,20 @@ MemoryWidget::TargetAddress MemoryWidget::GetTargetAddress() const
return target;
}
void MemoryWidget::FindValue(bool next)
bool MemoryWidget::FindValue(bool next)
{
auto target_addr = GetTargetAddress();
if (!target_addr.is_good_address)
{
m_result_label->setText(tr("Bad address provided."));
return;
return false;
}
if (!target_addr.is_good_offset)
{
m_result_label->setText(tr("Bad offset provided."));
return;
return false;
}
const QByteArray search_for = GetInputData();
@ -870,7 +898,7 @@ void MemoryWidget::FindValue(bool next)
if (search_for.isEmpty())
{
m_result_label->setText(tr("Bad Value Given"));
return;
return false;
}
if (!m_search_address->currentText().isEmpty())
@ -900,15 +928,35 @@ void MemoryWidget::FindValue(bool next)
m_memory_view->SetAddress(offset);
return;
return true;
}
m_result_label->setText(tr("No Match"));
return false;
}
void MemoryWidget::OnFindNextValue()
{
FindValue(true);
int alignment = m_find_align->currentData().toInt();
bool set_mem_bp = m_find_auto_mem_bp->isChecked();
bool set_code_bp = m_find_auto_code_bp->isChecked();
while (FindValue(true))
{
if ((alignment == 0) || ((m_memory_view->GetAddress() & (alignment - 1)) == 0))
{
if (set_mem_bp)
{
m_memory_view->ToggleBreakpoint(m_memory_view->GetAddress(), false);
}
if (set_code_bp && ( 4 <= alignment ) )
{
m_system.GetPowerPC().GetBreakPoints().ToggleBreakPoint(m_memory_view->GetAddress());
emit Host::GetInstance()->PPCBreakpointsChanged();
}
break;
}
}
}
void MemoryWidget::OnFindPreviousValue()

View file

@ -60,6 +60,7 @@ private:
void OnBPTypeChanged();
void OnSearchAddress();
void OnBreakOnAll();
void OnFindNextValue();
void OnFindPreviousValue();
@ -74,7 +75,7 @@ private:
void ValidateAndPreviewInputValue();
QByteArray GetInputData() const;
TargetAddress GetTargetAddress() const;
void FindValue(bool next);
bool FindValue(bool next);
void closeEvent(QCloseEvent*) override;
void hideEvent(QHideEvent* event) override;
@ -82,6 +83,7 @@ private:
void RegisterAfterFrameEventCallback();
void RemoveAfterFrameEventCallback();
void AutoUpdateTable();
void ActivateSearchAddress();
Core::System& m_system;
@ -101,6 +103,9 @@ private:
// Search
QPushButton* m_find_next;
QPushButton* m_find_previous;
QComboBox* m_find_align;
QCheckBox* m_find_auto_mem_bp;
QCheckBox* m_find_auto_code_bp;
QComboBox* m_input_combo;
QLabel* m_result_label;