diff options
| author | TryTwo <taolas@gmail.com> | 2022-03-26 14:48:25 -0700 |
|---|---|---|
| committer | TryTwo <taolas@gmail.com> | 2022-10-06 22:17:22 -0700 |
| commit | fb79c04cf1aa95ed4c0d55dc840dafb16319f49b (patch) | |
| tree | 2959af7ec686607380e0b12b2a826fe3cbd8da41 /Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp | |
| parent | 9ca1c0f53349b3a736942ebd1f89f8e70e954a32 (diff) | |
MemoryView auto updateDebugger. Implement base codetrace logic. Add register breakpoints. Add CodeViewWidget autostepping to track a value.Debugger
Diffstat (limited to 'Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp')
| -rw-r--r-- | Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp index 76e43d50ad..886b04da64 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp @@ -12,6 +12,7 @@ #include <QInputDialog> #include <QKeyEvent> #include <QMenu> +#include <QMessageBox> #include <QMouseEvent> #include <QPainter> #include <QResizeEvent> @@ -21,6 +22,7 @@ #include <QWheelEvent> #include "Common/Assert.h" +#include "Common/Debug/CodeTrace.h" #include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" #include "Core/Core.h" @@ -564,6 +566,26 @@ void CodeViewWidget::OnContextMenu() auto* restore_action = menu->addAction(tr("Restore instruction"), this, &CodeViewWidget::OnRestoreInstruction); + QString target; + if (addr == PC && running && Core::GetState() == Core::State::Paused) + { + const std::string line = PowerPC::debug_interface.Disassemble(PC); + const auto target_it = std::find(line.begin(), line.end(), '\t'); + const auto target_end = std::find(target_it, line.end(), ','); + + if (target_it != line.end() && target_end != line.end()) + target = QString::fromStdString(std::string{target_it + 1, target_end}); + } + + auto* run_until_menu = menu->addMenu(tr("Run until (ignoring breakpoints)")); + run_until_menu->addAction(tr("%1's value is hit").arg(target), this, + [this] { AutoStep(CodeTrace::AutoStop::Always); }); + run_until_menu->addAction(tr("%1's value is used").arg(target), this, + [this] { AutoStep(CodeTrace::AutoStop::Used); }); + run_until_menu->addAction(tr("%1's value is changed").arg(target), + [this] { AutoStep(CodeTrace::AutoStop::Changed); }); + + run_until_menu->setEnabled(!target.isEmpty()); follow_branch_action->setEnabled(running && GetBranchFromAddress(addr)); for (auto* action : {copy_address_action, copy_line_action, copy_hex_action, function_action, @@ -587,6 +609,85 @@ void CodeViewWidget::OnContextMenu() Update(); } +void CodeViewWidget::AutoStep(CodeTrace::AutoStop option) +{ + // Autosteps and follows value in the target (left-most) register. The Used and Changed options + // silently follows target through reshuffles in memory and registers and stops on use or update. + + CodeTrace code_trace; + bool repeat = false; + + QMessageBox msgbox(QMessageBox::NoIcon, tr("Run until"), {}, QMessageBox::Cancel); + QPushButton* run_button = msgbox.addButton(tr("Keep Running"), QMessageBox::AcceptRole); + // Not sure if we want default to be cancel. Spacebar can let you quickly continue autostepping if + // Yes. + + do + { + // Run autostep then update codeview + const AutoStepResults results = code_trace.AutoStepping(repeat, option); + emit Host::GetInstance()->UpdateDisasmDialog(); + repeat = true; + + // Invalid instruction, 0 means no step executed. + if (results.count == 0) + return; + + // Status report + if (results.reg_tracked.empty() && results.mem_tracked.empty()) + { + QMessageBox::warning( + this, tr("Overwritten"), + tr("Target value was overwritten by current instruction.\nInstructions executed: %1") + .arg(QString::number(results.count)), + QMessageBox::Cancel); + return; + } + else if (results.timed_out) + { + // Can keep running and try again after a time out. + msgbox.setText( + tr("<font color='#ff0000'>AutoStepping timed out. Current instruction is irrelevant.")); + } + else + { + msgbox.setText(tr("Value tracked to current instruction.")); + } + + // Mem_tracked needs to track each byte individually, so a tracked word-sized value would have + // four entries. The displayed memory list needs to be shortened so it's not a huge list of + // bytes. Assumes adjacent bytes represent a word or half-word and removes the redundant bytes. + std::set<u32> mem_out; + auto iter = results.mem_tracked.begin(); + + while (iter != results.mem_tracked.end()) + { + const u32 address = *iter; + mem_out.insert(address); + + for (u32 i = 1; i <= 3; i++) + { + if (results.mem_tracked.count(address + i)) + iter++; + else + break; + } + + iter++; + } + + const QString msgtext = + tr("Instructions executed: %1\nValue contained in:\nRegisters: %2\nMemory: %3") + .arg(QString::number(results.count)) + .arg(QString::fromStdString(fmt::format("{}", fmt::join(results.reg_tracked, ", ")))) + .arg(QString::fromStdString(fmt::format("{:#x}", fmt::join(mem_out, ", ")))); + + msgbox.setInformativeText(msgtext); + msgbox.exec(); + + } while (msgbox.clickedButton() == (QAbstractButton*)run_button); +} + void CodeViewWidget::OnCopyAddress() { const u32 addr = GetContextAddress(); |
