mirror of https://github.com/PCSX2/pcsx2.git
debugger: some user-friendly improves in ui
Grouping bytes in debugger memory window, following pointers and history Goto in register view Printing strings in pointer registers Memory view can be resized correctly by ctrl+wheel Improvement in function 5900DebugInterface::isValidAddress
This commit is contained in:
parent
00643dbdfb
commit
7e91eb6616
|
@ -30,6 +30,8 @@ memory view:
|
|||
any overwrite ansi byte
|
||||
left click select byte/nibble
|
||||
right click open context menu
|
||||
ctrl+wheel zoom memory view
|
||||
esc return to previous goto address
|
||||
|
||||
breakpoint list:
|
||||
|
||||
|
|
|
@ -184,6 +184,37 @@ void DebugInterface::resumeCpu()
|
|||
core.Resume();
|
||||
}
|
||||
|
||||
|
||||
char* DebugInterface::stringFromPointer(u32 p)
|
||||
{
|
||||
const int BUFFER_LEN = 25;
|
||||
static char buf[BUFFER_LEN] = { 0 };
|
||||
|
||||
if (!isValidAddress(p))
|
||||
return NULL;
|
||||
|
||||
try {
|
||||
for (u32 i = 0; i < BUFFER_LEN; i++) {
|
||||
char c = read8(p + i);
|
||||
buf[i] = c;
|
||||
|
||||
if (c == 0) {
|
||||
return i > 0 ? buf : NULL;
|
||||
}
|
||||
else if (c < 0x20 || c >= 0x7f) {
|
||||
// non printable character
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception::Ps2Generic&) {
|
||||
return NULL;
|
||||
}
|
||||
buf[BUFFER_LEN - 1] = 0;
|
||||
buf[BUFFER_LEN - 2] = '~';
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest)
|
||||
{
|
||||
MipsExpressionFunctions funcs(this);
|
||||
|
@ -509,33 +540,59 @@ std::string R5900DebugInterface::disasm(u32 address, bool simplify)
|
|||
|
||||
bool R5900DebugInterface::isValidAddress(u32 addr)
|
||||
{
|
||||
// ee can't access the first part of memory.
|
||||
if (addr < 0x80000)
|
||||
return false;
|
||||
|
||||
if (addr >= 0xFFFF8000)
|
||||
return true;
|
||||
|
||||
addr &= 0x7FFFFFFF;
|
||||
u32 lopart = addr & 0xfFFffFF;
|
||||
|
||||
// get rid of ee ram mirrors
|
||||
if ((addr >> 28) == 2 || (addr >> 28) == 3)
|
||||
addr &= ~(0xF << 28);
|
||||
|
||||
// registers
|
||||
if (addr >= 0x10000000 && addr < 0x10010000)
|
||||
return true;
|
||||
if (addr >= 0x12000000 && addr < 0x12001100)
|
||||
return true;
|
||||
switch (addr >> 28)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
// case 3: throw exception (not mapped ?)
|
||||
// [ 0000_8000 - 01FF_FFFF ] RAM
|
||||
// [ 2000_8000 - 21FF_FFFF ] RAM MIRROR
|
||||
// [ 3000_8000 - 31FF_FFFF ] RAM MIRROR
|
||||
if (lopart >= 0x80000 && lopart <= 0x1ffFFff)
|
||||
return !!vtlb_GetPhyPtr(lopart);
|
||||
break;
|
||||
case 1:
|
||||
// [ 1000_0000 - 1000_CFFF ] EE register
|
||||
if (lopart <= 0xcfff)
|
||||
return true;
|
||||
|
||||
// scratchpad
|
||||
if (addr >= 0x70000000 && addr < 0x70004000)
|
||||
return true;
|
||||
// [ 1100_0000 - 1100_FFFF ] VU mem
|
||||
if (lopart >= 0x1000000 && lopart <= 0x100FFff)
|
||||
return true;
|
||||
|
||||
return !(addr & 0x40000000) && vtlb_GetPhyPtr(addr & 0x1FFFFFFF) != NULL;
|
||||
// [ 1200_0000 - 1200_FFFF ] GS regs
|
||||
if (lopart >= 0x2000000 && lopart <= 0x20010ff)
|
||||
return true;
|
||||
|
||||
// [ 1E00_0000 - 1FFF_FFFF ] ROM
|
||||
// if (lopart >= 0xe000000)
|
||||
// return true; throw exception (not mapped ?)
|
||||
break;
|
||||
case 7:
|
||||
// [ 7000_0000 - 7000_3FFF ] Scratchpad
|
||||
if (lopart <= 0x3fff)
|
||||
return true;
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 0xA:
|
||||
case 0xB:
|
||||
// [ 8000_0000 - BFFF_FFFF ] kernel
|
||||
// return true;
|
||||
break;
|
||||
case 0xF:
|
||||
// [ 8000_0000 - BFFF_FFFF ] IOP or kernel stack
|
||||
if (lopart >= 0xfff8000)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
u32 R5900DebugInterface::getCycles()
|
||||
{
|
||||
return cpuRegs.cycle;
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
bool isCpuPaused();
|
||||
void pauseCpu();
|
||||
void resumeCpu();
|
||||
char *stringFromPointer(u32 p);
|
||||
};
|
||||
|
||||
class R5900DebugInterface: public DebugInterface
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <cstring> // string.h under c++
|
||||
#include <cstdio> // stdio.h under c++
|
||||
#include <cstdlib>
|
||||
|
|
|
@ -60,4 +60,4 @@ private:
|
|||
u32 size;
|
||||
char condition[128];
|
||||
PostfixExpression compiledCondition;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <wchar.h>
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE(CtrlMemView, wxWindow)
|
||||
EVT_PAINT(CtrlMemView::paintEvent)
|
||||
EVT_MOUSEWHEEL(CtrlMemView::mouseEvent)
|
||||
|
@ -45,6 +46,12 @@ enum MemoryViewMenuIdentifiers
|
|||
{
|
||||
ID_MEMVIEW_GOTOINDISASM = 1,
|
||||
ID_MEMVIEW_COPYADDRESS,
|
||||
ID_MEMVIEW_FOLLOWADDRESS,
|
||||
ID_MEMVIEW_DISPLAYVALUE_8,
|
||||
ID_MEMVIEW_DISPLAYVALUE_16,
|
||||
ID_MEMVIEW_DISPLAYVALUE_32,
|
||||
ID_MEMVIEW_DISPLAYVALUE_64,
|
||||
ID_MEMVIEW_DISPLAYVALUE_128,
|
||||
ID_MEMVIEW_COPYVALUE_8,
|
||||
ID_MEMVIEW_COPYVALUE_16,
|
||||
ID_MEMVIEW_COPYVALUE_32,
|
||||
|
@ -60,14 +67,14 @@ CtrlMemView::CtrlMemView(wxWindow* parent, DebugInterface* _cpu)
|
|||
charWidth = getDebugFontWidth();
|
||||
windowStart = 0x480000;
|
||||
curAddress = windowStart;
|
||||
rowSize = 16;
|
||||
|
||||
byteGroupSize = 1;
|
||||
|
||||
asciiSelected = false;
|
||||
selectedNibble = 0;
|
||||
rowSize = 16;
|
||||
addressStart = charWidth;
|
||||
hexStart = addressStart + 9*charWidth;
|
||||
asciiStart = hexStart + (rowSize*3+1)*charWidth;
|
||||
|
||||
setRowSize(16);
|
||||
|
||||
#ifdef _WIN32
|
||||
font = wxFont(wxSize(charWidth,rowHeight),wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console");
|
||||
|
@ -81,6 +88,13 @@ CtrlMemView::CtrlMemView(wxWindow* parent, DebugInterface* _cpu)
|
|||
|
||||
menu.Append(ID_MEMVIEW_GOTOINDISASM, L"Go to in Disasm");
|
||||
menu.Append(ID_MEMVIEW_COPYADDRESS, L"Copy address");
|
||||
menu.Append(ID_MEMVIEW_FOLLOWADDRESS, L"Follow address");
|
||||
menu.AppendSeparator();
|
||||
menu.Append(ID_MEMVIEW_DISPLAYVALUE_8, L"Display as 1 byte");
|
||||
menu.Append(ID_MEMVIEW_DISPLAYVALUE_16, L"Display as 2 byte");
|
||||
menu.Append(ID_MEMVIEW_DISPLAYVALUE_32, L"Display as 4 byte");
|
||||
menu.Append(ID_MEMVIEW_DISPLAYVALUE_64, L"Display as 8 byte");
|
||||
menu.Append(ID_MEMVIEW_DISPLAYVALUE_128, L"Display as 16 byte");
|
||||
menu.AppendSeparator();
|
||||
menu.Append(ID_MEMVIEW_COPYVALUE_8, L"Copy Value (8 bit)");
|
||||
menu.Append(ID_MEMVIEW_COPYVALUE_16, L"Copy Value (16 bit)");
|
||||
|
@ -95,6 +109,11 @@ CtrlMemView::CtrlMemView(wxWindow* parent, DebugInterface* _cpu)
|
|||
SetDoubleBuffered(true);
|
||||
}
|
||||
|
||||
void CtrlMemView::setRowSize(int bytesInRow) {
|
||||
rowSize = (std::max(16, std::min(256, bytesInRow)) / 16) * 16;
|
||||
asciiStart = hexStart + (rowSize * 3 + 1)*charWidth;
|
||||
}
|
||||
|
||||
void CtrlMemView::postEvent(wxEventType type, wxString text)
|
||||
{
|
||||
wxCommandEvent event( type, GetId() );
|
||||
|
@ -125,137 +144,167 @@ void CtrlMemView::redraw()
|
|||
render(dc);
|
||||
}
|
||||
|
||||
int CtrlMemView::hexGroupPositionFromIndex(int idx)
|
||||
{
|
||||
int groupPos = idx * charWidth * 2;
|
||||
|
||||
int space = (charWidth / 4);
|
||||
|
||||
// spaces after every byte
|
||||
groupPos += idx * space;
|
||||
|
||||
// spaces after every 2 bytes
|
||||
groupPos += (idx / 2) * space;
|
||||
|
||||
// spaces after every 4 bytes
|
||||
return groupPos + (idx / 4) * space;
|
||||
}
|
||||
|
||||
void CtrlMemView::render(wxDC& dc)
|
||||
{
|
||||
bool hasFocus = wxWindow::FindFocus() == this;
|
||||
int visibleRows = GetClientSize().y/rowHeight;
|
||||
int visibleRows = GetClientSize().y / rowHeight;
|
||||
|
||||
wxColor white = wxColor(0xFFFFFFFF);
|
||||
dc.SetBrush(wxBrush(white));
|
||||
dc.SetPen(wxPen(white));
|
||||
const wxColor COLOR_WHITE = wxColor(0xFFFFFFFF);
|
||||
const wxColor COLOR_BLACK = wxColor(0xFF000000);
|
||||
const wxColor COLOR_SELECTED_BG = wxColor(0xFFFF9933);
|
||||
const wxColor COLOR_SELECTED_INACTIVE_BG = wxColor(0xFFC0C0C0);
|
||||
const wxColor COLOR_ADDRESS = wxColor(0xFF600000);
|
||||
const wxColor COLOR_DELIMETER = wxColor(0xFFC0C0C0);
|
||||
|
||||
int width,height;
|
||||
dc.GetSize(&width,&height);
|
||||
dc.DrawRectangle(0,0,width,height);
|
||||
dc.SetBrush(wxBrush(COLOR_WHITE));
|
||||
dc.SetPen(wxPen(COLOR_WHITE));
|
||||
|
||||
for (int i = 0; i < visibleRows+1; i++)
|
||||
int width, height;
|
||||
dc.GetSize(&width, &height);
|
||||
dc.DrawRectangle(0, 0, width, height);
|
||||
|
||||
const int TEMP_SIZE = 64;
|
||||
wchar_t temp[TEMP_SIZE];
|
||||
|
||||
u32 byteGroupMask = ~(byteGroupSize - 1);
|
||||
bool validCpu = cpu && cpu->isAlive();
|
||||
|
||||
// not hexGroupPositionFromIndex(byteGroupSize), because we dont need space after last symbol;
|
||||
int groupWidth = hexGroupPositionFromIndex(byteGroupSize - 1) + charWidth * 2;
|
||||
|
||||
for (int i = 0; i < visibleRows + 1; i++)
|
||||
{
|
||||
wchar_t temp[32];
|
||||
u32 rowAddress = windowStart + i * rowSize;
|
||||
int rowY = rowHeight * i;
|
||||
|
||||
unsigned int address = windowStart + i*rowSize;
|
||||
int rowY = rowHeight*i;
|
||||
|
||||
swprintf(temp,32,L"%08X",address);
|
||||
swprintf(temp, TEMP_SIZE, L"%08X" , rowAddress);
|
||||
dc.SetFont(font);
|
||||
dc.SetTextForeground(wxColor(0xFF600000));
|
||||
dc.DrawText(temp,addressStart,rowY);
|
||||
dc.SetTextForeground(COLOR_ADDRESS);
|
||||
dc.DrawText(temp, addressStart, rowY);
|
||||
|
||||
u32 memory[4];
|
||||
bool valid = cpu != NULL && cpu->isAlive() && cpu->isValidAddress(address);
|
||||
if (valid)
|
||||
{
|
||||
memory[0] = cpu->read32(address);
|
||||
memory[1] = cpu->read32(address+4);
|
||||
memory[2] = cpu->read32(address+8);
|
||||
memory[3] = cpu->read32(address+12);
|
||||
}
|
||||
|
||||
u8* m = (u8*) memory;
|
||||
for (int j = 0; j < rowSize; j++)
|
||||
{
|
||||
if (valid)
|
||||
swprintf(temp,32,L"%02X",m[j]);
|
||||
else
|
||||
wcscpy(temp,L"??");
|
||||
u32 byteAddress = rowAddress + j;
|
||||
u8 byteCurrent;
|
||||
bool byteValid;
|
||||
|
||||
unsigned char c = m[j];
|
||||
if (c < 32 || c >= 128 || valid == false)
|
||||
c = '.';
|
||||
|
||||
if (address+j == curAddress)
|
||||
{
|
||||
wchar_t text[2];
|
||||
try {
|
||||
byteValid = validCpu && cpu->isValidAddress(byteAddress);
|
||||
|
||||
if (hasFocus && !asciiSelected)
|
||||
{
|
||||
dc.SetTextForeground(wxColor(0xFFFFFFFF));
|
||||
|
||||
dc.SetPen(wxColor(0xFFFF9933));
|
||||
dc.SetBrush(wxColor(0xFFFF9933));
|
||||
dc.DrawRectangle(hexStart+j*3*charWidth,rowY,charWidth,rowHeight);
|
||||
|
||||
if (selectedNibble == 0)
|
||||
dc.SetFont(underlineFont);
|
||||
} else {
|
||||
dc.SetTextForeground(wxColor(0xFF000000));
|
||||
|
||||
dc.SetPen(wxColor(0xFFC0C0C0));
|
||||
dc.SetBrush(wxColor(0xFFC0C0C0));
|
||||
dc.DrawRectangle(hexStart+j*3*charWidth,rowY,charWidth,rowHeight);
|
||||
}
|
||||
|
||||
text[0] = temp[0];
|
||||
text[1] = 0;
|
||||
dc.DrawText(text,hexStart+j*3*charWidth,rowY);
|
||||
|
||||
if (hasFocus && !asciiSelected)
|
||||
{
|
||||
dc.DrawRectangle(hexStart+j*3*charWidth+charWidth,rowY,charWidth,rowHeight);
|
||||
|
||||
if (selectedNibble == 1)
|
||||
dc.SetFont(underlineFont);
|
||||
else
|
||||
dc.SetFont(font);
|
||||
} else {
|
||||
dc.DrawRectangle(hexStart+j*3*charWidth+charWidth,rowY,charWidth,rowHeight);
|
||||
}
|
||||
|
||||
text[0] = temp[1];
|
||||
text[1] = 0;
|
||||
dc.DrawText(text,hexStart+j*3*charWidth+charWidth,rowY);
|
||||
|
||||
if (hasFocus && asciiSelected)
|
||||
{
|
||||
dc.SetTextForeground(wxColor(0xFFFFFFFF));
|
||||
|
||||
dc.SetPen(wxColor(0xFFFF9933));
|
||||
dc.SetBrush(wxColor(0xFFFF9933));
|
||||
dc.DrawRectangle(asciiStart+j*(charWidth+2),rowY,charWidth,rowHeight);
|
||||
} else {
|
||||
dc.SetTextForeground(wxColor(0xFF000000));
|
||||
dc.SetFont(font);
|
||||
|
||||
dc.SetPen(wxColor(0xFFC0C0C0));
|
||||
dc.SetBrush(wxColor(0xFFC0C0C0));
|
||||
dc.DrawRectangle(asciiStart+j*(charWidth+2),rowY,charWidth,rowHeight);
|
||||
}
|
||||
|
||||
text[0] = c;
|
||||
text[1] = 0;
|
||||
dc.DrawText(text,asciiStart+j*(charWidth+2),rowY);
|
||||
} else {
|
||||
wchar_t text[2];
|
||||
text[0] = c;
|
||||
text[1] = 0;
|
||||
|
||||
dc.SetTextForeground(wxColor(0xFF000000));
|
||||
dc.DrawText(temp,hexStart+j*3*charWidth,rowY);
|
||||
dc.DrawText(text,asciiStart+j*(charWidth+2),rowY);
|
||||
if (byteValid)
|
||||
byteCurrent = cpu->read8(byteAddress);
|
||||
}
|
||||
catch (Exception::Ps2Generic &) {
|
||||
byteValid = false;
|
||||
}
|
||||
|
||||
// not optimized way, but more flexible than previous
|
||||
|
||||
// calculate group position
|
||||
int groupNum = j / byteGroupSize;
|
||||
int groupPosX = hexStart + groupNum * byteGroupSize * 3 * charWidth;
|
||||
|
||||
// calculate symbol position in group
|
||||
int groupIndex = j % byteGroupSize;
|
||||
|
||||
int symbolPosX = groupPosX + hexGroupPositionFromIndex(byteGroupSize - groupIndex - 1);
|
||||
|
||||
u32 groupAddress = byteAddress - groupIndex;
|
||||
|
||||
if (curAddress >= groupAddress && curAddress < groupAddress + byteGroupSize)
|
||||
{
|
||||
// if group selected, draw rectangle behind
|
||||
if (groupIndex == 0) {
|
||||
if (hasFocus && !asciiSelected) {
|
||||
dc.SetPen(COLOR_SELECTED_BG);
|
||||
dc.SetBrush(COLOR_SELECTED_BG);
|
||||
}
|
||||
else {
|
||||
dc.SetPen(COLOR_SELECTED_INACTIVE_BG);
|
||||
dc.SetBrush(COLOR_SELECTED_INACTIVE_BG);
|
||||
}
|
||||
|
||||
dc.DrawRectangle(groupPosX, rowY, groupWidth, rowHeight);
|
||||
}
|
||||
|
||||
dc.SetTextForeground((hasFocus && !asciiSelected) ? COLOR_WHITE : COLOR_BLACK);
|
||||
}
|
||||
else {
|
||||
dc.SetTextForeground(COLOR_BLACK);
|
||||
}
|
||||
|
||||
swprintf(temp, TEMP_SIZE, byteValid ? L"%02X" : L"??", byteCurrent);
|
||||
// if selected byte, need hint current nibble
|
||||
if (byteAddress == curAddress) {
|
||||
if (selectedNibble == 1)
|
||||
dc.SetFont(underlineFont);
|
||||
|
||||
dc.DrawText(temp + 1, symbolPosX + charWidth, rowY);
|
||||
|
||||
if (selectedNibble == 1)
|
||||
dc.SetFont(font);
|
||||
else
|
||||
dc.SetFont(underlineFont);
|
||||
|
||||
temp[1] = 0;
|
||||
dc.DrawText(temp, symbolPosX, rowY);
|
||||
|
||||
if (selectedNibble == 0)
|
||||
dc.SetFont(font);
|
||||
}
|
||||
else {
|
||||
dc.DrawText(temp, symbolPosX, rowY);
|
||||
}
|
||||
|
||||
// draw in ansii text representation table
|
||||
temp[1] = 0;
|
||||
temp[0] = (!byteValid || byteCurrent < 32 || byteCurrent > 128) ? '.' : byteCurrent;
|
||||
|
||||
if (byteAddress == curAddress) {
|
||||
if (hasFocus && asciiSelected) {
|
||||
dc.SetPen(COLOR_SELECTED_BG);
|
||||
dc.SetBrush(COLOR_SELECTED_BG);
|
||||
dc.SetTextForeground(COLOR_WHITE);
|
||||
}
|
||||
else {
|
||||
dc.SetPen(COLOR_SELECTED_INACTIVE_BG);
|
||||
dc.SetBrush(COLOR_SELECTED_INACTIVE_BG);
|
||||
dc.SetTextForeground(COLOR_BLACK);
|
||||
}
|
||||
dc.DrawRectangle(asciiStart + j*(charWidth + 2), rowY, charWidth, rowHeight);
|
||||
}
|
||||
else {
|
||||
dc.SetTextForeground(COLOR_BLACK);
|
||||
}
|
||||
|
||||
dc.DrawText(temp, asciiStart + j*(charWidth + 2), rowY);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make optional?
|
||||
if (true)
|
||||
dc.SetPen(COLOR_DELIMETER);
|
||||
dc.SetBrush(COLOR_DELIMETER);
|
||||
int linestep = std::max((u32) 4, byteGroupSize);
|
||||
for (int i = linestep; i < rowSize; i += linestep)
|
||||
{
|
||||
dc.SetPen(wxColor(0xFFC0C0C0));
|
||||
dc.SetBrush(wxColor(0xFFC0C0C0));
|
||||
for (int i = 4; i < rowSize; i += 4)
|
||||
{
|
||||
int x = hexStart+i*3*charWidth-charWidth/2;
|
||||
int y = (visibleRows+1)*rowHeight;
|
||||
dc.DrawLine(x,0,x,y);
|
||||
}
|
||||
int x = hexStart + i * 3 * charWidth - charWidth / 2;
|
||||
int y = (visibleRows + 1) * rowHeight;
|
||||
dc.DrawLine(x, 0, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,6 +325,29 @@ void CtrlMemView::onPopupClick(wxCommandEvent& evt)
|
|||
case ID_MEMVIEW_GOTOINDISASM:
|
||||
postEvent(debEVT_GOTOINDISASM,curAddress);
|
||||
break;
|
||||
case ID_MEMVIEW_FOLLOWADDRESS:
|
||||
gotoAddress(cpu->read32(curAddress), true);
|
||||
break;
|
||||
case ID_MEMVIEW_DISPLAYVALUE_8:
|
||||
byteGroupSize = 1;
|
||||
Refresh();
|
||||
break;
|
||||
case ID_MEMVIEW_DISPLAYVALUE_16:
|
||||
byteGroupSize = 2;
|
||||
Refresh();
|
||||
break;
|
||||
case ID_MEMVIEW_DISPLAYVALUE_32:
|
||||
byteGroupSize = 4;
|
||||
Refresh();
|
||||
break;
|
||||
case ID_MEMVIEW_DISPLAYVALUE_64:
|
||||
byteGroupSize = 8;
|
||||
Refresh();
|
||||
break;
|
||||
case ID_MEMVIEW_DISPLAYVALUE_128:
|
||||
byteGroupSize = 16;
|
||||
Refresh();
|
||||
break;
|
||||
case ID_MEMVIEW_COPYVALUE_8:
|
||||
if (wxTheClipboard->Open())
|
||||
{
|
||||
|
@ -331,6 +403,16 @@ void CtrlMemView::mouseEvent(wxMouseEvent& evt)
|
|||
SetFocusFromKbd();
|
||||
} else if (evt.GetEventType() == wxEVT_RIGHT_UP)
|
||||
{
|
||||
curAddress -= (curAddress - windowStart) % byteGroupSize;
|
||||
|
||||
menu.Enable(ID_MEMVIEW_FOLLOWADDRESS, (curAddress & 3) == 0);
|
||||
|
||||
menu.Enable(ID_MEMVIEW_DISPLAYVALUE_8, byteGroupSize != 1);
|
||||
menu.Enable(ID_MEMVIEW_DISPLAYVALUE_16, byteGroupSize != 2);
|
||||
menu.Enable(ID_MEMVIEW_DISPLAYVALUE_32, byteGroupSize != 4);
|
||||
menu.Enable(ID_MEMVIEW_DISPLAYVALUE_64, byteGroupSize != 8);
|
||||
menu.Enable(ID_MEMVIEW_DISPLAYVALUE_128, byteGroupSize != 16);
|
||||
|
||||
menu.Enable(ID_MEMVIEW_COPYVALUE_128,(curAddress & 15) == 0);
|
||||
menu.Enable(ID_MEMVIEW_COPYVALUE_64,(curAddress & 7) == 0);
|
||||
menu.Enable(ID_MEMVIEW_COPYVALUE_32,(curAddress & 3) == 0);
|
||||
|
@ -340,11 +422,22 @@ void CtrlMemView::mouseEvent(wxMouseEvent& evt)
|
|||
return;
|
||||
} else if (evt.GetEventType() == wxEVT_MOUSEWHEEL)
|
||||
{
|
||||
if (evt.GetWheelRotation() > 0)
|
||||
{
|
||||
scrollWindow(-3);
|
||||
} else if (evt.GetWheelRotation() < 0) {
|
||||
scrollWindow(3);
|
||||
if (evt.ControlDown()) {
|
||||
if (evt.GetWheelRotation() > 0) {
|
||||
setRowSize(rowSize + 16);
|
||||
}
|
||||
else {
|
||||
setRowSize(rowSize - 16);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (evt.GetWheelRotation() > 0)
|
||||
{
|
||||
scrollWindow(-3);
|
||||
}
|
||||
else if (evt.GetWheelRotation() < 0) {
|
||||
scrollWindow(3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
evt.Skip();
|
||||
|
@ -366,7 +459,8 @@ void CtrlMemView::keydownEvent(wxKeyEvent& evt)
|
|||
u64 addr;
|
||||
if (executeExpressionWindow(this,cpu,addr) == false)
|
||||
return;
|
||||
gotoAddress(addr);
|
||||
|
||||
gotoAddress(addr, true);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
|
@ -407,6 +501,12 @@ void CtrlMemView::keydownEvent(wxKeyEvent& evt)
|
|||
case WXK_PAGEDOWN:
|
||||
scrollWindow(GetClientSize().y/rowHeight);
|
||||
break;
|
||||
case WXK_ESCAPE:
|
||||
if (history.size()) {
|
||||
gotoAddress(history.top());
|
||||
history.pop();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
evt.Skip();
|
||||
break;
|
||||
|
@ -510,12 +610,14 @@ void CtrlMemView::scrollCursor(int bytes)
|
|||
|
||||
int visibleRows = GetClientSize().y/rowHeight;
|
||||
u32 windowEnd = windowStart+visibleRows*rowSize;
|
||||
|
||||
if (curAddress < windowStart)
|
||||
{
|
||||
windowStart = curAddress & ~15;
|
||||
windowStart = (curAddress / rowSize) * curAddress;
|
||||
} else if (curAddress >= windowEnd)
|
||||
{
|
||||
windowStart = (curAddress-(visibleRows-1)*rowSize) & ~15;
|
||||
windowStart = curAddress - (visibleRows - 1)*rowSize;
|
||||
windowStart = (windowStart / rowSize) * windowStart;
|
||||
}
|
||||
|
||||
updateStatusBarText();
|
||||
|
@ -525,22 +627,26 @@ void CtrlMemView::scrollCursor(int bytes)
|
|||
void CtrlMemView::updateStatusBarText()
|
||||
{
|
||||
wchar_t text[64];
|
||||
swprintf(text,64,L"%08X",curAddress);
|
||||
|
||||
int needpad = (curAddress - windowStart) % byteGroupSize;
|
||||
u32 addr = curAddress - needpad;
|
||||
|
||||
swprintf(text, 64, L"%08X %08X", curAddress, addr);
|
||||
|
||||
postEvent(debEVT_SETSTATUSBARTEXT,text);
|
||||
}
|
||||
|
||||
void CtrlMemView::gotoAddress(u32 addr)
|
||||
void CtrlMemView::gotoAddress(u32 addr, bool pushInHistory)
|
||||
{
|
||||
int lines= GetClientSize().y/rowHeight;
|
||||
u32 windowEnd = windowStart+lines*rowSize;
|
||||
if (pushInHistory)
|
||||
history.push(windowStart);
|
||||
|
||||
int lines= GetClientSize().y / rowHeight;
|
||||
u32 windowEnd = windowStart + lines * rowSize;
|
||||
|
||||
curAddress = addr;
|
||||
selectedNibble = 0;
|
||||
|
||||
if (curAddress < windowStart || curAddress >= windowEnd)
|
||||
{
|
||||
windowStart = curAddress & ~15;
|
||||
}
|
||||
windowStart = curAddress;
|
||||
|
||||
updateStatusBarText();
|
||||
redraw();
|
||||
|
@ -563,18 +669,37 @@ void CtrlMemView::gotoPoint(int x, int y)
|
|||
redraw();
|
||||
} else if (x >= hexStart)
|
||||
{
|
||||
int col = (x-hexStart) / charWidth;
|
||||
if ((col/3) >= rowSize) return;
|
||||
int col = (x-hexStart);
|
||||
int space = (charWidth / 4);
|
||||
|
||||
switch (col % 3)
|
||||
{
|
||||
case 0: selectedNibble = 0; break;
|
||||
case 1: selectedNibble = 1; break;
|
||||
case 2: return; // don't change position when clicking on the space
|
||||
int groupWidth = byteGroupSize * charWidth * 3;
|
||||
int group = col / groupWidth;
|
||||
|
||||
int posInGroup = col % groupWidth;
|
||||
|
||||
int indexInGroup = -1;
|
||||
|
||||
for (int i = 0; i < int(byteGroupSize); i++) {
|
||||
int start = hexGroupPositionFromIndex(i);
|
||||
int end = start + 2 * charWidth -1;
|
||||
if (posInGroup < start)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (posInGroup <= end)
|
||||
{
|
||||
selectedNibble = ((posInGroup - start) / charWidth) % 2;
|
||||
indexInGroup = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (indexInGroup == -1)
|
||||
return;
|
||||
|
||||
curAddress = lineAddress + group * byteGroupSize + (byteGroupSize - indexInGroup - 1);
|
||||
|
||||
asciiSelected = false;
|
||||
curAddress = lineAddress+col/3;
|
||||
updateStatusBarText();
|
||||
redraw();
|
||||
}
|
||||
|
|
|
@ -30,11 +30,13 @@ public:
|
|||
void scrollbarEvent(wxScrollWinEvent& evt);
|
||||
void charEvent(wxKeyEvent& evt);
|
||||
void redraw();
|
||||
void gotoAddress(u32 address);
|
||||
void gotoAddress(u32 address, bool pushInHistory = false);
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
private:
|
||||
void render(wxDC& dc);
|
||||
int hexGroupPositionFromIndex(int idx);
|
||||
void setRowSize(int bytesInRow);
|
||||
void gotoPoint(int x, int y);
|
||||
void updateStatusBarText();
|
||||
void postEvent(wxEventType type, wxString text);
|
||||
|
@ -49,6 +51,7 @@ private:
|
|||
int charWidth;
|
||||
u32 windowStart;
|
||||
u32 curAddress;
|
||||
u32 byteGroupSize;
|
||||
int rowSize;
|
||||
wxFont font,underlineFont;
|
||||
|
||||
|
@ -58,5 +61,6 @@ private:
|
|||
bool asciiSelected;
|
||||
int selectedNibble;
|
||||
|
||||
std::stack<u32> history;
|
||||
wxMenu menu;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -35,9 +35,12 @@ enum DisassemblyMenuIdentifiers
|
|||
ID_REGISTERLIST_DISPLAY32 = 1,
|
||||
ID_REGISTERLIST_DISPLAY64,
|
||||
ID_REGISTERLIST_DISPLAY128,
|
||||
ID_REGISTERLIST_DISPLAY128STRINGS,
|
||||
ID_REGISTERLIST_CHANGELOWER,
|
||||
ID_REGISTERLIST_CHANGEUPPER,
|
||||
ID_REGISTERLIST_CHANGEVALUE
|
||||
ID_REGISTERLIST_CHANGEVALUE,
|
||||
ID_REGISTERLIST_GOTOINMEMORYVIEW,
|
||||
ID_REGISTERLIST_GOTOINDISASM
|
||||
};
|
||||
|
||||
|
||||
|
@ -276,7 +279,18 @@ void CtrlRegisterList::OnDraw(wxDC& dc)
|
|||
{
|
||||
case 128:
|
||||
{
|
||||
int startIndex = std::min<int>(3,maxBits/32-1);
|
||||
int startIndex = std::min<int>(3, maxBits / 32 - 1);
|
||||
|
||||
if (resolvePointerStrings && cpu && cpu->isAlive()) {
|
||||
char *strval = cpu->stringFromPointer(value._u32[0]);
|
||||
if (strval) {
|
||||
static wxColor clr = wxColor(0xFF228822);
|
||||
dc.SetTextForeground(clr);
|
||||
dc.DrawText(wxString(strval), width - (32 * charWidth + 12), y + 2);
|
||||
startIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int actualX = width-4-(startIndex+1)*(8*charWidth+2);
|
||||
x = std::max<int>(actualX,x);
|
||||
|
||||
|
@ -396,23 +410,33 @@ void CtrlRegisterList::onPopupClick(wxCommandEvent& evt)
|
|||
switch (evt.GetId())
|
||||
{
|
||||
case ID_REGISTERLIST_DISPLAY32:
|
||||
resolvePointerStrings = false;
|
||||
maxBits = 32;
|
||||
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
|
||||
postEvent(debEVT_UPDATELAYOUT,0);
|
||||
Refresh();
|
||||
break;
|
||||
case ID_REGISTERLIST_DISPLAY64:
|
||||
resolvePointerStrings = false;
|
||||
maxBits = 64;
|
||||
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
|
||||
postEvent(debEVT_UPDATELAYOUT,0);
|
||||
Refresh();
|
||||
break;
|
||||
case ID_REGISTERLIST_DISPLAY128:
|
||||
resolvePointerStrings = false;
|
||||
maxBits = 128;
|
||||
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
|
||||
postEvent(debEVT_UPDATELAYOUT,0);
|
||||
Refresh();
|
||||
break;
|
||||
case ID_REGISTERLIST_DISPLAY128STRINGS:
|
||||
resolvePointerStrings = true;
|
||||
maxBits = 128;
|
||||
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
|
||||
postEvent(debEVT_UPDATELAYOUT, 0);
|
||||
Refresh();
|
||||
break;
|
||||
case ID_REGISTERLIST_CHANGELOWER:
|
||||
changeValue(LOWER64);
|
||||
Refresh();
|
||||
|
@ -428,6 +452,12 @@ void CtrlRegisterList::onPopupClick(wxCommandEvent& evt)
|
|||
changeValue(LOWER64);
|
||||
Refresh();
|
||||
break;
|
||||
case ID_REGISTERLIST_GOTOINMEMORYVIEW:
|
||||
postEvent(debEVT_GOTOINMEMORYVIEW, cpu->getRegister(category, currentRows[category])._u32[0]);
|
||||
break;
|
||||
case ID_REGISTERLIST_GOTOINDISASM:
|
||||
postEvent(debEVT_GOTOINDISASM, cpu->getRegister(category, currentRows[category])._u32[0]);
|
||||
break;
|
||||
default:
|
||||
wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
|
||||
break;
|
||||
|
@ -495,6 +525,7 @@ void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
|
|||
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY32, L"Display 32 bit");
|
||||
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit");
|
||||
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit");
|
||||
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128STRINGS, L"Display 128 bit + Resolve string pointers");
|
||||
menu.AppendSeparator();
|
||||
|
||||
if (bits >= 64)
|
||||
|
@ -505,10 +536,17 @@ void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
|
|||
menu.Append(ID_REGISTERLIST_CHANGEVALUE, L"Change value");
|
||||
}
|
||||
|
||||
menu.AppendSeparator();
|
||||
menu.Append(ID_REGISTERLIST_GOTOINMEMORYVIEW, L"Follow in Memory view");
|
||||
menu.Append(ID_REGISTERLIST_GOTOINDISASM, L"Follow in Disasm");
|
||||
|
||||
switch (maxBits)
|
||||
{
|
||||
case 128:
|
||||
menu.Check(ID_REGISTERLIST_DISPLAY128,true);
|
||||
if (resolvePointerStrings)
|
||||
menu.Check(ID_REGISTERLIST_DISPLAY128STRINGS, true);
|
||||
else
|
||||
menu.Check(ID_REGISTERLIST_DISPLAY128,true);
|
||||
break;
|
||||
case 64:
|
||||
menu.Check(ID_REGISTERLIST_DISPLAY64,true);
|
||||
|
|
|
@ -71,4 +71,5 @@ private:
|
|||
u32 lastPc;
|
||||
int category;
|
||||
int maxBits;
|
||||
};
|
||||
bool resolvePointerStrings;
|
||||
};
|
||||
|
|
|
@ -54,4 +54,4 @@ bool executeExpressionWindow(wxWindow* parent, DebugInterface* cpu, u64& dest, c
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -501,8 +501,10 @@ void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt)
|
|||
if (currentCpu != NULL)
|
||||
{
|
||||
currentCpu->showMemoryView();
|
||||
currentCpu->getMemoryView()->gotoAddress(evt.GetInt());
|
||||
currentCpu->getDisassembly()->SetFocus();
|
||||
|
||||
CtrlMemView *memview = currentCpu->getMemoryView();
|
||||
memview->gotoAddress(evt.GetInt(), true);
|
||||
memview->SetFocus();
|
||||
}
|
||||
} else if (type == debEVT_RUNTOPOS)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue