mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-02-20 07:13:19 -07:00
debugger: Various QoL improvements (#1777)
* Ignore keyboard inputs when debugger is focused * Add workaround for slightly improved multi-thread debugging * debugger: Add interpreter mode switch and log-only memory breakpoints
This commit is contained in:
parent
4fe73a3582
commit
07bdb3454a
@ -208,7 +208,24 @@ void debugger_handleSingleStepException(uint64 dr6)
|
||||
if (catchBP)
|
||||
{
|
||||
PPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();
|
||||
debugger_createCodeBreakpoint(hCPU->instructionPointer + 4, DEBUGGER_BP_T_ONE_SHOT);
|
||||
if (debuggerState.logOnlyMemoryBreakpoints)
|
||||
{
|
||||
float memValueF = memory_readFloat(debuggerState.activeMemoryBreakpoint->address);
|
||||
uint32 memValue = memory_readU32(debuggerState.activeMemoryBreakpoint->address);
|
||||
cemuLog_log(LogType::Force, "[Debugger] 0x{:08X} was read/written! New Value: 0x{:08X} (float {}) IP: {:08X} LR: {:08X}",
|
||||
debuggerState.activeMemoryBreakpoint->address,
|
||||
memValue,
|
||||
memValueF,
|
||||
hCPU->instructionPointer,
|
||||
hCPU->spr.LR
|
||||
);
|
||||
if (cemuLog_advancedPPCLoggingEnabled())
|
||||
DebugLogStackTrace(coreinit::OSGetCurrentThread(), hCPU->gpr[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger_createCodeBreakpoint(hCPU->instructionPointer + 4, DEBUGGER_BP_T_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -543,6 +560,12 @@ void debugger_createPPCStateSnapshot(PPCInterpreter_t* hCPU)
|
||||
|
||||
void debugger_enterTW(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
// Currently, we don't support multiple threads inside the debugger. Spin loop a thread if we already paused for another breakpoint hit.
|
||||
while (debuggerState.debugSession.isTrapped)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
// handle logging points
|
||||
DebuggerBreakpoint* bp = debugger_getFirstBP(hCPU->instructionPointer);
|
||||
bool shouldBreak = debuggerBPChain_hasType(bp, DEBUGGER_BP_T_NORMAL) || debuggerBPChain_hasType(bp, DEBUGGER_BP_T_ONE_SHOT);
|
||||
|
||||
@ -142,6 +142,7 @@ struct PPCSnapshot
|
||||
typedef struct
|
||||
{
|
||||
bool breakOnEntry;
|
||||
bool logOnlyMemoryBreakpoints;
|
||||
// breakpoints
|
||||
std::vector<DebuggerBreakpoint*> breakpoints;
|
||||
std::vector<DebuggerPatch*> patches;
|
||||
|
||||
@ -44,6 +44,7 @@ namespace WindowSystem
|
||||
std::atomic_int32_t restored_pad_width = -1, restored_pad_height = -1;
|
||||
|
||||
std::atomic_bool is_fullscreen;
|
||||
std::atomic_bool debugger_focused;
|
||||
|
||||
void set_keystate(uint32 keycode, bool state)
|
||||
{
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "wxgui/helpers/wxHelpers.h"
|
||||
#include "Cemu/ncrypto/ncrypto.h"
|
||||
#include "wxgui/input/HotkeySettings.h"
|
||||
#include "wxgui/debugger/DebuggerWindow2.h"
|
||||
#include <wx/language.h>
|
||||
|
||||
#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND
|
||||
@ -434,6 +435,30 @@ int CemuApp::FilterEvent(wxEvent& event)
|
||||
g_window_info.set_keystatesup();
|
||||
}
|
||||
|
||||
// track if debugger window or its child windows are focused
|
||||
if (g_debugger_window && (event.GetEventType() == wxEVT_SET_FOCUS || event.GetEventType() == wxEVT_ACTIVATE))
|
||||
{
|
||||
wxWindow* target_window = wxDynamicCast(event.GetEventObject(), wxWindow);
|
||||
|
||||
if (target_window && event.GetEventType() == wxEVT_ACTIVATE && !((wxActivateEvent&)event).GetActive())
|
||||
target_window = nullptr;
|
||||
|
||||
if (target_window)
|
||||
{
|
||||
g_window_info.debugger_focused = false;
|
||||
wxWindow* window_it = target_window;
|
||||
while (window_it)
|
||||
{
|
||||
if (window_it == g_debugger_window) g_window_info.debugger_focused = true;
|
||||
window_it = window_it->GetParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!g_debugger_window)
|
||||
{
|
||||
g_window_info.debugger_focused = false;
|
||||
}
|
||||
|
||||
return wxApp::FilterEvent(event);
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
#include "wxgui/debugger/BreakpointWindow.h"
|
||||
#include "wxgui/debugger/ModuleWindow.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
|
||||
#include "Cemu/Logging/CemuLogging.h"
|
||||
|
||||
#include "resource/embedded/resources.h"
|
||||
|
||||
@ -30,6 +32,8 @@ enum
|
||||
// settings
|
||||
MENU_ID_OPTIONS_PIN_TO_MAINWINDOW,
|
||||
MENU_ID_OPTIONS_BREAK_ON_START,
|
||||
MENU_ID_OPTIONS_LOG_MEMORY_BREAKPOINTS,
|
||||
MENU_ID_OPTIONS_SWITCH_CPU_MODE,
|
||||
// window
|
||||
MENU_ID_WINDOW_REGISTERS,
|
||||
MENU_ID_WINDOW_DUMP,
|
||||
@ -75,12 +79,14 @@ wxBEGIN_EVENT_TABLE(DebuggerWindow2, wxFrame)
|
||||
EVT_MENU_RANGE(MENU_ID_WINDOW_REGISTERS, MENU_ID_WINDOW_MODULE, DebuggerWindow2::OnWindowMenu)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
|
||||
DebuggerWindow2* g_debugger_window;
|
||||
|
||||
void DebuggerConfig::Load(XMLConfigParser& parser)
|
||||
{
|
||||
pin_to_main = parser.get("PinToMainWindow", true);
|
||||
break_on_start = parser.get("break_on_start", true);
|
||||
log_memory_breakpoints = parser.get("log_memory_breakpoints", false);
|
||||
|
||||
auto window_parser = parser.get("Windows");
|
||||
show_register = window_parser.get("Registers", true);
|
||||
@ -95,7 +101,8 @@ void DebuggerConfig::Save(XMLConfigParser& parser)
|
||||
{
|
||||
parser.set("PinToMainWindow", pin_to_main);
|
||||
parser.set("break_on_start", break_on_start);
|
||||
|
||||
parser.set("log_memory_breakpoints", log_memory_breakpoints);
|
||||
|
||||
auto window_parser = parser.set("Windows");
|
||||
window_parser.set("Registers", show_register);
|
||||
window_parser.set("MemoryDump", show_dump);
|
||||
@ -285,6 +292,7 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size)
|
||||
m_config.Load();
|
||||
|
||||
debuggerState.breakOnEntry = m_config.data().break_on_start;
|
||||
debuggerState.logOnlyMemoryBreakpoints = m_config.data().log_memory_breakpoints;
|
||||
|
||||
m_main_position = parent.GetPosition();
|
||||
m_main_size = parent.GetSize();
|
||||
@ -571,6 +579,26 @@ void DebuggerWindow2::OnOptionsInput(wxCommandEvent& event)
|
||||
debuggerState.breakOnEntry = value;
|
||||
break;
|
||||
}
|
||||
case MENU_ID_OPTIONS_LOG_MEMORY_BREAKPOINTS:
|
||||
{
|
||||
const bool value = !m_config.data().log_memory_breakpoints;
|
||||
m_config.data().log_memory_breakpoints = value;
|
||||
debuggerState.logOnlyMemoryBreakpoints = value;
|
||||
break;
|
||||
}
|
||||
case MENU_ID_OPTIONS_SWITCH_CPU_MODE:
|
||||
{
|
||||
if (ppcRecompilerEnabled)
|
||||
{
|
||||
ppcRecompilerEnabled = false;
|
||||
cemuLog_log(LogType::Force, "Debugger: Switched CPU mode to interpreter");
|
||||
}
|
||||
else {
|
||||
ppcRecompilerEnabled = true;
|
||||
cemuLog_log(LogType::Force, "Debugger: Switched CPU mode to recompiler");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -662,6 +690,8 @@ void DebuggerWindow2::CreateMenuBar()
|
||||
wxMenu* options_menu = new wxMenu;
|
||||
options_menu->Append(MENU_ID_OPTIONS_PIN_TO_MAINWINDOW, _("&Pin to main window"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().pin_to_main);
|
||||
options_menu->Append(MENU_ID_OPTIONS_BREAK_ON_START, _("Break on &entry point"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().break_on_start);
|
||||
options_menu->Append(MENU_ID_OPTIONS_LOG_MEMORY_BREAKPOINTS, _("Log only memory breakpoints"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().log_memory_breakpoints);
|
||||
options_menu->Append(MENU_ID_OPTIONS_SWITCH_CPU_MODE, _("Switch to &interpreter CPU mode"), wxEmptyString, wxITEM_CHECK);
|
||||
menu_bar->Append(options_menu, _("&Options"));
|
||||
|
||||
// window
|
||||
|
||||
@ -26,13 +26,16 @@ wxDECLARE_EVENT(wxEVT_NOTIFY_MODULE_LOADED, wxCommandEvent);
|
||||
wxDECLARE_EVENT(wxEVT_NOTIFY_MODULE_UNLOADED, wxCommandEvent);
|
||||
wxDECLARE_EVENT(wxEVT_NOTIFY_GRAPHIC_PACKS_MODIFIED, wxCommandEvent);
|
||||
|
||||
extern class DebuggerWindow2* g_debugger_window;
|
||||
|
||||
struct DebuggerConfig
|
||||
{
|
||||
DebuggerConfig()
|
||||
: pin_to_main(true), break_on_start(true), show_register(true), show_dump(true), show_stack(true), show_breakpoints(true), show_modules(true), show_symbols(true) {}
|
||||
|
||||
: pin_to_main(true), break_on_start(true), log_memory_breakpoints(false), show_register(true), show_dump(true), show_stack(true), show_breakpoints(true), show_modules(true), show_symbols(true) {}
|
||||
|
||||
bool pin_to_main;
|
||||
bool break_on_start;
|
||||
bool log_memory_breakpoints;
|
||||
|
||||
bool show_register;
|
||||
bool show_dump;
|
||||
@ -82,6 +85,7 @@ public:
|
||||
|
||||
bool Show(bool show = true) override;
|
||||
std::wstring GetModuleStoragePath(std::string module_name, uint32_t crc_hash) const;
|
||||
|
||||
private:
|
||||
void OnBreakpointHit(wxCommandEvent& event);
|
||||
void OnRunProgram(wxCommandEvent& event);
|
||||
|
||||
@ -17,6 +17,10 @@ std::string KeyboardController::get_button_name(uint64 button) const
|
||||
ControllerState KeyboardController::raw_state()
|
||||
{
|
||||
ControllerState result{};
|
||||
|
||||
if (WindowSystem::GetWindowInfo().debugger_focused)
|
||||
return result;
|
||||
|
||||
boost::container::small_vector<uint32, 16> pressedKeys;
|
||||
WindowSystem::GetWindowInfo().iter_keystates([&pressedKeys](const std::pair<const uint32, bool>& keyState) { if (keyState.second) pressedKeys.emplace_back(keyState.first); });
|
||||
result.buttons.SetPressedButtons(pressedKeys);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user