mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-24 16:51:52 +01:00
Debugger: Added right click context menu to disasm view + small fixes
This commit is contained in:
parent
adab729f43
commit
6aaad1eb83
@ -447,6 +447,34 @@ bool debugger_hasPatch(uint32 address)
|
||||
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)
|
||||
{
|
||||
bool isRecEnabled = ppcRecompilerEnabled;
|
||||
|
@ -114,6 +114,7 @@ void debugger_updateExecutionBreakpoint(uint32 address, bool forceRestore = fals
|
||||
|
||||
void debugger_createPatch(uint32 address, std::span<uint8> patchData);
|
||||
bool debugger_hasPatch(uint32 address);
|
||||
void debugger_removePatch(uint32 address);
|
||||
|
||||
void debugger_forceBreak(); // force breakpoint at the next possible instruction
|
||||
bool debugger_isTrapped();
|
||||
|
@ -64,6 +64,7 @@ wxBEGIN_EVENT_TABLE(DebuggerWindow2, wxFrame)
|
||||
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_UNLOADED, DebuggerWindow2::OnNotifyModuleUnloaded)
|
||||
EVT_COMMAND(wxID_ANY, wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, DebuggerWindow2::OnDisasmCtrlGotoAddress)
|
||||
// file menu
|
||||
EVT_MENU(MENU_ID_FILE_EXIT, DebuggerWindow2::OnExit)
|
||||
// window
|
||||
@ -383,6 +384,12 @@ void DebuggerWindow2::OnMoveIP(wxCommandEvent& event)
|
||||
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)
|
||||
{
|
||||
m_main_position = main_position;
|
||||
@ -416,7 +423,7 @@ void DebuggerWindow2::OnNotifyModuleLoaded(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);
|
||||
m_module_window->OnGameLoaded();
|
||||
m_symbol_window->OnGameLoaded();
|
||||
@ -659,7 +666,7 @@ void DebuggerWindow2::CreateMenuBar()
|
||||
|
||||
void DebuggerWindow2::UpdateModuleLabel(uint32 address)
|
||||
{
|
||||
if(address == 0)
|
||||
if (address == 0)
|
||||
address = m_disasm_ctrl->GetViewBaseAddress();
|
||||
|
||||
RPLModule* module = RPLLoader_FindModuleByCodeAddr(address);
|
||||
|
@ -86,6 +86,8 @@ private:
|
||||
void OnMoveIP(wxCommandEvent& event);
|
||||
void OnNotifyModuleLoaded(wxCommandEvent& event);
|
||||
void OnNotifyModuleUnloaded(wxCommandEvent& event);
|
||||
// events from DisasmCtrl
|
||||
void OnDisasmCtrlGotoAddress(wxCommandEvent& event);
|
||||
|
||||
void CreateMenuBar();
|
||||
void UpdateModuleLabel(uint32 address = 0);
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h"
|
||||
#include <wx/mstream.h> // for wxMemoryInputStream
|
||||
|
||||
wxDEFINE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent);
|
||||
|
||||
#define MAX_SYMBOL_LEN (120)
|
||||
|
||||
#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);
|
||||
tooltip_sizer->Add(new wxStaticText(m_tooltip_window, wxID_ANY, wxEmptyString), 0, wxALL, 5);
|
||||
m_tooltip_window->SetSizer(tooltip_sizer);
|
||||
|
||||
Bind(wxEVT_MENU, &DisasmCtrl::OnContextMenuEntryClicked, this, IDContextMenu_ToggleBreakpoint, IDContextMenu_Last);
|
||||
}
|
||||
|
||||
void DisasmCtrl::Init()
|
||||
@ -662,29 +666,67 @@ void DisasmCtrl::CopyToClipboard(std::string text) {
|
||||
#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)
|
||||
{
|
||||
wxPoint pos = position;
|
||||
auto optVirtualAddress = LinePixelPosToAddress(position.y - GetViewStart().y * m_line_height);
|
||||
if (!optVirtualAddress)
|
||||
return;
|
||||
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
|
||||
if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE)
|
||||
void DisasmCtrl::OnContextMenuEntryClicked(wxCommandEvent& event)
|
||||
{
|
||||
switch(event.GetId())
|
||||
{
|
||||
CopyToClipboard(fmt::format("{:#10x}", virtualAddress));
|
||||
return;
|
||||
}
|
||||
else if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE + OFFSET_DISASSEMBLY)
|
||||
{
|
||||
// double-clicked on disassembly (operation and operand data)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// comment
|
||||
return;
|
||||
case IDContextMenu_ToggleBreakpoint:
|
||||
{
|
||||
debugger_toggleExecuteBreakpoint(m_contextMenuAddress);
|
||||
wxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);
|
||||
wxPostEvent(this->m_parent, evt);
|
||||
break;
|
||||
}
|
||||
case IDContextMenu_RestoreOriginalInstructions:
|
||||
{
|
||||
debugger_removePatch(m_contextMenuAddress);
|
||||
wxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE); // This also refreshes the disassembly view
|
||||
wxPostEvent(this->m_parent, evt);
|
||||
break;
|
||||
}
|
||||
case IDContextMenu_CopyAddress:
|
||||
{
|
||||
CopyToClipboard(fmt::format("{:#10x}", m_contextMenuAddress));
|
||||
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)
|
||||
return std::nullopt;
|
||||
|
||||
|
||||
sint32 lineIndex = posY / m_line_height;
|
||||
if (lineIndex >= m_lineToAddress.size())
|
||||
return std::nullopt;
|
||||
@ -751,8 +792,6 @@ void DisasmCtrl::CenterOffset(uint32 offset)
|
||||
|
||||
m_active_line = line;
|
||||
RefreshLine(m_active_line);
|
||||
|
||||
debug_printf("scroll to %x\n", debuggerState.debugSession.instructionPointer);
|
||||
}
|
||||
|
||||
void DisasmCtrl::GoToAddressDialog()
|
||||
@ -765,6 +804,10 @@ void DisasmCtrl::GoToAddressDialog()
|
||||
auto value = goto_dialog.GetValue().ToStdString();
|
||||
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);
|
||||
|
||||
// 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);
|
||||
m_lastGotoTarget = result;
|
||||
CenterOffset(result);
|
||||
wxCommandEvent evt(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS);
|
||||
evt.SetExtraLong(static_cast<long>(result));
|
||||
wxPostEvent(GetParent(), evt);
|
||||
}
|
||||
else if (parser.IsConstantExpression(value))
|
||||
{
|
||||
const auto result = (uint32)parser.Evaluate(value);
|
||||
m_lastGotoTarget = result;
|
||||
CenterOffset(result);
|
||||
wxCommandEvent evt(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS);
|
||||
evt.SetExtraLong(static_cast<long>(result));
|
||||
wxPostEvent(GetParent(), evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
|
@ -1,9 +1,20 @@
|
||||
#pragma once
|
||||
#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
|
||||
{
|
||||
enum
|
||||
{
|
||||
IDContextMenu_ToggleBreakpoint = wxID_HIGHEST + 1,
|
||||
IDContextMenu_RestoreOriginalInstructions,
|
||||
IDContextMenu_CopyAddress,
|
||||
IDContextMenu_CopyUnrelocatedAddress,
|
||||
IDContextMenu_Last
|
||||
};
|
||||
public:
|
||||
|
||||
DisasmCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style);
|
||||
|
||||
void Init();
|
||||
@ -26,6 +37,7 @@ protected:
|
||||
void OnKeyPressed(sint32 key_code, const wxPoint& position) override;
|
||||
void OnMouseDClick(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;
|
||||
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_active_line;
|
||||
uint32 m_lastGotoTarget{};
|
||||
uint32 m_contextMenuAddress{};
|
||||
// code region info
|
||||
uint32 currentCodeRegionStart;
|
||||
uint32 currentCodeRegionEnd;
|
||||
|
Loading…
Reference in New Issue
Block a user