Merge pull request #1287 from mogaika/debug_window_improve

Debugger features
This commit is contained in:
Gregory Hainaut 2016-07-07 19:59:33 +02:00 committed by GitHub
commit a735e2b58f
11 changed files with 403 additions and 172 deletions

View File

@ -30,6 +30,8 @@ memory view:
any overwrite ansi byte any overwrite ansi byte
left click select byte/nibble left click select byte/nibble
right click open context menu right click open context menu
ctrl+wheel zoom memory view
esc return to previous goto address
breakpoint list: breakpoint list:

View File

@ -184,6 +184,37 @@ void DebugInterface::resumeCpu()
core.Resume(); 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) bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest)
{ {
MipsExpressionFunctions funcs(this); MipsExpressionFunctions funcs(this);
@ -509,33 +540,59 @@ std::string R5900DebugInterface::disasm(u32 address, bool simplify)
bool R5900DebugInterface::isValidAddress(u32 addr) bool R5900DebugInterface::isValidAddress(u32 addr)
{ {
// ee can't access the first part of memory. u32 lopart = addr & 0xfFFffFF;
if (addr < 0x80000)
return false;
if (addr >= 0xFFFF8000)
return true;
addr &= 0x7FFFFFFF;
// get rid of ee ram mirrors // get rid of ee ram mirrors
if ((addr >> 28) == 2 || (addr >> 28) == 3) switch (addr >> 28)
addr &= ~(0xF << 28); {
case 0:
// registers case 2:
if (addr >= 0x10000000 && addr < 0x10010000) // case 3: throw exception (not mapped ?)
return true; // [ 0000_8000 - 01FF_FFFF ] RAM
if (addr >= 0x12000000 && addr < 0x12001100) // [ 2000_8000 - 21FF_FFFF ] RAM MIRROR
return true; // [ 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 // [ 1100_0000 - 1100_FFFF ] VU mem
if (addr >= 0x70000000 && addr < 0x70004000) if (lopart >= 0x1000000 && lopart <= 0x100FFff)
return true; 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() u32 R5900DebugInterface::getCycles()
{ {
return cpuRegs.cycle; return cpuRegs.cycle;

View File

@ -58,6 +58,7 @@ public:
bool isCpuPaused(); bool isCpuPaused();
void pauseCpu(); void pauseCpu();
void resumeCpu(); void resumeCpu();
char *stringFromPointer(u32 p);
}; };
class R5900DebugInterface: public DebugInterface class R5900DebugInterface: public DebugInterface

View File

@ -41,6 +41,7 @@
#include <stdexcept> #include <stdexcept>
#include <vector> #include <vector>
#include <list> #include <list>
#include <stack>
#include <cstring> // string.h under c++ #include <cstring> // string.h under c++
#include <cstdio> // stdio.h under c++ #include <cstdio> // stdio.h under c++
#include <cstdlib> #include <cstdlib>

View File

@ -60,4 +60,4 @@ private:
u32 size; u32 size;
char condition[128]; char condition[128];
PostfixExpression compiledCondition; PostfixExpression compiledCondition;
}; };

View File

@ -24,6 +24,7 @@
#include <wchar.h> #include <wchar.h>
#include <wx/clipbrd.h> #include <wx/clipbrd.h>
BEGIN_EVENT_TABLE(CtrlMemView, wxWindow) BEGIN_EVENT_TABLE(CtrlMemView, wxWindow)
EVT_PAINT(CtrlMemView::paintEvent) EVT_PAINT(CtrlMemView::paintEvent)
EVT_MOUSEWHEEL(CtrlMemView::mouseEvent) EVT_MOUSEWHEEL(CtrlMemView::mouseEvent)
@ -45,6 +46,12 @@ enum MemoryViewMenuIdentifiers
{ {
ID_MEMVIEW_GOTOINDISASM = 1, ID_MEMVIEW_GOTOINDISASM = 1,
ID_MEMVIEW_COPYADDRESS, 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_8,
ID_MEMVIEW_COPYVALUE_16, ID_MEMVIEW_COPYVALUE_16,
ID_MEMVIEW_COPYVALUE_32, ID_MEMVIEW_COPYVALUE_32,
@ -60,14 +67,14 @@ CtrlMemView::CtrlMemView(wxWindow* parent, DebugInterface* _cpu)
charWidth = getDebugFontWidth(); charWidth = getDebugFontWidth();
windowStart = 0x480000; windowStart = 0x480000;
curAddress = windowStart; curAddress = windowStart;
rowSize = 16; byteGroupSize = 1;
asciiSelected = false; asciiSelected = false;
selectedNibble = 0; selectedNibble = 0;
rowSize = 16;
addressStart = charWidth; addressStart = charWidth;
hexStart = addressStart + 9*charWidth; hexStart = addressStart + 9*charWidth;
asciiStart = hexStart + (rowSize*3+1)*charWidth;
setRowSize(16);
#ifdef _WIN32 #ifdef _WIN32
font = wxFont(wxSize(charWidth,rowHeight),wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console"); 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_GOTOINDISASM, L"Go to in Disasm");
menu.Append(ID_MEMVIEW_COPYADDRESS, L"Copy address"); 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.AppendSeparator();
menu.Append(ID_MEMVIEW_COPYVALUE_8, L"Copy Value (8 bit)"); menu.Append(ID_MEMVIEW_COPYVALUE_8, L"Copy Value (8 bit)");
menu.Append(ID_MEMVIEW_COPYVALUE_16, L"Copy Value (16 bit)"); menu.Append(ID_MEMVIEW_COPYVALUE_16, L"Copy Value (16 bit)");
@ -95,6 +109,11 @@ CtrlMemView::CtrlMemView(wxWindow* parent, DebugInterface* _cpu)
SetDoubleBuffered(true); 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) void CtrlMemView::postEvent(wxEventType type, wxString text)
{ {
wxCommandEvent event( type, GetId() ); wxCommandEvent event( type, GetId() );
@ -125,137 +144,167 @@ void CtrlMemView::redraw()
render(dc); 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) void CtrlMemView::render(wxDC& dc)
{ {
bool hasFocus = wxWindow::FindFocus() == this; bool hasFocus = wxWindow::FindFocus() == this;
int visibleRows = GetClientSize().y/rowHeight; int visibleRows = GetClientSize().y / rowHeight;
wxColor white = wxColor(0xFFFFFFFF); const wxColor COLOR_WHITE = wxColor(0xFFFFFFFF);
dc.SetBrush(wxBrush(white)); const wxColor COLOR_BLACK = wxColor(0xFF000000);
dc.SetPen(wxPen(white)); 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.SetBrush(wxBrush(COLOR_WHITE));
dc.GetSize(&width,&height); dc.SetPen(wxPen(COLOR_WHITE));
dc.DrawRectangle(0,0,width,height);
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; swprintf(temp, TEMP_SIZE, L"%08X" , rowAddress);
int rowY = rowHeight*i;
swprintf(temp,32,L"%08X",address);
dc.SetFont(font); dc.SetFont(font);
dc.SetTextForeground(wxColor(0xFF600000)); dc.SetTextForeground(COLOR_ADDRESS);
dc.DrawText(temp,addressStart,rowY); 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++) for (int j = 0; j < rowSize; j++)
{ {
if (valid) u32 byteAddress = rowAddress + j;
swprintf(temp,32,L"%02X",m[j]); u8 byteCurrent;
else bool byteValid;
wcscpy(temp,L"??");
unsigned char c = m[j]; try {
if (c < 32 || c >= 128 || valid == false) byteValid = validCpu && cpu->isValidAddress(byteAddress);
c = '.';
if (address+j == curAddress)
{
wchar_t text[2];
if (hasFocus && !asciiSelected) if (byteValid)
{ byteCurrent = cpu->read8(byteAddress);
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);
} }
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? dc.SetPen(COLOR_DELIMETER);
if (true) dc.SetBrush(COLOR_DELIMETER);
int linestep = std::max((u32) 4, byteGroupSize);
for (int i = linestep; i < rowSize; i += linestep)
{ {
dc.SetPen(wxColor(0xFFC0C0C0)); int x = hexStart + i * 3 * charWidth - charWidth / 2;
dc.SetBrush(wxColor(0xFFC0C0C0)); int y = (visibleRows + 1) * rowHeight;
for (int i = 4; i < rowSize; i += 4) 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: case ID_MEMVIEW_GOTOINDISASM:
postEvent(debEVT_GOTOINDISASM,curAddress); postEvent(debEVT_GOTOINDISASM,curAddress);
break; 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: case ID_MEMVIEW_COPYVALUE_8:
if (wxTheClipboard->Open()) if (wxTheClipboard->Open())
{ {
@ -331,6 +403,16 @@ void CtrlMemView::mouseEvent(wxMouseEvent& evt)
SetFocusFromKbd(); SetFocusFromKbd();
} else if (evt.GetEventType() == wxEVT_RIGHT_UP) } 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_128,(curAddress & 15) == 0);
menu.Enable(ID_MEMVIEW_COPYVALUE_64,(curAddress & 7) == 0); menu.Enable(ID_MEMVIEW_COPYVALUE_64,(curAddress & 7) == 0);
menu.Enable(ID_MEMVIEW_COPYVALUE_32,(curAddress & 3) == 0); menu.Enable(ID_MEMVIEW_COPYVALUE_32,(curAddress & 3) == 0);
@ -340,11 +422,22 @@ void CtrlMemView::mouseEvent(wxMouseEvent& evt)
return; return;
} else if (evt.GetEventType() == wxEVT_MOUSEWHEEL) } else if (evt.GetEventType() == wxEVT_MOUSEWHEEL)
{ {
if (evt.GetWheelRotation() > 0) if (evt.ControlDown()) {
{ if (evt.GetWheelRotation() > 0) {
scrollWindow(-3); setRowSize(rowSize + 16);
} else if (evt.GetWheelRotation() < 0) { }
scrollWindow(3); else {
setRowSize(rowSize - 16);
}
}
else {
if (evt.GetWheelRotation() > 0)
{
scrollWindow(-3);
}
else if (evt.GetWheelRotation() < 0) {
scrollWindow(3);
}
} }
} else { } else {
evt.Skip(); evt.Skip();
@ -366,7 +459,8 @@ void CtrlMemView::keydownEvent(wxKeyEvent& evt)
u64 addr; u64 addr;
if (executeExpressionWindow(this,cpu,addr) == false) if (executeExpressionWindow(this,cpu,addr) == false)
return; return;
gotoAddress(addr);
gotoAddress(addr, true);
} }
break; break;
case 'b': case 'b':
@ -407,6 +501,12 @@ void CtrlMemView::keydownEvent(wxKeyEvent& evt)
case WXK_PAGEDOWN: case WXK_PAGEDOWN:
scrollWindow(GetClientSize().y/rowHeight); scrollWindow(GetClientSize().y/rowHeight);
break; break;
case WXK_ESCAPE:
if (history.size()) {
gotoAddress(history.top());
history.pop();
}
break;
default: default:
evt.Skip(); evt.Skip();
break; break;
@ -510,12 +610,14 @@ void CtrlMemView::scrollCursor(int bytes)
int visibleRows = GetClientSize().y/rowHeight; int visibleRows = GetClientSize().y/rowHeight;
u32 windowEnd = windowStart+visibleRows*rowSize; u32 windowEnd = windowStart+visibleRows*rowSize;
if (curAddress < windowStart) if (curAddress < windowStart)
{ {
windowStart = curAddress & ~15; windowStart = (curAddress / rowSize) * curAddress;
} else if (curAddress >= windowEnd) } else if (curAddress >= windowEnd)
{ {
windowStart = (curAddress-(visibleRows-1)*rowSize) & ~15; windowStart = curAddress - (visibleRows - 1)*rowSize;
windowStart = (windowStart / rowSize) * windowStart;
} }
updateStatusBarText(); updateStatusBarText();
@ -525,22 +627,26 @@ void CtrlMemView::scrollCursor(int bytes)
void CtrlMemView::updateStatusBarText() void CtrlMemView::updateStatusBarText()
{ {
wchar_t text[64]; 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); postEvent(debEVT_SETSTATUSBARTEXT,text);
} }
void CtrlMemView::gotoAddress(u32 addr) void CtrlMemView::gotoAddress(u32 addr, bool pushInHistory)
{ {
int lines= GetClientSize().y/rowHeight; if (pushInHistory)
u32 windowEnd = windowStart+lines*rowSize; history.push(windowStart);
int lines= GetClientSize().y / rowHeight;
u32 windowEnd = windowStart + lines * rowSize;
curAddress = addr; curAddress = addr;
selectedNibble = 0; selectedNibble = 0;
windowStart = curAddress;
if (curAddress < windowStart || curAddress >= windowEnd)
{
windowStart = curAddress & ~15;
}
updateStatusBarText(); updateStatusBarText();
redraw(); redraw();
@ -563,18 +669,37 @@ void CtrlMemView::gotoPoint(int x, int y)
redraw(); redraw();
} else if (x >= hexStart) } else if (x >= hexStart)
{ {
int col = (x-hexStart) / charWidth; int col = (x-hexStart);
if ((col/3) >= rowSize) return; int space = (charWidth / 4);
switch (col % 3) int groupWidth = byteGroupSize * charWidth * 3;
{ int group = col / groupWidth;
case 0: selectedNibble = 0; break;
case 1: selectedNibble = 1; break; int posInGroup = col % groupWidth;
case 2: return; // don't change position when clicking on the space
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; asciiSelected = false;
curAddress = lineAddress+col/3;
updateStatusBarText(); updateStatusBarText();
redraw(); redraw();
} }

View File

@ -30,11 +30,13 @@ public:
void scrollbarEvent(wxScrollWinEvent& evt); void scrollbarEvent(wxScrollWinEvent& evt);
void charEvent(wxKeyEvent& evt); void charEvent(wxKeyEvent& evt);
void redraw(); void redraw();
void gotoAddress(u32 address); void gotoAddress(u32 address, bool pushInHistory = false);
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
private: private:
void render(wxDC& dc); void render(wxDC& dc);
int hexGroupPositionFromIndex(int idx);
void setRowSize(int bytesInRow);
void gotoPoint(int x, int y); void gotoPoint(int x, int y);
void updateStatusBarText(); void updateStatusBarText();
void postEvent(wxEventType type, wxString text); void postEvent(wxEventType type, wxString text);
@ -49,6 +51,7 @@ private:
int charWidth; int charWidth;
u32 windowStart; u32 windowStart;
u32 curAddress; u32 curAddress;
u32 byteGroupSize;
int rowSize; int rowSize;
wxFont font,underlineFont; wxFont font,underlineFont;
@ -58,5 +61,6 @@ private:
bool asciiSelected; bool asciiSelected;
int selectedNibble; int selectedNibble;
std::stack<u32> history;
wxMenu menu; wxMenu menu;
}; };

View File

@ -35,9 +35,12 @@ enum DisassemblyMenuIdentifiers
ID_REGISTERLIST_DISPLAY32 = 1, ID_REGISTERLIST_DISPLAY32 = 1,
ID_REGISTERLIST_DISPLAY64, ID_REGISTERLIST_DISPLAY64,
ID_REGISTERLIST_DISPLAY128, ID_REGISTERLIST_DISPLAY128,
ID_REGISTERLIST_DISPLAY128STRINGS,
ID_REGISTERLIST_CHANGELOWER, ID_REGISTERLIST_CHANGELOWER,
ID_REGISTERLIST_CHANGEUPPER, 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: 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); int actualX = width-4-(startIndex+1)*(8*charWidth+2);
x = std::max<int>(actualX,x); x = std::max<int>(actualX,x);
@ -396,23 +410,33 @@ void CtrlRegisterList::onPopupClick(wxCommandEvent& evt)
switch (evt.GetId()) switch (evt.GetId())
{ {
case ID_REGISTERLIST_DISPLAY32: case ID_REGISTERLIST_DISPLAY32:
resolvePointerStrings = false;
maxBits = 32; maxBits = 32;
SetInitialSize(ClientToWindowSize(GetMinClientSize())); SetInitialSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0); postEvent(debEVT_UPDATELAYOUT,0);
Refresh(); Refresh();
break; break;
case ID_REGISTERLIST_DISPLAY64: case ID_REGISTERLIST_DISPLAY64:
resolvePointerStrings = false;
maxBits = 64; maxBits = 64;
SetInitialSize(ClientToWindowSize(GetMinClientSize())); SetInitialSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0); postEvent(debEVT_UPDATELAYOUT,0);
Refresh(); Refresh();
break; break;
case ID_REGISTERLIST_DISPLAY128: case ID_REGISTERLIST_DISPLAY128:
resolvePointerStrings = false;
maxBits = 128; maxBits = 128;
SetInitialSize(ClientToWindowSize(GetMinClientSize())); SetInitialSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0); postEvent(debEVT_UPDATELAYOUT,0);
Refresh(); Refresh();
break; break;
case ID_REGISTERLIST_DISPLAY128STRINGS:
resolvePointerStrings = true;
maxBits = 128;
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT, 0);
Refresh();
break;
case ID_REGISTERLIST_CHANGELOWER: case ID_REGISTERLIST_CHANGELOWER:
changeValue(LOWER64); changeValue(LOWER64);
Refresh(); Refresh();
@ -428,6 +452,12 @@ void CtrlRegisterList::onPopupClick(wxCommandEvent& evt)
changeValue(LOWER64); changeValue(LOWER64);
Refresh(); Refresh();
break; 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: default:
wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION); wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
break; break;
@ -496,6 +526,7 @@ void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY32, L"Display 32 bit"); menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY32, L"Display 32 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit"); menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit"); menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128STRINGS, L"Display 128 bit + Resolve string pointers");
menu.AppendSeparator(); menu.AppendSeparator();
if (bits >= 64) if (bits >= 64)
@ -506,10 +537,17 @@ void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
menu.Append(ID_REGISTERLIST_CHANGEVALUE, L"Change value"); 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) switch (maxBits)
{ {
case 128: case 128:
menu.Check(ID_REGISTERLIST_DISPLAY128,true); if (resolvePointerStrings)
menu.Check(ID_REGISTERLIST_DISPLAY128STRINGS, true);
else
menu.Check(ID_REGISTERLIST_DISPLAY128,true);
break; break;
case 64: case 64:
menu.Check(ID_REGISTERLIST_DISPLAY64,true); menu.Check(ID_REGISTERLIST_DISPLAY64,true);

View File

@ -72,4 +72,5 @@ private:
u32 lastPc; u32 lastPc;
int category; int category;
int maxBits; int maxBits;
}; bool resolvePointerStrings;
};

View File

@ -54,4 +54,4 @@ bool executeExpressionWindow(wxWindow* parent, DebugInterface* cpu, u64& dest, c
} }
return true; return true;
} }

View File

@ -501,8 +501,10 @@ void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt)
if (currentCpu != NULL) if (currentCpu != NULL)
{ {
currentCpu->showMemoryView(); 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) } else if (type == debEVT_RUNTOPOS)
{ {