Debugger: Added right click context menu to disasm view + small fixes

This commit is contained in:
Exzap 2024-12-15 21:47:05 +01:00
parent adab729f43
commit 6aaad1eb83
6 changed files with 121 additions and 20 deletions

View File

@ -447,6 +447,34 @@ bool debugger_hasPatch(uint32 address)
return false; return false;
} }
void debugger_removePatch(uint32 address)
{
for (sint32 i = 0; i < debuggerState.patches.size(); i++)
{
auto& patch = debuggerState.patches[i];
if (address < patch->address || address >= (patch->address + patch->length))
continue;
MPTR startAddress = patch->address;
MPTR endAddress = patch->address + patch->length;
// remove any breakpoints overlapping with the patch
for (auto& bp : debuggerState.breakpoints)
{
if (bp->address + 4 > startAddress && bp->address < endAddress)
{
bp->enabled = false;
debugger_updateExecutionBreakpoint(bp->address);
}
}
// restore original data
memcpy(MEMPTR<void>(startAddress).GetPtr(), patch->origData.data(), patch->length);
PPCRecompiler_invalidateRange(startAddress, endAddress);
// remove patch
delete patch;
debuggerState.patches.erase(debuggerState.patches.begin() + i);
return;
}
}
void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true) void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true)
{ {
bool isRecEnabled = ppcRecompilerEnabled; bool isRecEnabled = ppcRecompilerEnabled;

View File

@ -114,6 +114,7 @@ void debugger_updateExecutionBreakpoint(uint32 address, bool forceRestore = fals
void debugger_createPatch(uint32 address, std::span<uint8> patchData); void debugger_createPatch(uint32 address, std::span<uint8> patchData);
bool debugger_hasPatch(uint32 address); bool debugger_hasPatch(uint32 address);
void debugger_removePatch(uint32 address);
void debugger_forceBreak(); // force breakpoint at the next possible instruction void debugger_forceBreak(); // force breakpoint at the next possible instruction
bool debugger_isTrapped(); bool debugger_isTrapped();

View File

@ -64,6 +64,7 @@ wxBEGIN_EVENT_TABLE(DebuggerWindow2, wxFrame)
EVT_COMMAND(wxID_ANY, wxEVT_RUN, DebuggerWindow2::OnRunProgram) EVT_COMMAND(wxID_ANY, wxEVT_RUN, DebuggerWindow2::OnRunProgram)
EVT_COMMAND(wxID_ANY, wxEVT_NOTIFY_MODULE_LOADED, DebuggerWindow2::OnNotifyModuleLoaded) EVT_COMMAND(wxID_ANY, wxEVT_NOTIFY_MODULE_LOADED, DebuggerWindow2::OnNotifyModuleLoaded)
EVT_COMMAND(wxID_ANY, wxEVT_NOTIFY_MODULE_UNLOADED, DebuggerWindow2::OnNotifyModuleUnloaded) EVT_COMMAND(wxID_ANY, wxEVT_NOTIFY_MODULE_UNLOADED, DebuggerWindow2::OnNotifyModuleUnloaded)
EVT_COMMAND(wxID_ANY, wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, DebuggerWindow2::OnDisasmCtrlGotoAddress)
// file menu // file menu
EVT_MENU(MENU_ID_FILE_EXIT, DebuggerWindow2::OnExit) EVT_MENU(MENU_ID_FILE_EXIT, DebuggerWindow2::OnExit)
// window // window
@ -383,6 +384,12 @@ void DebuggerWindow2::OnMoveIP(wxCommandEvent& event)
m_disasm_ctrl->CenterOffset(ip); m_disasm_ctrl->CenterOffset(ip);
} }
void DebuggerWindow2::OnDisasmCtrlGotoAddress(wxCommandEvent& event)
{
uint32 address = static_cast<uint32>(event.GetExtraLong());
UpdateModuleLabel(address);
}
void DebuggerWindow2::OnParentMove(const wxPoint& main_position, const wxSize& main_size) void DebuggerWindow2::OnParentMove(const wxPoint& main_position, const wxSize& main_size)
{ {
m_main_position = main_position; m_main_position = main_position;
@ -416,7 +423,7 @@ void DebuggerWindow2::OnNotifyModuleLoaded(wxCommandEvent& event)
void DebuggerWindow2::OnNotifyModuleUnloaded(wxCommandEvent& event) void DebuggerWindow2::OnNotifyModuleUnloaded(wxCommandEvent& event)
{ {
RPLModule* module = (RPLModule*)event.GetClientData(); RPLModule* module = (RPLModule*)event.GetClientData(); // todo - the RPL module is already unloaded at this point. Find a better way to handle this
SaveModuleStorage(module, true); SaveModuleStorage(module, true);
m_module_window->OnGameLoaded(); m_module_window->OnGameLoaded();
m_symbol_window->OnGameLoaded(); m_symbol_window->OnGameLoaded();

View File

@ -86,6 +86,8 @@ private:
void OnMoveIP(wxCommandEvent& event); void OnMoveIP(wxCommandEvent& event);
void OnNotifyModuleLoaded(wxCommandEvent& event); void OnNotifyModuleLoaded(wxCommandEvent& event);
void OnNotifyModuleUnloaded(wxCommandEvent& event); void OnNotifyModuleUnloaded(wxCommandEvent& event);
// events from DisasmCtrl
void OnDisasmCtrlGotoAddress(wxCommandEvent& event);
void CreateMenuBar(); void CreateMenuBar();
void UpdateModuleLabel(uint32 address = 0); void UpdateModuleLabel(uint32 address = 0);

View File

@ -15,6 +15,8 @@
#include "Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h" #include "Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h"
#include <wx/mstream.h> // for wxMemoryInputStream #include <wx/mstream.h> // for wxMemoryInputStream
wxDEFINE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent);
#define MAX_SYMBOL_LEN (120) #define MAX_SYMBOL_LEN (120)
#define COLOR_DEBUG_ACTIVE_BP 0xFFFFA0FF #define COLOR_DEBUG_ACTIVE_BP 0xFFFFA0FF
@ -74,6 +76,8 @@ DisasmCtrl::DisasmCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& po
auto tooltip_sizer = new wxBoxSizer(wxVERTICAL); auto tooltip_sizer = new wxBoxSizer(wxVERTICAL);
tooltip_sizer->Add(new wxStaticText(m_tooltip_window, wxID_ANY, wxEmptyString), 0, wxALL, 5); tooltip_sizer->Add(new wxStaticText(m_tooltip_window, wxID_ANY, wxEmptyString), 0, wxALL, 5);
m_tooltip_window->SetSizer(tooltip_sizer); m_tooltip_window->SetSizer(tooltip_sizer);
Bind(wxEVT_MENU, &DisasmCtrl::OnContextMenuEntryClicked, this, IDContextMenu_ToggleBreakpoint, IDContextMenu_Last);
} }
void DisasmCtrl::Init() void DisasmCtrl::Init()
@ -662,29 +666,67 @@ void DisasmCtrl::CopyToClipboard(std::string text) {
#endif #endif
} }
static uint32 GetUnrelocatedAddress(MPTR address)
{
RPLModule* rplModule = RPLLoader_FindModuleByCodeAddr(address);
if (!rplModule)
return 0;
if (address >= rplModule->regionMappingBase_text.GetMPTR() && address < (rplModule->regionMappingBase_text.GetMPTR() + rplModule->regionSize_text))
return 0x02000000 + (address - rplModule->regionMappingBase_text.GetMPTR());
return 0;
}
void DisasmCtrl::OnContextMenu(const wxPoint& position, uint32 line) void DisasmCtrl::OnContextMenu(const wxPoint& position, uint32 line)
{ {
wxPoint pos = position;
auto optVirtualAddress = LinePixelPosToAddress(position.y - GetViewStart().y * m_line_height); auto optVirtualAddress = LinePixelPosToAddress(position.y - GetViewStart().y * m_line_height);
if (!optVirtualAddress) if (!optVirtualAddress)
return; return;
MPTR virtualAddress = *optVirtualAddress; MPTR virtualAddress = *optVirtualAddress;
m_contextMenuAddress = virtualAddress;
// show dialog
wxMenu menu;
menu.Append(IDContextMenu_ToggleBreakpoint, _("Toggle breakpoint"));
if(debugger_hasPatch(virtualAddress))
menu.Append(IDContextMenu_RestoreOriginalInstructions, _("Restore original instructions"));
menu.AppendSeparator();
menu.Append(IDContextMenu_CopyAddress, _("Copy address"));
uint32 unrelocatedAddress = GetUnrelocatedAddress(virtualAddress);
if (unrelocatedAddress && unrelocatedAddress != virtualAddress)
menu.Append(IDContextMenu_CopyUnrelocatedAddress, _("Copy virtual address (for IDA/Ghidra)"));
PopupMenu(&menu);
}
// address void DisasmCtrl::OnContextMenuEntryClicked(wxCommandEvent& event)
if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE)
{ {
CopyToClipboard(fmt::format("{:#10x}", virtualAddress)); switch(event.GetId())
return; {
case IDContextMenu_ToggleBreakpoint:
{
debugger_toggleExecuteBreakpoint(m_contextMenuAddress);
wxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);
wxPostEvent(this->m_parent, evt);
break;
} }
else if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE + OFFSET_DISASSEMBLY) case IDContextMenu_RestoreOriginalInstructions:
{ {
// double-clicked on disassembly (operation and operand data) debugger_removePatch(m_contextMenuAddress);
return; wxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE); // This also refreshes the disassembly view
wxPostEvent(this->m_parent, evt);
break;
} }
else case IDContextMenu_CopyAddress:
{ {
// comment CopyToClipboard(fmt::format("{:#10x}", m_contextMenuAddress));
return; break;
}
case IDContextMenu_CopyUnrelocatedAddress:
{
uint32 unrelocatedAddress = GetUnrelocatedAddress(m_contextMenuAddress);
CopyToClipboard(fmt::format("{:#10x}", unrelocatedAddress));
break;
}
default:
UNREACHABLE;
} }
} }
@ -722,7 +764,6 @@ std::optional<MPTR> DisasmCtrl::LinePixelPosToAddress(sint32 posY)
if (posY < 0) if (posY < 0)
return std::nullopt; return std::nullopt;
sint32 lineIndex = posY / m_line_height; sint32 lineIndex = posY / m_line_height;
if (lineIndex >= m_lineToAddress.size()) if (lineIndex >= m_lineToAddress.size())
return std::nullopt; return std::nullopt;
@ -751,8 +792,6 @@ void DisasmCtrl::CenterOffset(uint32 offset)
m_active_line = line; m_active_line = line;
RefreshLine(m_active_line); RefreshLine(m_active_line);
debug_printf("scroll to %x\n", debuggerState.debugSession.instructionPointer);
} }
void DisasmCtrl::GoToAddressDialog() void DisasmCtrl::GoToAddressDialog()
@ -765,6 +804,10 @@ void DisasmCtrl::GoToAddressDialog()
auto value = goto_dialog.GetValue().ToStdString(); auto value = goto_dialog.GetValue().ToStdString();
std::transform(value.begin(), value.end(), value.begin(), tolower); std::transform(value.begin(), value.end(), value.begin(), tolower);
// trim any leading spaces
while(!value.empty() && value[0] == ' ')
value.erase(value.begin());
debugger_addParserSymbols(parser); debugger_addParserSymbols(parser);
// try to parse expression as hex value first (it should interpret 1234 as 0x1234, not 1234) // try to parse expression as hex value first (it should interpret 1234 as 0x1234, not 1234)
@ -773,17 +816,24 @@ void DisasmCtrl::GoToAddressDialog()
const auto result = (uint32)parser.Evaluate("0x"+value); const auto result = (uint32)parser.Evaluate("0x"+value);
m_lastGotoTarget = result; m_lastGotoTarget = result;
CenterOffset(result); CenterOffset(result);
wxCommandEvent evt(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS);
evt.SetExtraLong(static_cast<long>(result));
wxPostEvent(GetParent(), evt);
} }
else if (parser.IsConstantExpression(value)) else if (parser.IsConstantExpression(value))
{ {
const auto result = (uint32)parser.Evaluate(value); const auto result = (uint32)parser.Evaluate(value);
m_lastGotoTarget = result; m_lastGotoTarget = result;
CenterOffset(result); CenterOffset(result);
wxCommandEvent evt(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS);
evt.SetExtraLong(static_cast<long>(result));
wxPostEvent(GetParent(), evt);
} }
else else
{ {
try try
{ {
// if not a constant expression (i.e. relying on unknown variables), then evaluating will throw an exception with a detailed error message
const auto _ = (uint32)parser.Evaluate(value); const auto _ = (uint32)parser.Evaluate(value);
} }
catch (const std::exception& ex) catch (const std::exception& ex)

View File

@ -1,9 +1,20 @@
#pragma once #pragma once
#include "gui/components/TextList.h" #include "gui/components/TextList.h"
wxDECLARE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent); // Notify parent that goto address operation completed. Event contains the address that was jumped to.
class DisasmCtrl : public TextList class DisasmCtrl : public TextList
{ {
enum
{
IDContextMenu_ToggleBreakpoint = wxID_HIGHEST + 1,
IDContextMenu_RestoreOriginalInstructions,
IDContextMenu_CopyAddress,
IDContextMenu_CopyUnrelocatedAddress,
IDContextMenu_Last
};
public: public:
DisasmCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style); DisasmCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style);
void Init(); void Init();
@ -26,6 +37,7 @@ protected:
void OnKeyPressed(sint32 key_code, const wxPoint& position) override; void OnKeyPressed(sint32 key_code, const wxPoint& position) override;
void OnMouseDClick(const wxPoint& position, uint32 line) override; void OnMouseDClick(const wxPoint& position, uint32 line) override;
void OnContextMenu(const wxPoint& position, uint32 line) override; void OnContextMenu(const wxPoint& position, uint32 line) override;
void OnContextMenuEntryClicked(wxCommandEvent& event);
bool OnShowTooltip(const wxPoint& position, uint32 line) override; bool OnShowTooltip(const wxPoint& position, uint32 line) override;
void ScrollWindow(int dx, int dy, const wxRect* prect) override; void ScrollWindow(int dx, int dy, const wxRect* prect) override;
@ -40,6 +52,7 @@ private:
sint32 m_mouse_line, m_mouse_line_drawn; sint32 m_mouse_line, m_mouse_line_drawn;
sint32 m_active_line; sint32 m_active_line;
uint32 m_lastGotoTarget{}; uint32 m_lastGotoTarget{};
uint32 m_contextMenuAddress{};
// code region info // code region info
uint32 currentCodeRegionStart; uint32 currentCodeRegionStart;
uint32 currentCodeRegionEnd; uint32 currentCodeRegionEnd;