debugger: add more memory writing options

This commit is contained in:
Swift
2026-06-07 18:18:32 -05:00
parent 326933b248
commit 055a5f838f
3 changed files with 229 additions and 22 deletions

View File

@@ -1,5 +1,6 @@
#include "wxgui/wxgui.h"
#include "wxgui/debugger/DumpCtrl.h"
#include "wxgui/helpers/wxHelpers.h"
#include "Cafe/OS/RPL/rpl.h"
#include "Cafe/OS/RPL/rpl_structs.h"
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
@@ -28,6 +29,8 @@ DumpCtrl::DumpCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, c
m_memoryRegion.size = 0x1000;
Init();
}
Bind(wxEVT_MENU, &DumpCtrl::OnMenuSelected, this);
}
void DumpCtrl::Init()
@@ -163,32 +166,47 @@ void DumpCtrl::OnMouseMove(const wxPoint& start_position, uint32 line)
position.x -= OFFSET_MEMORY;
}
uint32 DumpCtrl::PositionToAddress(const wxPoint& position, uint32 line)
{
wxPoint pos = position;
if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE)
return MPTR_NULL;
pos.x -= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE;
if (pos.x > OFFSET_MEMORY)
return MPTR_NULL;
const uint32 byteIndex = (pos.x / m_char_width) / 3;
return LineToOffset(line) + byteIndex;
}
void DumpCtrl::OnMouseDClick(const wxPoint& position, uint32 line)
{
wxPoint pos = position;
if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE)
uint32 address = PositionToAddress(position, line);
if (address == MPTR_NULL)
return;
pos.x -= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE;
if(pos.x <= OFFSET_MEMORY)
if (!memory_isAddressRangeAccessible(address, 1))
return;
if (WriteNumericDialog<uint8>(address))
{
const uint32 byte_index = (pos.x / m_char_width) / 3;
const uint32 offset = LineToOffset(line) + byte_index;
if (!memory_isAddressRangeAccessible(offset, 1))
return;
const uint8 value = memory_readU8(offset);
wxTextEntryDialog set_value_dialog(this, _("Enter a new value."), wxString::Format(_("Set byte at address %08x"), offset), wxString::Format("%02x", value));
if (set_value_dialog.ShowModal() == wxID_OK)
{
const uint8 new_value = std::stoul(set_value_dialog.GetValue().ToStdString(), nullptr, 16);
memory_writeU8(offset, new_value);
wxRect update_rect(0, line * m_line_height, GetSize().x, m_line_height);
RefreshControl(&update_rect);
}
return;
wxRect updateRect(0, line * m_line_height, GetSize().x, m_line_height);
RefreshControl(&updateRect);
}
// const uint8 value = memory_readU8(address);
// wxTextEntryDialog set_value_dialog(this, _("Enter a new value."), wxString::Format(_("Set byte at address %08x"), address), wxString::Format("%02x", value));
// if (set_value_dialog.ShowModal() == wxID_OK)
// {
// const uint8 new_value = std::stoul(set_value_dialog.GetValue().ToStdString(), nullptr, 16);
// memory_writeU8(address, new_value);
// wxRect update_rect(0, line * m_line_height, GetSize().x, m_line_height);
// RefreshControl(&update_rect);
// }
}
void DumpCtrl::GoToAddressDialog()
@@ -264,7 +282,6 @@ uint32 DumpCtrl::OffsetToLine(uint32 offset)
return (offset - m_memoryRegion.baseAddress) / 0x10;
}
void DumpCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position)
{
switch (key_code)
@@ -284,3 +301,157 @@ wxSize DumpCtrl::DoGetBestSize() const
{
return TextList::DoGetBestSize();
}
void DumpCtrl::OnContextMenu(const wxPoint& position, uint32 line)
{
wxPoint pos = position;
if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE)
return;
pos.x -= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE;
if (pos.x > OFFSET_MEMORY)
return;
const uint32 byteIndex = (pos.x / m_char_width) / 3;
const uint32 address = LineToOffset(line) + byteIndex;
if (!memory_isAddressRangeAccessible(address, 1))
return;
m_writerContextAddress = address;
m_writerContextLine = line;
wxMenu menu;
menu.Append(ID_WRITE_U8, "Write Byte");
menu.Append(ID_WRITE_U16, "Write Int16");
menu.Append(ID_WRITE_U32, "Write Int32");
menu.Append(ID_WRITE_FLOAT, "Write Float");
menu.Append(ID_WRITE_STRING, "Write String");
PopupMenu(&menu);
}
void DumpCtrl::OnMenuSelected(wxCommandEvent& event)
{
bool update = false;
switch (event.GetId())
{
case ID_WRITE_U8:
update = WriteNumericDialog<uint8>(m_writerContextAddress);
break;
case ID_WRITE_U16:
update = WriteNumericDialog<uint16>(m_writerContextAddress);
break;
case ID_WRITE_U32:
update = WriteNumericDialog<uint32>(m_writerContextAddress);
break;
case ID_WRITE_FLOAT:
update = WriteNumericDialog<float>(m_writerContextAddress);
break;
case ID_WRITE_STRING:
update = WriteString(m_writerContextAddress);
break;
}
if (update)
{
wxRect updateRect(0, m_writerContextLine * m_line_height, GetSize().x, m_line_height);
RefreshControl(&updateRect);
}
}
template <typename T>
bool DumpCtrl::WriteNumericDialog(uint32 address)
{
static_assert(
std::is_same<T, uint8>::value ||
std::is_same<T, uint16>::value ||
std::is_same<T, uint32>::value ||
std::is_same<T, float>::value,
"Unsupported type"
);
T value;
const char* dataType;
wxString label;
if constexpr (std::is_same<T, uint8>::value)
{
value = memory_readU8(address);
dataType = "byte";
label = wxString::Format("0x%02x", value);
}
else if constexpr (std::is_same<T, uint16>::value)
{
value = memory_readU16(address);
dataType = "int16";
label = wxString::Format("0x%04x", value);
}
else if constexpr (std::is_same<T, uint32>::value)
{
value = memory_readU32(address);
dataType = "int32";
label = wxString::Format("0x%08x", value);
}
else if constexpr (std::is_same<T, float>::value)
{
value = memory_readFloat(address);
dataType = "float";
label = wxString::Format("%f", value);
}
wxTextEntryDialog dialog(
this,
_("Enter a new value."),
wxString::Format(_("Write %s at address 0x%08x"), dataType, address),
label
);
if (dialog.ShowModal() != wxID_OK)
return false;
const std::optional<T> opt = parse_numeric<T>(dialog.GetValue());
if (!opt.has_value())
{
wxMessageBox(_("Invalid value."), _("Error"), wxOK | wxICON_ERROR, this);
return false;
}
if constexpr (std::is_same<T, uint8>::value)
memory_writeU8(address, opt.value());
else if constexpr (std::is_same<T, uint16>::value)
memory_writeU16(address, opt.value());
else if constexpr (std::is_same<T, uint32>::value)
memory_writeU32(address, opt.value());
else if constexpr (std::is_same<T, float>::value)
memory_writeFloat(address, opt.value());
return true;
}
bool DumpCtrl::WriteString(uint32 address)
{
wxTextEntryDialog dialog(
this,
_("Enter string"),
wxString::Format(_("Write string at address 0x%08x"), address),
""
);
if (dialog.ShowModal() != wxID_OK)
return false;
std::string text = dialog.GetValue().ToStdString();
for (size_t i = 0; i < text.size(); i++)
memory_writeU8(address + i, static_cast<uint8>(text[i]));
// null-terminator
memory_writeU8(address + text.size(), 0);
return true;
}

View File

@@ -2,6 +2,14 @@
#include "wxgui/components/TextList.h"
enum {
ID_WRITE_U8 = wxID_HIGHEST + 1,
ID_WRITE_U16,
ID_WRITE_U32,
ID_WRITE_FLOAT,
ID_WRITE_STRING
};
class DumpCtrl : public TextList
{
public:
@@ -15,11 +23,18 @@ protected:
void CenterOffset(uint32 offset);
uint32 LineToOffset(uint32 line);
uint32 OffsetToLine(uint32 offset);
uint32 PositionToAddress(const wxPoint& position, uint32 line);
void OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position) override;
void OnMouseMove(const wxPoint& position, uint32 line) override;
void OnMouseDClick(const wxPoint& position, uint32 line) override;
void OnKeyPressed(sint32 key_code, const wxPoint& position) override;
void OnContextMenu(const wxPoint& position, uint32 line) override;
void OnMenuSelected(wxCommandEvent& event);
template <typename T>
bool WriteNumericDialog(uint32 address);
bool WriteString(uint32 address);
private:
struct
{
@@ -27,4 +42,6 @@ private:
uint32 size;
}m_memoryRegion;
uint32 m_lastGotoOffset{0};
uint32 m_writerContextAddress {0};
uint32 m_writerContextLine {0};
};

View File

@@ -5,6 +5,8 @@
#include <wx/listbase.h>
#include <wx/string.h>
#include <concepts>
template <>
struct fmt::formatter<wxString> : formatter<string_view>
{
@@ -106,3 +108,20 @@ void update_slider_text(wxCommandEvent& event, const wxFormatString& format = "%
uint32 fix_raw_keycode(uint32 keycode, uint32 raw_flags);
WindowSystem::WindowHandleInfo initHandleContextFromWxWidgetsWindow(wxWindow* wxw);
template <typename T>
std::optional<T> parse_numeric(const wxString& text)
{
try
{
if (std::is_same<T, float>::value)
return std::stof(text.ToStdString());
// it's integral
return static_cast<T>(std::stol(text.ToStdString(), nullptr, 0));
}
catch (...)
{
return std::nullopt;
}
}