mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-04 05:04:33 +00:00
CPU: Add Host::ReportDebuggerEvent()
And replace the old ReportDebuggerMessage(). Fixes breakpoint hit counts not updating in UI.
This commit is contained in:
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)>;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user