mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-11 01:08:30 +12:00
316 lines
No EOL
8.3 KiB
C++
316 lines
No EOL
8.3 KiB
C++
#include "gui/wxgui.h"
|
|
#include "gui/debugger/DumpCtrl.h"
|
|
#include "Cafe/OS/RPL/rpl.h"
|
|
#include "Cafe/OS/RPL/rpl_structs.h"
|
|
#include "Cafe/HW/Espresso/Debugger/Debugger.h"
|
|
#include "util/helpers/helpers.h"
|
|
|
|
#include "Cemu/ExpressionParser/ExpressionParser.h"
|
|
|
|
#define COLOR_BLACK 0xFF000000
|
|
#define COLOR_GREY 0xFFA0A0A0
|
|
#define COLOR_WHITE 0xFFFFFFFF
|
|
|
|
#define COLOR_DEBUG_ACTIVE_BP 0xFFFFA0FF
|
|
#define COLOR_DEBUG_ACTIVE 0xFFFFA080
|
|
#define COLOR_DEBUG_BP 0xFF8080FF
|
|
|
|
#define SYNTAX_COLOR_GPR 0xFF000066
|
|
#define SYNTAX_COLOR_FPR 0xFF006666
|
|
#define SYNTAX_COLOR_SPR 0xFF666600
|
|
#define SYNTAX_COLOR_CR 0xFF666600
|
|
#define SYNTAX_COLOR_IMM 0xFF006600
|
|
#define SYNTAX_COLOR_IMM_OFFSET 0xFF006600
|
|
#define SYNTAX_COLOR_CIMM 0xFF880000
|
|
#define SYNTAX_COLOR_PSEUDO 0xFFA0A0A0 // color for pseudo code
|
|
#define SYNTAX_COLOR_SYMBOL 0xFF0000A0 // color for function symbol
|
|
|
|
#define OFFSET_ADDRESS (60)
|
|
#define OFFSET_ADDRESS_RELATIVE (90)
|
|
#define OFFSET_MEMORY (450)
|
|
|
|
#define OFFSET_DISASSEMBLY_OPERAND (80)
|
|
|
|
|
|
DumpCtrl::DumpCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style)
|
|
: TextList(parent, id, pos, size, style)
|
|
{
|
|
MMURange* range = memory_getMMURangeByAddress(0x10000000);
|
|
if (range)
|
|
{
|
|
m_memoryRegion.baseAddress = range->getBase();
|
|
m_memoryRegion.size = range->getSize();
|
|
Init();
|
|
}
|
|
else
|
|
{
|
|
m_memoryRegion.baseAddress = 0x10000000;
|
|
m_memoryRegion.size = 0x1000;
|
|
Init();
|
|
}
|
|
}
|
|
|
|
void DumpCtrl::Init()
|
|
{
|
|
uint32 element_count = m_memoryRegion.size;
|
|
this->SetElementCount(element_count / 0x10);
|
|
Scroll(0, 0);
|
|
RefreshControl();
|
|
}
|
|
|
|
void DumpCtrl::OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position)
|
|
{
|
|
wxPoint position = start_position;
|
|
uint32 endAddr = m_memoryRegion.baseAddress + m_memoryRegion.size;
|
|
RPLModule* currentCodeRPL = RPLLoader_FindModuleByCodeAddr(m_memoryRegion.baseAddress + start);
|
|
RPLModule* currentDataRPL = RPLLoader_FindModuleByDataAddr(m_memoryRegion.baseAddress + start);
|
|
for (sint32 i = 0; i <= count; i++)
|
|
{
|
|
const uint32 virtual_address = m_memoryRegion.baseAddress + (start + i) * 0x10;
|
|
|
|
dc.SetTextForeground(wxColour(COLOR_BLACK));
|
|
dc.DrawText(wxString::Format("%08x", virtual_address), position);
|
|
position.x += OFFSET_ADDRESS;
|
|
|
|
dc.SetTextForeground(wxColour(COLOR_GREY));
|
|
if (currentCodeRPL)
|
|
{
|
|
dc.DrawText(wxString::Format("+0x%-8x", virtual_address - currentCodeRPL->regionMappingBase_text.GetMPTR()), position);
|
|
}
|
|
else if (currentDataRPL)
|
|
{
|
|
dc.DrawText(wxString::Format("+0x%-8x", virtual_address - currentDataRPL->regionMappingBase_data), position);
|
|
}
|
|
else
|
|
{
|
|
dc.DrawText("???", position);
|
|
}
|
|
|
|
position.x += OFFSET_ADDRESS_RELATIVE;
|
|
|
|
sint32 start_width = position.x;
|
|
|
|
if (!memory_isAddressRangeAccessible(virtual_address, 0x10))
|
|
{
|
|
for (sint32 f=0; f<0x10; f++)
|
|
{
|
|
wxPoint p(position);
|
|
WriteText(dc, wxString::Format("?? "), p);
|
|
position.x += (m_char_width * 3);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::array<uint8, 0x10> data;
|
|
memory_readBytes(virtual_address, data);
|
|
for (auto b : data)
|
|
{
|
|
wxPoint p(position);
|
|
WriteText(dc, wxString::Format("%02x ", b), p);
|
|
position.x += (m_char_width * 3);
|
|
}
|
|
position.x = start_width = OFFSET_MEMORY;
|
|
dc.SetTextForeground(wxColour(COLOR_BLACK));
|
|
for (auto b : data)
|
|
{
|
|
if (isprint(b))
|
|
dc.DrawText(wxString::Format("%c ", b), position);
|
|
else
|
|
dc.DrawText(".", position);
|
|
|
|
position.x += m_char_width;
|
|
}
|
|
}
|
|
|
|
// display goto indicator
|
|
if (m_lastGotoOffset >= virtual_address && m_lastGotoOffset < (virtual_address + 16))
|
|
{
|
|
sint32 indicatorX = start_position.x + OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE + (m_lastGotoOffset - virtual_address) * m_char_width * 3;
|
|
wxPoint line1(start_position.x + indicatorX - 2, position.y);
|
|
wxPoint line2(line1.x, line1.y + m_line_height);
|
|
dc.SetPen(*wxRED_PEN);
|
|
dc.DrawLine(line1, line2);
|
|
dc.DrawLine(line1, wxPoint(line1.x + 3, line1.y));
|
|
dc.DrawLine(line2, wxPoint(line2.x + 3, line2.y));
|
|
}
|
|
|
|
NextLine(position, &start_position);
|
|
}
|
|
|
|
// draw vertical separator lines for 4 byte blocks
|
|
sint32 cursorOffsetHexBytes = start_position.x + OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE;
|
|
wxPoint line_from(
|
|
cursorOffsetHexBytes + m_char_width * (3 * 4 - 1) + m_char_width / 2,
|
|
start_position.y
|
|
);
|
|
wxPoint line_to(line_from.x, line_from.y + m_line_height * (count + 1));
|
|
dc.SetPen(*wxLIGHT_GREY_PEN);
|
|
for (sint32 i = 0; i < 3; i++)
|
|
{
|
|
dc.DrawLine(line_from, line_to);
|
|
line_from.x += m_char_width * (3 * 4);
|
|
line_to.x += m_char_width * (3 * 4);
|
|
}
|
|
}
|
|
|
|
void DumpCtrl::OnMouseMove(const wxPoint& start_position, uint32 line)
|
|
{
|
|
wxPoint position = start_position;
|
|
|
|
// address
|
|
if (position.x <= OFFSET_ADDRESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
position.x -= OFFSET_ADDRESS;
|
|
|
|
// relative offset
|
|
if (position.x <= OFFSET_ADDRESS_RELATIVE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
position.x -= OFFSET_ADDRESS_RELATIVE;
|
|
|
|
// byte code
|
|
if (position.x <= OFFSET_MEMORY)
|
|
{
|
|
|
|
}
|
|
|
|
// string view
|
|
position.x -= OFFSET_MEMORY;
|
|
}
|
|
|
|
void DumpCtrl::OnMouseDClick(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)
|
|
{
|
|
const uint32 byte_index = (pos.x / m_char_width) / 3;
|
|
const uint32 offset = LineToOffset(line) + byte_index;
|
|
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;
|
|
}
|
|
}
|
|
|
|
void DumpCtrl::GoToAddressDialog()
|
|
{
|
|
wxTextEntryDialog goto_dialog(this, _("Enter a target address."), _("GoTo address"), wxEmptyString);
|
|
if (goto_dialog.ShowModal() == wxID_OK)
|
|
{
|
|
try
|
|
{
|
|
ExpressionParser parser;
|
|
|
|
auto value = goto_dialog.GetValue().ToStdString();
|
|
std::transform(value.begin(), value.end(), value.begin(), tolower);
|
|
//parser.SetExpr(value);
|
|
|
|
const auto module_count = RPLLoader_GetModuleCount();
|
|
const auto module_list = RPLLoader_GetModuleList();
|
|
|
|
std::vector<double> module_tmp(module_count);
|
|
for (int i = 0; i < module_count; i++)
|
|
{
|
|
const auto module = module_list[i];
|
|
if (module)
|
|
{
|
|
module_tmp[i] = (double)module->regionMappingBase_text.GetMPTR();
|
|
parser.AddConstant(module->moduleName2, module_tmp[i]);
|
|
}
|
|
}
|
|
|
|
double grp_tmp[32];
|
|
PPCSnapshot& ppc_snapshot = debuggerState.debugSession.ppcSnapshot;
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
char var_name[32];
|
|
sprintf(var_name, "r%d", i);
|
|
grp_tmp[i] = ppc_snapshot.gpr[i];
|
|
parser.AddConstant(var_name, grp_tmp[i]);
|
|
}
|
|
|
|
const auto result = (uint32)parser.Evaluate(value);
|
|
debug_printf("goto eval result: %x\n", result);
|
|
m_lastGotoOffset = result;
|
|
CenterOffset(result);
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
wxMessageBox(ex.what(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DumpCtrl::CenterOffset(uint32 offset)
|
|
{
|
|
// check if the offset is valid
|
|
if (!memory_isAddressRangeAccessible(offset, 1))
|
|
return;
|
|
// set region and line
|
|
MMURange* range = memory_getMMURangeByAddress(offset);
|
|
if (m_memoryRegion.baseAddress != range->getBase() || m_memoryRegion.size != range->getSize())
|
|
{
|
|
m_memoryRegion.baseAddress = range->getBase();
|
|
m_memoryRegion.size = range->getSize();
|
|
Init();
|
|
}
|
|
|
|
const sint32 line = OffsetToLine(offset);
|
|
if (line < 0 || line >= (sint32)m_element_count)
|
|
return;
|
|
|
|
DoScroll(0, std::max(0, line - ((sint32)m_elements_visible / 2)));
|
|
|
|
RefreshControl();
|
|
//RefreshLine(line);
|
|
|
|
debug_printf("scroll to %x\n", debuggerState.debugSession.instructionPointer);
|
|
}
|
|
|
|
uint32 DumpCtrl::LineToOffset(uint32 line)
|
|
{
|
|
return m_memoryRegion.baseAddress + line * 0x10;
|
|
}
|
|
|
|
uint32 DumpCtrl::OffsetToLine(uint32 offset)
|
|
{
|
|
return (offset - m_memoryRegion.baseAddress) / 0x10;
|
|
}
|
|
|
|
|
|
void DumpCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position)
|
|
{
|
|
switch (key_code)
|
|
{
|
|
case 'G':
|
|
{
|
|
if (IsKeyDown(WXK_CONTROL))
|
|
{
|
|
GoToAddressDialog();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wxSize DumpCtrl::DoGetBestSize() const
|
|
{
|
|
return TextList::DoGetBestSize();
|
|
} |