CPU: Add Host::ReportDebuggerEvent()

And replace the old ReportDebuggerMessage().

Fixes breakpoint hit counts not updating in UI.
This commit is contained in:
Stenzek
2026-01-07 13:57:28 +10:00
parent 74a8e6653d
commit 54285978cf
9 changed files with 89 additions and 30 deletions

View File

@@ -2276,7 +2276,7 @@ bool CPU::AddBreakpoint(BreakpointType type, VirtualMemoryAddress address, bool
System::InterruptExecution();
if (!auto_clear)
Host::ReportDebuggerMessage(fmt::format("Added breakpoint at 0x{:08X}.", address));
Host::ReportDebuggerEvent(DebuggerEvent::Message, fmt::format("Added breakpoint at 0x{:08X}.", address));
return true;
}
@@ -2303,8 +2303,9 @@ bool CPU::SetBreakpointEnabled(BreakpointType type, VirtualMemoryAddress address
if (it == bplist.end())
return false;
Host::ReportDebuggerMessage(fmt::format("{} {} breakpoint at 0x{:08X}.", enabled ? "Enabled" : "Disabled",
GetBreakpointTypeName(type), address));
Host::ReportDebuggerEvent(DebuggerEvent::Message,
fmt::format("{} {} breakpoint at 0x{:08X}.", enabled ? "Enabled" : "Disabled",
GetBreakpointTypeName(type), address));
it->enabled = enabled;
if (UpdateDebugDispatcherFlag())
@@ -2324,7 +2325,8 @@ bool CPU::RemoveBreakpoint(BreakpointType type, VirtualMemoryAddress address)
if (it == bplist.end())
return false;
Host::ReportDebuggerMessage(fmt::format("Removed {} breakpoint at 0x{:08X}.", GetBreakpointTypeName(type), address));
Host::ReportDebuggerEvent(DebuggerEvent::Message,
fmt::format("Removed {} breakpoint at 0x{:08X}.", GetBreakpointTypeName(type), address));
bplist.erase(it);
if (UpdateDebugDispatcherFlag())
@@ -2358,7 +2360,7 @@ bool CPU::AddStepOverBreakpoint()
if (!IsCallInstruction(inst))
{
Host::ReportDebuggerMessage(fmt::format("0x{:08X} is not a call instruction.", g_state.pc));
Host::ReportDebuggerEvent(DebuggerEvent::Message, fmt::format("0x{:08X} is not a call instruction.", g_state.pc));
return false;
}
@@ -2367,14 +2369,15 @@ bool CPU::AddStepOverBreakpoint()
if (IsBranchInstruction(inst))
{
Host::ReportDebuggerMessage(fmt::format("Can't step over double branch at 0x{:08X}", g_state.pc));
Host::ReportDebuggerEvent(DebuggerEvent::Message,
fmt::format("Can't step over double branch at 0x{:08X}", g_state.pc));
return false;
}
// skip the delay slot
bp_pc += sizeof(Instruction);
Host::ReportDebuggerMessage(fmt::format("Stepping over to 0x{:08X}.", bp_pc));
Host::ReportDebuggerEvent(DebuggerEvent::Message, fmt::format("Stepping over to 0x{:08X}.", bp_pc));
return AddBreakpoint(BreakpointType::Execute, bp_pc, true);
}
@@ -2390,20 +2393,22 @@ bool CPU::AddStepOutBreakpoint(u32 max_instructions_to_search)
Instruction inst;
if (!SafeReadInstruction(ret_pc, &inst.bits))
{
Host::ReportDebuggerMessage(
Host::ReportDebuggerEvent(
DebuggerEvent::Message,
fmt::format("Instruction read failed at {:08X} while searching for function end.", ret_pc));
return false;
}
if (IsReturnInstruction(inst))
{
Host::ReportDebuggerMessage(fmt::format("Stepping out to 0x{:08X}.", ret_pc));
Host::ReportDebuggerEvent(DebuggerEvent::Message, fmt::format("Stepping out to 0x{:08X}.", ret_pc));
return AddBreakpoint(BreakpointType::Execute, ret_pc, true);
}
}
Host::ReportDebuggerMessage(fmt::format("No return instruction found after {} instructions for step-out at {:08X}.",
max_instructions_to_search, g_state.pc));
Host::ReportDebuggerEvent(DebuggerEvent::Message,
fmt::format("No return instruction found after {} instructions for step-out at {:08X}.",
max_instructions_to_search, g_state.pc));
return false;
}
@@ -2450,7 +2455,7 @@ ALWAYS_INLINE_RELEASE bool CPU::CheckBreakpointList(BreakpointType type, Virtual
if (bp.auto_clear)
{
msg.format("Stopped execution at 0x{:08X}.", pc);
Host::ReportDebuggerMessage(msg);
Host::ReportDebuggerEvent(DebuggerEvent::Message, msg);
bplist.erase(bplist.begin() + i);
count--;
UpdateDebugDispatcherFlag();
@@ -2459,7 +2464,7 @@ ALWAYS_INLINE_RELEASE bool CPU::CheckBreakpointList(BreakpointType type, Virtual
{
msg.format("Hit {} breakpoint {} at 0x{:08X}, Hit Count {}.", GetBreakpointTypeName(type), bp.number, address,
bp.hit_count);
Host::ReportDebuggerMessage(msg);
Host::ReportDebuggerEvent(DebuggerEvent::BreakpointHit, msg);
i++;
}

View File

@@ -256,4 +256,18 @@ struct DebuggerRegisterListEntry
inline constexpr u32 NUM_DEBUGGER_REGISTER_LIST_ENTRIES = 103;
extern const std::array<DebuggerRegisterListEntry, NUM_DEBUGGER_REGISTER_LIST_ENTRIES> g_debugger_register_list;
// Debugger events, calls Host::ReportDebuggerEvent()
enum class DebuggerEvent : u8
{
Message,
BreakpointHit,
};
} // namespace CPU
namespace Host {
/// Debugger feedback.
void ReportDebuggerEvent(CPU::DebuggerEvent event, std::string_view message);
} // namespace Host

View File

@@ -37,9 +37,6 @@ std::optional<std::time_t> GetResourceFileTimestamp(std::string_view filename, b
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportErrorAsync(std::string_view title, std::string_view message);
/// Debugger feedback.
void ReportDebuggerMessage(std::string_view message);
/// Displays an asynchronous confirmation on the UI thread, but does not block the caller.
/// The callback may be executed on a different thread. Use RunOnCoreThread() in the callback to ensure safety.
using ConfirmMessageAsyncCallback = std::function<void(bool)>;

View File

@@ -7,6 +7,7 @@
#include "core/bus.h"
#include "core/controller.h"
#include "core/core_private.h"
#include "core/cpu_core.h"
#include "core/fullscreenui.h"
#include "core/fullscreenui_widgets.h"
#include "core/game_list.h"
@@ -331,9 +332,9 @@ void MiniHost::SetDefaultSettings(SettingsInterface& si, bool system, bool contr
}
}
void Host::ReportDebuggerMessage(std::string_view message)
void Host::ReportDebuggerEvent(CPU::DebuggerEvent event, std::string_view message)
{
ERROR_LOG("ReportDebuggerMessage(): {}", message);
ERROR_LOG("ReportDebuggerEvent(): {}", message);
}
std::span<const std::pair<const char*, const char*>> Host::GetAvailableLanguageList()

View File

@@ -12,6 +12,7 @@
#include "core/cpu_core_private.h"
#include "common/assert.h"
#include "common/log.h"
#include <QtCore/QSignalBlocker>
#include <QtGui/QCursor>
@@ -21,6 +22,8 @@
#include "moc_debuggerwindow.cpp"
LOG_CHANNEL(Host);
static constexpr int TIMER_REFRESH_INTERVAL_MS = 100;
DebuggerWindow::DebuggerWindow(QWidget* parent /* = nullptr */)
@@ -61,7 +64,7 @@ void DebuggerWindow::onSystemResumed()
m_ui.actionPause->setChecked(false);
}
void DebuggerWindow::onDebuggerMessageReported(const QString& message)
void DebuggerWindow::reportMessage(const QString& message)
{
m_ui.statusbar->showMessage(message, 0);
}
@@ -457,7 +460,6 @@ void DebuggerWindow::connectSignals()
connect(g_core_thread, &CoreThread::systemResumed, this, &DebuggerWindow::onSystemResumed);
connect(g_core_thread, &CoreThread::systemStarted, this, &DebuggerWindow::onSystemStarted);
connect(g_core_thread, &CoreThread::systemDestroyed, this, &DebuggerWindow::onSystemDestroyed);
connect(g_core_thread, &CoreThread::debuggerMessageReported, this, &DebuggerWindow::onDebuggerMessageReported);
connect(m_ui.actionPause, &QAction::triggered, this, &DebuggerWindow::onPauseActionTriggered);
connect(m_ui.actionRunToCursor, &QAction::triggered, this, &DebuggerWindow::onRunToCursorTriggered);
@@ -726,3 +728,47 @@ void DebuggerWindow::removeBreakpoint(CPU::BreakpointType type, u32 address)
});
});
}
void DebuggerWindow::updateBreakpointHitCounts(const CPU::BreakpointList& bps)
{
for (size_t i = 0; i < bps.size(); i++)
{
const CPU::Breakpoint& bp = bps[i];
QTreeWidgetItem* const item = m_ui.breakpointsWidget->topLevelItem(static_cast<int>(i));
if (!item)
continue;
item->setText(3, QString::asprintf("%u", bp.hit_count));
}
}
void Host::ReportDebuggerEvent(CPU::DebuggerEvent event, std::string_view message)
{
if (event == CPU::DebuggerEvent::Message)
{
if (!message.empty())
return;
INFO_LOG("Debugger message: {}", message);
Host::RunOnUIThread([message = QtUtils::StringViewToQString(message)]() {
DebuggerWindow* const win = g_main_window->getDebuggerWindow();
if (!win)
return;
win->reportMessage(message);
});
}
else if (event == CPU::DebuggerEvent::BreakpointHit)
{
Host::RunOnUIThread([bps = CPU::CopyBreakpointList(), message = QtUtils::StringViewToQString(message)]() {
DebuggerWindow* const win = g_main_window->getDebuggerWindow();
if (!win)
return;
win->updateBreakpointHitCounts(bps);
if (!message.isEmpty())
win->reportMessage(message);
});
}
}

View File

@@ -27,6 +27,9 @@ public:
explicit DebuggerWindow(QWidget* parent = nullptr);
~DebuggerWindow();
void reportMessage(const QString& message);
void updateBreakpointHitCounts(const CPU::BreakpointList& bps);
Q_SIGNALS:
void closed();
@@ -55,7 +58,6 @@ private:
void onSystemDestroyed();
void onSystemPaused();
void onSystemResumed();
void onDebuggerMessageReported(const QString& message);
void timerRefresh();
void refreshAll();

View File

@@ -2552,12 +2552,6 @@ void QtHost::UpdateApplicationLocale(std::string_view language)
}
}
void Host::ReportDebuggerMessage(std::string_view message)
{
INFO_LOG("Debugger message: {}", message);
emit g_core_thread->debuggerMessageReported(QString::fromUtf8(message));
}
InputDeviceListModel::InputDeviceListModel(QObject* parent) : QAbstractListModel(parent)
{
}

View File

@@ -105,7 +105,6 @@ public:
Q_SIGNALS:
void errorReported(const QString& title, const QString& message);
void statusMessage(const QString& message);
void debuggerMessageReported(const QString& message);
void settingsResetToDefault(bool system, bool controller);
void systemStarting();
void systemStarted();

View File

@@ -5,6 +5,7 @@
#include "core/bus.h"
#include "core/controller.h"
#include "core/core_private.h"
#include "core/cpu_core.h"
#include "core/fullscreenui.h"
#include "core/fullscreenui_widgets.h"
#include "core/game_list.h"
@@ -176,9 +177,9 @@ void Host::ConfirmMessageAsync(std::string_view title, std::string_view message,
callback(true);
}
void Host::ReportDebuggerMessage(std::string_view message)
void Host::ReportDebuggerEvent(CPU::DebuggerEvent event, std::string_view message)
{
ERROR_LOG("ReportDebuggerMessage: {}", message);
ERROR_LOG("ReportDebuggerEvent: {}", message);
}
std::span<const std::pair<const char*, const char*>> Host::GetAvailableLanguageList()