Merge pull request #20006 from hrydgard/break-reason-refactor

Turn the break reason into an enum, fix some minor issues
This commit is contained in:
Henrik Rydgård 2025-02-19 17:52:09 -06:00 committed by GitHub
commit e365bfb5f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 116 additions and 59 deletions

View file

@ -50,7 +50,7 @@ static std::mutex g_stepMutex;
struct CPUStepCommand {
CPUStepType type;
int stepSize;
const char *reason;
BreakReason reason;
u32 relatedAddr;
bool empty() const {
return type == CPUStepType::None;
@ -58,7 +58,7 @@ struct CPUStepCommand {
void clear() {
type = CPUStepType::None;
stepSize = 0;
reason = "";
reason = BreakReason::None;
relatedAddr = 0;
}
};
@ -80,13 +80,47 @@ volatile bool coreStatePending = false;
static bool powerSaving = false;
static bool g_breakAfterFrame = false;
static std::string g_breakReason;
static BreakReason g_breakReason = BreakReason::None;
static MIPSExceptionInfo g_exceptionInfo;
// This is called on EmuThread before RunLoop.
static bool Core_ProcessStepping(MIPSDebugInterface *cpu);
BreakReason Core_BreakReason() {
return g_breakReason;
}
const char *BreakReasonToString(BreakReason reason) {
switch (reason) {
case BreakReason::None: return "None";
case BreakReason::DebugBreak: return "cpu.debugbreak";
case BreakReason::DebugStep: return "cpu.stepping";
case BreakReason::DebugStepInto: return "cpu.stepInto";
case BreakReason::UIFocus: return "ui.lost_focus";
case BreakReason::AfterFrame: return "frame.after";
case BreakReason::MemoryException: return "memory.exception";
case BreakReason::CpuException: return "cpu.exception";
case BreakReason::BreakInstruction: return "cpu.breakInstruction";
case BreakReason::SavestateLoad: return "savestate.load";
case BreakReason::SavestateSave: return "savestate.save";
case BreakReason::SavestateRewind: return "savestate.rewind";
case BreakReason::SavestateCrash: return "savestate.crash";
case BreakReason::MemoryBreakpoint: return "memory.breakpoint";
case BreakReason::CpuBreakpoint: return "cpu.breakpoint";
case BreakReason::BreakpointUpdate: return "cpu.breakpoint.update";
case BreakReason::MemoryAccess: return "memory.access"; // ???
case BreakReason::JitBranchDebug: return "jit.branchdebug";
case BreakReason::RABreak: return "ra.break";
case BreakReason::BreakOnBoot: return "ui.boot";
case BreakReason::AddBreakpoint: return "cpu.breakpoint.add";
case BreakReason::FrameAdvance: return "ui.frameAdvance";
case BreakReason::UIPause: return "ui.pause";
case BreakReason::HLEDebugBreak: return "hle.step";
default: return "Unknown";
}
}
void Core_SetGraphicsContext(GraphicsContext *ctx) {
PSP_CoreParameter().graphicsContext = ctx;
}
@ -170,6 +204,7 @@ void Core_RunLoopUntil(u64 globalticks) {
mipsr4k.RunLoopUntil(globalticks);
if (g_breakAfterFrame && coreState == CORE_NEXTFRAME) {
g_breakAfterFrame = false;
g_breakReason = BreakReason::AfterFrame;
coreState = CORE_STEPPING_CPU;
}
break; // Will loop around to go to RUNNING_GE or NEXTFRAME, which will exit.
@ -376,7 +411,7 @@ static bool Core_ProcessStepping(MIPSDebugInterface *cpu) {
}
// Free-threaded (hm, possibly except tracing).
void Core_Break(const char *reason, u32 relatedAddress) {
void Core_Break(BreakReason reason, u32 relatedAddress) {
if (coreState != CORE_RUNNING_CPU) {
ERROR_LOG(Log::CPU, "Core_Break only works in the CORE_RUNNING_CPU state");
return;
@ -405,16 +440,12 @@ void Core_Break(const char *reason, u32 relatedAddress) {
g_cpuStepCommand.reason = reason;
g_cpuStepCommand.relatedAddr = relatedAddress;
steppingCounter++;
_assert_msg_(reason != nullptr, "No reason specified for break");
_assert_msg_(reason != BreakReason::None, "No reason specified for break");
Core_UpdateState(CORE_STEPPING_CPU);
}
System_Notify(SystemNotification::DEBUG_MODE_CHANGE);
}
const std::string &Core_BreakReason() {
return g_breakReason;
}
// Free-threaded (or at least should be)
void Core_Resume() {
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
@ -431,6 +462,7 @@ void Core_Resume() {
// Clear the exception if we resume.
Core_ResetException();
coreState = CORE_RUNNING_CPU;
g_breakReason = BreakReason::None;
System_Notify(SystemNotification::DEBUG_MODE_CHANGE);
}
@ -523,7 +555,7 @@ void Core_MemoryException(u32 address, u32 accessSize, u32 pc, MemoryExceptionTy
e.accessSize = accessSize;
e.stackTrace = stackTrace;
e.pc = pc;
Core_Break("memory.exception", address);
Core_Break(BreakReason::MemoryException, address);
}
}
@ -551,7 +583,7 @@ void Core_MemoryExceptionInfo(u32 address, u32 accessSize, u32 pc, MemoryExcepti
e.accessSize = accessSize;
e.stackTrace = stackTrace;
e.pc = pc;
Core_Break("memory.exception", address);
Core_Break(BreakReason::MemoryException, address);
}
}
@ -570,7 +602,7 @@ void Core_ExecException(u32 address, u32 pc, ExecExceptionType type) {
e.pc = pc;
// This just records the closest value that could be useful as reference.
e.ra = currentMIPS->r[MIPS_REG_RA];
Core_Break("cpu.exception", address);
Core_Break(BreakReason::CpuException, address);
}
void Core_BreakException(u32 pc) {
@ -583,7 +615,7 @@ void Core_BreakException(u32 pc) {
e.pc = pc;
if (!g_Config.bIgnoreBadMemAccess) {
Core_Break("cpu.breakInstruction", currentMIPS->pc);
Core_Break(BreakReason::BreakInstruction, currentMIPS->pc);
}
}

View file

@ -44,13 +44,42 @@ enum class CPUStepType {
Frame,
};
// Must be set when breaking.
enum class BreakReason {
None,
DebugBreak,
DebugStep,
DebugStepInto,
UIFocus,
AfterFrame,
MemoryException,
CpuException,
BreakInstruction,
SavestateLoad,
SavestateSave,
SavestateRewind,
SavestateCrash,
MemoryBreakpoint,
CpuBreakpoint,
BreakpointUpdate,
MemoryAccess, // ???
JitBranchDebug,
BreakOnBoot,
RABreak,
AddBreakpoint,
FrameAdvance,
UIPause,
HLEDebugBreak,
};
const char *BreakReasonToString(BreakReason reason);
// Async, called from gui
void Core_Break(const char *reason, u32 relatedAddress = 0);
void Core_Break(BreakReason reason, u32 relatedAddress = 0);
// Resumes execution. Works both when stepping the CPU and the GE.
void Core_Resume();
const std::string &Core_BreakReason();
BreakReason Core_BreakReason();
// This should be called externally.
// Can fail if another step type was requested this frame.
@ -62,7 +91,7 @@ void Core_SwitchToGe(); // Switches from CPU emulation to GE display list execu
// Changes every time we enter stepping.
int Core_GetSteppingCounter();
struct SteppingReason {
const char *reason = nullptr;
BreakReason reason;
u32 relatedAddress = 0;
};
SteppingReason Core_GetSteppingReason();

View file

@ -147,7 +147,7 @@ int RegisterEvent(const char *name, TimedCallback callback) {
void AntiCrashCallback(u64 userdata, int cyclesLate) {
ERROR_LOG(Log::SaveState, "Savestate broken: an unregistered event was called.");
Core_Break("savestate.crash", 0);
Core_Break(BreakReason::SavestateCrash, 0);
}
void RestoreRegisterEvent(int &event_type, const char *name, TimedCallback callback) {

View file

@ -64,7 +64,7 @@ BreakAction MemCheck::Action(u32 addr, bool write, int size, u32 pc, const char
// Conditions have always already been checked if we get here.
Log(addr, write, size, pc, reason);
if ((result & BREAK_ACTION_PAUSE) && coreState != CORE_POWERUP) {
Core_Break("memory.breakpoint", start);
Core_Break(BreakReason::MemoryBreakpoint, start);
}
return result;
@ -316,7 +316,7 @@ BreakAction BreakpointManager::ExecBreakPoint(u32 addr) {
}
}
if ((info.result & BREAK_ACTION_PAUSE) && coreState != CORE_POWERUP) {
Core_Break("cpu.breakpoint", info.addr);
Core_Break(BreakReason::CpuBreakpoint, info.addr);
}
return info.result;
@ -624,7 +624,7 @@ void BreakpointManager::Update(u32 addr) {
if (MIPSComp::jit && addr != -1) {
bool resume = false;
if (Core_IsStepping() == false) {
Core_Break("cpu.breakpoint.update", addr);
Core_Break(BreakReason::BreakpointUpdate, addr);
Core_WaitInactive();
resume = true;
}

View file

@ -72,7 +72,7 @@ void WebSocketCPUStepping(DebuggerRequest &req) {
return req.Fail("CPU not started");
}
if (!Core_IsStepping() && Core_IsActive()) {
Core_Break("cpu.stepping", 0);
Core_Break(BreakReason::DebugStep, 0);
}
}

View file

@ -64,7 +64,7 @@ static AutoDisabledReplacements LockMemoryAndCPU(uint32_t addr, bool keepReplace
if (Core_IsStepping()) {
result.wasStepping = true;
} else {
Core_Break("memory.access", addr);
Core_Break(BreakReason::MemoryAccess, addr);
Core_WaitInactive();
}

View file

@ -33,8 +33,8 @@ struct CPUSteppingEvent {
j.writeUint("pc", currentMIPS->pc);
// A double ought to be good enough for a 156 day debug session.
j.writeFloat("ticks", CoreTiming::GetTicks());
if (reason_.reason) {
j.writeString("reason", reason_.reason);
if (reason_.reason != BreakReason::None) {
j.writeString("reason", BreakReasonToString(reason_.reason));
j.writeUint("relatedAddress", reason_.relatedAddress);
}
j.end();

View file

@ -91,7 +91,7 @@ void WebSocketSteppingState::Into(DebuggerRequest &req) {
if (!currentDebugMIPS->isAlive())
return req.Fail("CPU not started");
if (!Core_IsStepping()) {
Core_Break("cpu.stepInto", 0);
Core_Break(BreakReason::DebugStepInto, 0);
return;
}

View file

@ -404,7 +404,7 @@ static bool hleExecuteDebugBreak(const HLEFunction *func) {
}
INFO_LOG(Log::CPU, "Broke after syscall: %s", func->name);
Core_Break("hle.step", g_syscallPC);
Core_Break(BreakReason::HLEDebugBreak, g_syscallPC);
return true;
}

View file

@ -1003,7 +1003,7 @@ static void RunUntilWithChecks(u64 globalTicks) {
if (hasBPs && g_breakpoints.IsAddressBreakPoint(curMips->pc) && g_breakpoints.CheckSkipFirst() != curMips->pc) {
auto cond = g_breakpoints.GetBreakPointCondition(currentMIPS->pc);
if (!cond || cond->Evaluate()) {
Core_Break("cpu.breakpoint", curMips->pc);
Core_Break(BreakReason::CpuBreakpoint, curMips->pc);
if (g_breakpoints.IsTempBreakPoint(curMips->pc))
g_breakpoints.RemoveBreakPoint(curMips->pc);
break;

View file

@ -109,7 +109,7 @@ static void JitBranchLogMismatch(MIPSOpcode op, u32 pc)
char temp[256];
MIPSDisAsm(op, pc, temp, sizeof(temp), true);
ERROR_LOG(Log::JIT, "Bad jump: %s - int:%08x jit:%08x", temp, currentMIPS->intBranchExit, currentMIPS->jitBranchExit);
Core_Break("jit.branchdebug", pc);
Core_Break(BreakReason::JitBranchDebug, pc);
}
void Jit::BranchLog(MIPSOpcode op)

View file

@ -545,7 +545,7 @@ static void raintegration_event_handler(const rc_client_raintegration_event_t *e
break;
case RC_CLIENT_RAINTEGRATION_EVENT_PAUSE:
// The toolkit has hit a breakpoint and wants to pause the emulator. Do so.
Core_Break("ra_breakpoint");
Core_Break(BreakReason::RABreak);
break;
case RC_CLIENT_RAINTEGRATION_EVENT_HARDCORE_CHANGED:
// Hardcore mode has been changed (either directly by the user, or disabled through the use of the tools).

View file

@ -432,7 +432,7 @@ double g_lastSaveTime = -1.0;
rewindStates.NotifyState();
if (coreState == CoreState::CORE_RUNTIME_ERROR)
Core_Break("savestate.load", 0);
Core_Break(BreakReason::SavestateLoad, 0);
Enqueue(Operation(SAVESTATE_LOAD, filename, slot, callback, cbUserData));
}
@ -444,7 +444,7 @@ double g_lastSaveTime = -1.0;
rewindStates.NotifyState();
if (coreState == CoreState::CORE_RUNTIME_ERROR)
Core_Break("savestate.save", 0);
Core_Break(BreakReason::SavestateSave, 0);
Enqueue(Operation(SAVESTATE_SAVE, filename, slot, callback, cbUserData));
}
@ -459,7 +459,7 @@ double g_lastSaveTime = -1.0;
return;
}
if (coreState == CoreState::CORE_RUNTIME_ERROR)
Core_Break("savestate.rewind", 0);
Core_Break(BreakReason::SavestateRewind, 0);
Enqueue(Operation(SAVESTATE_REWIND, Path(), -1, callback, cbUserData));
}

View file

@ -441,7 +441,7 @@ void OSXOpenURL(const char *url) {
Core_Resume();
item.title = DESKTOPUI_LOCALIZED("Break");
} else {
Core_Break("ui.break", 0);
Core_Break(BreakReason::DebugBreak, 0);
item.title = DEVELOPERUI_LOCALIZED("Resume");
}
}

View file

@ -120,10 +120,9 @@ static void __EmuScreenVblank()
{
auto sy = GetI18NCategory(I18NCat::SYSTEM);
if (frameStep_ && lastNumFlips != gpuStats.numFlips)
{
if (frameStep_ && lastNumFlips != gpuStats.numFlips) {
frameStep_ = false;
Core_Break("ui.frameAdvance", 0);
Core_Break(BreakReason::FrameAdvance, 0);
lastNumFlips = gpuStats.numFlips;
}
#ifndef MOBILE_DEVICE
@ -772,10 +771,10 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
case VIRTKEY_PAUSE_NO_MENU:
if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) {
// We re-use debug break/resume to implement pause/resume without a menu.
if (coreState == CORE_STEPPING_CPU) {
if (coreState == CORE_STEPPING_CPU) { // should we check reason?
Core_Resume();
} else {
Core_Break("user-pause");
Core_Break(BreakReason::UIPause);
}
}
break;
@ -1586,7 +1585,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
Core_Resume();
} else if (!frameStep_) {
lastNumFlips = gpuStats.numFlips;
Core_Break("ui.frameAdvance", 0);
Core_Break(BreakReason::FrameAdvance, 0);
}
}
}

View file

@ -1341,7 +1341,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
break;
case CoreState::CORE_RUNNING_CPU:
if (ImGui::MenuItem("Break")) {
Core_Break("Menu:Break");
Core_Break(BreakReason::DebugBreak);
}
break;
default:
@ -1717,7 +1717,7 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImContro
if (coreState == CORE_STEPPING_GE || coreState == CORE_RUNNING_GE) {
ImGui::Text("!!! Currently stepping the GE");
ImGui::SameLine();
if (ImGui::SmallButton("Open Ge debugger")) {
if (ImGui::SmallButton("Open Ge Debugger")) {
cfg.geDebuggerOpen = true;
ImGui::SetWindowFocus("GE Debugger");
}
@ -1732,7 +1732,7 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImContro
ImGui::SameLine();
ImGui::BeginDisabled(coreState != CORE_RUNNING_CPU);
if (ImGui::SmallButton("Pause")) {
Core_Break("Pause");
Core_Break(BreakReason::DebugBreak);
}
ImGui::EndDisabled();
@ -1838,6 +1838,10 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImContro
disasmView_.scrollAddressIntoView();
}
BreakReason breakReason = Core_BreakReason();
ImGui::SameLine();
ImGui::TextUnformatted(BreakReasonToString(breakReason));
ImVec2 avail = ImGui::GetContentRegionAvail();
avail.y -= ImGui::GetTextLineHeightWithSpacing();

View file

@ -315,10 +315,6 @@ void ImMemView::onChar(int c) {
return;
}
bool active = Core_IsActive();
if (active)
Core_Break("memory.access", curAddress_);
if (asciiSelected_) {
Memory::WriteUnchecked_U8((u8)c, curAddress_);
ScrollCursor(1, GotoMode::RESET);
@ -341,8 +337,6 @@ void ImMemView::onChar(int c) {
}
Reporting::NotifyDebugger();
if (active)
Core_Resume();
}
ImMemView::GotoMode ImMemView::GotoModeFromModifiers(bool isRightClick) {

View file

@ -430,7 +430,7 @@ void CtrlMemView::onChar(WPARAM wParam, LPARAM lParam) {
bool active = Core_IsActive();
if (active)
Core_Break("memory.access", curAddress_);
Core_Break(BreakReason::MemoryAccess, curAddress_);
if (asciiSelected_) {
Memory::WriteUnchecked_U8((u8)wParam, curAddress_);

View file

@ -299,9 +299,8 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
keepStatusBarText = true;
view->LockPosition();
bool isRunning = Core_IsActive();
if (isRunning)
{
Core_Break("cpu.breakpoint.add", 0);
if (isRunning) {
Core_Break(BreakReason::AddBreakpoint, 0);
Core_WaitInactive();
}
@ -401,10 +400,9 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
}
if (!Core_IsStepping()) { // stop
ptr->setDontRedraw(false);
Core_Break("ui.break", 0);
Core_Break(BreakReason::DebugBreak, 0);
} else { // go
lastTicks_ = CoreTiming::GetTicks();
Core_Resume();
}
}

View file

@ -83,7 +83,7 @@ INT_PTR CALLBACK DumpMemoryWindow::dlgFunc(HWND hwnd, UINT iMsg, WPARAM wParam,
bool priorDumpWasStepping = Core_IsStepping();
if (!priorDumpWasStepping && PSP_IsInited()) {
// If emulator isn't paused force paused state, but wait before locking.
Core_Break("memory.access", bp->start);
Core_Break(BreakReason::MemoryAccess, bp->start);
Core_WaitInactive();
}

View file

@ -919,14 +919,15 @@ namespace MainWindow
} else {
g_activeWindow = WINDOW_OTHER;
}
if (!noFocusPause && g_Config.bPauseOnLostFocus && GetUIState() == UISTATE_INGAME) {
if (pause != Core_IsStepping()) {
if (disasmWindow) {
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
} else {
if (pause) {
Core_Break("ui.lost_focus", 0);
} else if (Core_BreakReason() == "ui.lost_focus") {
Core_Break(BreakReason::UIFocus, 0);
} else if (Core_BreakReason() == BreakReason::UIFocus) {
Core_Resume();
}
}

View file

@ -341,7 +341,7 @@ namespace MainWindow {
if (GetUIState() == UISTATE_INGAME) {
browsePauseAfter = Core_IsStepping();
if (!browsePauseAfter)
Core_Break("ui.boot", 0);
Core_Break(BreakReason::BreakOnBoot, 0);
}
auto mm = GetI18NCategory(I18NCat::MAINMENU);
@ -491,7 +491,7 @@ namespace MainWindow {
if (disasmWindow)
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
else
Core_Break("ui.break", 0);
Core_Break(BreakReason::DebugBreak, 0);
}
noFocusPause = !noFocusPause; // If we pause, override pause on lost focus
break;