diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp index 696ff60d47..7c5b8fb3b8 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp @@ -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 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; diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.h b/Source/Core/DolphinQt/Debugger/CodeViewWidget.h index 3fc78489ba..ad6215d85f 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.h +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.h @@ -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(); diff --git a/Source/Core/DolphinQt/Debugger/CodeWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeWidget.cpp index eedf70a192..e29d999528 100644 --- a/Source/Core/DolphinQt/Debugger/CodeWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeWidget.cpp @@ -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; diff --git a/Source/Core/DolphinQt/Debugger/CodeWidget.h b/Source/Core/DolphinQt/Debugger/CodeWidget.h index bf51db9d59..62f2642222 100644 --- a/Source/Core/DolphinQt/Debugger/CodeWidget.h +++ b/Source/Core/DolphinQt/Debugger/CodeWidget.h @@ -50,6 +50,7 @@ public: void Update(); void UpdateSymbols(); + void ActivateSearchAddress(); signals: void RequestPPCComparison(u32 address, bool translate_address); void ShowMemory(u32 address); diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp index 75cafdd814..2400e93ec5 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp @@ -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; diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h index 29d006f7db..9cf58979ad 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h @@ -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(); diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp index 4d06e74b10..10f9c1a818 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp @@ -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() diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.h b/Source/Core/DolphinQt/Debugger/MemoryWidget.h index 9104e0516c..7b05c0fb60 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.h +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.h @@ -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;