mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-06 06:51:18 +12:00
264 lines
No EOL
7.3 KiB
C++
264 lines
No EOL
7.3 KiB
C++
#include "gui/wxgui.h"
|
|
#include "gui/debugger/BreakpointWindow.h"
|
|
|
|
#include <sstream>
|
|
|
|
#include "gui/debugger/DebuggerWindow2.h"
|
|
#include "gui/guiWrapper.h"
|
|
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
|
|
|
|
#include "Cemu/ExpressionParser/ExpressionParser.h"
|
|
|
|
enum
|
|
{
|
|
MENU_ID_CREATE_MEM_BP_READ = 1,
|
|
MENU_ID_CREATE_MEM_BP_WRITE,
|
|
|
|
};
|
|
|
|
enum ItemColumns
|
|
{
|
|
ColumnEnabled = 0,
|
|
ColumnAddress,
|
|
ColumnType,
|
|
ColumnComment,
|
|
};
|
|
|
|
BreakpointWindow::BreakpointWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)
|
|
: wxFrame(&parent, wxID_ANY, "Breakpoints", wxDefaultPosition, wxSize(420, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)
|
|
{
|
|
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
|
|
|
|
this->wxWindowBase::SetBackgroundColour(*wxWHITE);
|
|
|
|
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
m_breakpoints = new wxCheckedListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
|
|
|
|
|
|
wxListItem col0;
|
|
col0.SetId(ColumnEnabled);
|
|
col0.SetText(_("On"));
|
|
col0.SetWidth(32);
|
|
m_breakpoints->InsertColumn(ColumnEnabled, col0);
|
|
|
|
wxListItem col1;
|
|
col1.SetId(ColumnAddress);
|
|
col1.SetText(_("Address"));
|
|
col1.SetWidth(75);
|
|
m_breakpoints->InsertColumn(ColumnAddress, col1);
|
|
|
|
wxListItem col2;
|
|
col2.SetId(ColumnType);
|
|
col2.SetText(_("Type"));
|
|
col2.SetWidth(42);
|
|
m_breakpoints->InsertColumn(ColumnType, col2);
|
|
|
|
wxListItem col3;
|
|
col3.SetId(ColumnComment);
|
|
col3.SetText(_("Comment"));
|
|
col3.SetWidth(250);
|
|
m_breakpoints->InsertColumn(ColumnComment, col3);
|
|
|
|
main_sizer->Add(m_breakpoints, 1, wxEXPAND);
|
|
|
|
this->SetSizer(main_sizer);
|
|
this->wxWindowBase::Layout();
|
|
|
|
this->Centre(wxBOTH);
|
|
|
|
if (parent.GetConfig().data().pin_to_main)
|
|
OnMainMove(main_position, main_size);
|
|
|
|
m_breakpoints->Bind(wxEVT_COMMAND_LIST_ITEM_CHECKED, (wxObjectEventFunction)&BreakpointWindow::OnBreakpointToggled, this);
|
|
m_breakpoints->Bind(wxEVT_COMMAND_LIST_ITEM_UNCHECKED, (wxObjectEventFunction)&BreakpointWindow::OnBreakpointToggled, this);
|
|
m_breakpoints->Bind(wxEVT_LEFT_DCLICK, &BreakpointWindow::OnLeftDClick, this);
|
|
m_breakpoints->Bind(wxEVT_RIGHT_DOWN, &BreakpointWindow::OnRightDown, this);
|
|
|
|
OnUpdateView();
|
|
}
|
|
|
|
BreakpointWindow::~BreakpointWindow()
|
|
{
|
|
m_breakpoints->Unbind(wxEVT_COMMAND_LIST_ITEM_CHECKED, (wxObjectEventFunction)&BreakpointWindow::OnBreakpointToggled, this);
|
|
m_breakpoints->Unbind(wxEVT_COMMAND_LIST_ITEM_UNCHECKED, (wxObjectEventFunction)&BreakpointWindow::OnBreakpointToggled, this);
|
|
}
|
|
|
|
void BreakpointWindow::OnMainMove(const wxPoint& main_position, const wxSize& main_size)
|
|
{
|
|
wxSize size(420, 250);
|
|
this->SetSize(size);
|
|
|
|
wxPoint position = main_position;
|
|
position.x -= 420;
|
|
position.y += main_size.y - 250;
|
|
this->SetPosition(position);
|
|
}
|
|
|
|
void BreakpointWindow::OnUpdateView()
|
|
{
|
|
Freeze();
|
|
|
|
m_breakpoints->DeleteAllItems();
|
|
|
|
if (!debuggerState.breakpoints.empty())
|
|
{
|
|
uint32_t i = 0;
|
|
for (const auto bpBase : debuggerState.breakpoints)
|
|
{
|
|
|
|
DebuggerBreakpoint* bp = bpBase;
|
|
while (bp)
|
|
{
|
|
wxListItem item;
|
|
item.SetId(i++);
|
|
|
|
const auto index = m_breakpoints->InsertItem(item);
|
|
m_breakpoints->SetItem(index, ColumnAddress, wxString::Format("%08x", bp->address));
|
|
const char* typeName = "UKN";
|
|
if (bp->bpType == DEBUGGER_BP_T_NORMAL)
|
|
typeName = "X";
|
|
else if (bp->bpType == DEBUGGER_BP_T_ONE_SHOT)
|
|
typeName = "XS";
|
|
else if (bp->bpType == DEBUGGER_BP_T_MEMORY_READ)
|
|
typeName = "R";
|
|
else if (bp->bpType == DEBUGGER_BP_T_MEMORY_WRITE)
|
|
typeName = "W";
|
|
|
|
m_breakpoints->SetItem(index, ColumnType, typeName);
|
|
m_breakpoints->SetItem(index, ColumnComment, bp->comment);
|
|
m_breakpoints->SetItemPtrData(item, (wxUIntPtr)bp);
|
|
m_breakpoints->Check(index, bp->enabled);
|
|
|
|
bp = bp->next;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Thaw();
|
|
}
|
|
|
|
void BreakpointWindow::OnGameLoaded()
|
|
{
|
|
OnUpdateView();
|
|
}
|
|
|
|
void BreakpointWindow::OnBreakpointToggled(wxListEvent& event)
|
|
{
|
|
const int32_t index = event.GetIndex();
|
|
if (0 <= index && index < m_breakpoints->GetItemCount())
|
|
{
|
|
const bool state = m_breakpoints->IsChecked(index);
|
|
wxString line = m_breakpoints->GetItemText(index, ColumnAddress);
|
|
DebuggerBreakpoint* bp = (DebuggerBreakpoint*)m_breakpoints->GetItemData(index);
|
|
const uint32 address = std::stoul(line.c_str().AsChar(), nullptr, 16);
|
|
debugger_toggleBreakpoint(address, state, bp);
|
|
}
|
|
}
|
|
|
|
void BreakpointWindow::OnLeftDClick(wxMouseEvent& event)
|
|
{
|
|
const auto position = event.GetPosition();
|
|
const sint32 index = (position.y / m_breakpoints->GetCharHeight()) - 2;
|
|
if (index < 0 || index >= m_breakpoints->GetItemCount())
|
|
return;
|
|
|
|
sint32 x = position.x;
|
|
const auto enabled_width = m_breakpoints->GetColumnWidth(ColumnEnabled);
|
|
if (x <= enabled_width)
|
|
return;
|
|
|
|
x -= enabled_width;
|
|
const auto address_width = m_breakpoints->GetColumnWidth(ColumnAddress);
|
|
if(x <= address_width)
|
|
{
|
|
const auto item = m_breakpoints->GetItemText(index, ColumnAddress);
|
|
const auto address = std::stoul(item.ToStdString(), nullptr, 16);
|
|
debuggerState.debugSession.instructionPointer = address;
|
|
debuggerWindow_moveIP();
|
|
return;
|
|
}
|
|
|
|
x -= address_width;
|
|
const auto type_width = m_breakpoints->GetColumnWidth(ColumnType);
|
|
if (x <= type_width)
|
|
return;
|
|
|
|
x -= type_width;
|
|
const auto comment_width = m_breakpoints->GetColumnWidth(ColumnComment);
|
|
if(x <= comment_width)
|
|
{
|
|
if (index >= debuggerState.breakpoints.size())
|
|
return;
|
|
|
|
const auto item = m_breakpoints->GetItemText(index, ColumnAddress);
|
|
const auto address = std::stoul(item.ToStdString(), nullptr, 16);
|
|
|
|
auto it = debuggerState.breakpoints.begin();
|
|
std::advance(it, index);
|
|
|
|
wxTextEntryDialog set_value_dialog(this, _("Enter a new comment."), wxString::Format(_("Set comment for breakpoint at address %08x"), address), (*it)->comment);
|
|
if (set_value_dialog.ShowModal() == wxID_OK)
|
|
{
|
|
(*it)->comment = set_value_dialog.GetValue().ToStdWstring();
|
|
m_breakpoints->SetItem(index, ColumnComment, set_value_dialog.GetValue());
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
void BreakpointWindow::OnRightDown(wxMouseEvent& event)
|
|
{
|
|
wxMenu menu;
|
|
|
|
menu.Append(MENU_ID_CREATE_MEM_BP_READ, _("Create memory breakpoint (read)"));
|
|
menu.Append(MENU_ID_CREATE_MEM_BP_WRITE, _("Create memory breakpoint (write)"));
|
|
|
|
menu.Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(BreakpointWindow::OnContextMenuClick), nullptr, this);
|
|
PopupMenu(&menu);
|
|
}
|
|
|
|
void BreakpointWindow::OnContextMenuClick(wxCommandEvent& evt)
|
|
{
|
|
switch (evt.GetId())
|
|
{
|
|
case MENU_ID_CREATE_MEM_BP_READ:
|
|
MemoryBreakpointDialog(false);
|
|
return;
|
|
case MENU_ID_CREATE_MEM_BP_WRITE:
|
|
MemoryBreakpointDialog(true);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void BreakpointWindow::MemoryBreakpointDialog(bool isWrite)
|
|
{
|
|
wxTextEntryDialog goto_dialog(this, _("Enter a memory address"), _("Memory breakpoint"), wxEmptyString);
|
|
if (goto_dialog.ShowModal() == wxID_OK)
|
|
{
|
|
ExpressionParser parser;
|
|
|
|
auto value = goto_dialog.GetValue().ToStdString();
|
|
std::transform(value.begin(), value.end(), value.begin(), tolower);
|
|
|
|
|
|
try
|
|
{
|
|
debugger_addParserSymbols(parser);
|
|
const auto result = (uint32)parser.Evaluate(value);
|
|
debug_printf("goto eval result: %x\n", result);
|
|
|
|
debugger_createMemoryBreakpoint(result, isWrite == false, isWrite == true);
|
|
this->OnUpdateView();
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
//ctx.errorHandler.printError(nullptr, -1, fmt::format("Unexpected error in expression \"{}\"", expressionString));
|
|
//return EXPRESSION_RESOLVE_RESULT::EXPRESSION_ERROR;
|
|
wxMessageBox(e.what(), "Invalid expression");
|
|
}
|
|
|
|
}
|
|
} |