ppsspp/Windows/Debugger/CtrlMemView.cpp

554 lines
12 KiB
C++
Raw Normal View History

2012-11-01 16:19:01 +01:00
// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
#include <tchar.h>
#include <math.h>
#include "../../globals.h"
#include "Core/Config.h"
2012-11-01 16:19:01 +01:00
#include "../resource.h"
#include "../../Core/MemMap.h"
#include "../W32Util/Misc.h"
#include "../Main.h"
#include "../../Core/Debugger/SymbolMap.h"
#include "Debugger_Disasm.h"
#include "DebuggerShared.h"
2012-11-01 16:19:01 +01:00
#include "CtrlMemView.h"
wchar_t CtrlMemView::szClassName[] = L"CtrlMemView";
2012-11-01 16:19:01 +01:00
extern HMENU g_hPopupMenus;
CtrlMemView::CtrlMemView(HWND _wnd)
{
wnd=_wnd;
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG)this);
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL);
SetScrollRange(wnd, SB_VERT, -1,1,TRUE);
rowHeight = g_Config.iFontHeight;
charWidth = g_Config.iFontWidth;
font =
CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console");
underlineFont =
CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console");
curAddress=0;
debugger = 0;
2013-06-25 02:43:31 +02:00
ctrlDown = false;
2013-06-25 02:43:31 +02:00
hasFocus = false;
windowStart = curAddress;
asciiSelected = false;
selectedNibble = 0;
rowSize = 16;
addressStart = charWidth;
hexStart = addressStart + 9*charWidth;
asciiStart = hexStart + (rowSize*3+1)*charWidth;
2012-11-01 16:19:01 +01:00
}
CtrlMemView::~CtrlMemView()
{
DeleteObject(font);
}
void CtrlMemView::init()
{
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
wc.lpszClassName = szClassName;
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = CtrlMemView::wndProc;
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hIcon = 0;
wc.lpszMenuName = 0;
wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
wc.style = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof( CtrlMemView * );
wc.hIconSm = 0;
RegisterClassEx(&wc);
}
void CtrlMemView::deinit()
{
//UnregisterClass(szClassName, hInst)
}
LRESULT CALLBACK CtrlMemView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CtrlMemView *ccp = CtrlMemView::getFrom(hwnd);
static bool lmbDown=false,rmbDown=false;
switch(msg)
{
case WM_NCCREATE:
// Allocate a new CustCtrl structure for this window.
ccp = new CtrlMemView(hwnd);
// Continue with window creation.
return ccp != NULL;
// Clean up when the window is destroyed.
case WM_NCDESTROY:
delete ccp;
break;
case WM_SETFONT:
break;
case WM_SIZE:
ccp->redraw();
break;
case WM_PAINT:
ccp->onPaint(wParam,lParam);
break;
case WM_VSCROLL:
ccp->onVScroll(wParam,lParam);
break;
2013-06-25 02:43:31 +02:00
case WM_MOUSEWHEEL:
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
{
ccp->scrollWindow(-3);
} else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {
ccp->scrollWindow(3);
}
break;
2012-11-01 16:19:01 +01:00
case WM_ERASEBKGND:
return FALSE;
case WM_KEYDOWN:
ccp->onKeyDown(wParam,lParam);
return 0;
2013-06-25 02:43:31 +02:00
case WM_CHAR:
ccp->onChar(wParam,lParam);
return 0;
case WM_KEYUP:
if (wParam == VK_CONTROL) ccp->ctrlDown = false;
return 0;
2012-11-01 16:19:01 +01:00
case WM_LBUTTONDOWN: SetFocus(hwnd); lmbDown=true; ccp->onMouseDown(wParam,lParam,1); break;
case WM_RBUTTONDOWN: SetFocus(hwnd); rmbDown=true; ccp->onMouseDown(wParam,lParam,2); break;
2012-11-01 16:19:01 +01:00
case WM_MOUSEMOVE: ccp->onMouseMove(wParam,lParam,(lmbDown?1:0) | (rmbDown?2:0)); break;
case WM_LBUTTONUP: lmbDown=false; ccp->onMouseUp(wParam,lParam,1); break;
case WM_RBUTTONUP: rmbDown=false; ccp->onMouseUp(wParam,lParam,2); break;
case WM_SETFOCUS:
SetFocus(hwnd);
ccp->hasFocus=true;
ccp->redraw();
break;
case WM_KILLFOCUS:
ccp->hasFocus=false;
ccp->redraw();
break;
2013-06-25 02:43:31 +02:00
case WM_GETDLGCODE: // we want to process the arrow keys and all characters ourselves
return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_WANTTAB;
2013-06-25 02:43:31 +02:00
break;
2012-11-01 16:19:01 +01:00
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
CtrlMemView *CtrlMemView::getFrom(HWND hwnd)
{
return (CtrlMemView *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
void CtrlMemView::onPaint(WPARAM wParam, LPARAM lParam)
{
2013-06-25 02:43:31 +02:00
// draw to a bitmap for double buffering
PAINTSTRUCT ps;
HDC actualHdc = BeginPaint(wnd, &ps);
HDC hdc = CreateCompatibleDC(actualHdc);
HBITMAP hBM = CreateCompatibleBitmap(actualHdc, rect.right-rect.left, rect.bottom-rect.top);
SelectObject(hdc, hBM);
SetBkMode(hdc,OPAQUE);
HPEN standardPen = CreatePen(0,0,0xFFFFFF);
HBRUSH standardBrush = CreateSolidBrush(0xFFFFFF);
HPEN oldPen = (HPEN) SelectObject(hdc,standardPen);
HBRUSH oldBrush = (HBRUSH) SelectObject(hdc,standardBrush);
HFONT oldFont = (HFONT) SelectObject(hdc,(HGDIOBJ)font);
// white background
SelectObject(hdc,standardPen);
SelectObject(hdc,standardBrush);
Rectangle(hdc,0,0,rect.right,rect.bottom);
// draw one extra row that may be partially visible
for (int i = 0; i < visibleRows+1; i++)
2012-11-01 16:19:01 +01:00
{
2013-06-25 02:43:31 +02:00
char temp[32];
2012-11-01 16:19:01 +01:00
2013-06-25 02:43:31 +02:00
unsigned int address=windowStart + i*rowSize;
int rowY = rowHeight*i;
sprintf(temp,"%08X",address);
2012-11-01 16:19:01 +01:00
SetTextColor(hdc,0x600000);
TextOutA(hdc,addressStart,rowY,temp,(int)strlen(temp));
2013-06-25 02:43:31 +02:00
2012-11-01 16:19:01 +01:00
SetTextColor(hdc,0x000000);
u32 memory[4];
bool valid = debugger != NULL && debugger->isAlive() && Memory::IsValidAddress(address);
if (valid)
{
memory[0] = debugger->readMemory(address);
memory[1] = debugger->readMemory(address+4);
memory[2] = debugger->readMemory(address+8);
memory[3] = debugger->readMemory(address+12);
}
u8* m = (u8*) memory;
for (int j = 0; j < rowSize; j++)
2012-11-01 16:19:01 +01:00
{
if (valid) sprintf(temp,"%02X",m[j]);
else strcpy(temp,"??");
unsigned char c = m[j];
if (c < 32 || c >= 128 || valid == false) c = '.';
2012-11-01 16:19:01 +01:00
if (address+j == curAddress)
{
COLORREF oldBkColor = GetBkColor(hdc);
COLORREF oldTextColor = GetTextColor(hdc);
if (hasFocus && !asciiSelected)
2012-11-01 16:19:01 +01:00
{
SetTextColor(hdc,0xFFFFFF);
SetBkColor(hdc,0xFF9933);
if (selectedNibble == 0) SelectObject(hdc,(HGDIOBJ)underlineFont);
} else {
SetTextColor(hdc,0);
SetBkColor(hdc,0xC0C0C0);
}
TextOutA(hdc,hexStart+j*3*charWidth,rowY,&temp[0],1);
2013-06-25 02:43:31 +02:00
if (hasFocus && !asciiSelected)
{
if (selectedNibble == 1) SelectObject(hdc,(HGDIOBJ)underlineFont);
else SelectObject(hdc,(HGDIOBJ)font);
2012-11-01 16:19:01 +01:00
}
TextOutA(hdc,hexStart+j*3*charWidth+charWidth,rowY,&temp[1],1);
if (hasFocus && asciiSelected)
2012-11-01 16:19:01 +01:00
{
SetTextColor(hdc,0xFFFFFF);
SetBkColor(hdc,0xFF9933);
} else {
SetTextColor(hdc,0);
SetBkColor(hdc,0xC0C0C0);
SelectObject(hdc,(HGDIOBJ)font);
}
TextOutA(hdc,asciiStart+j*(charWidth+2),rowY,(char*)&c,1);
SetTextColor(hdc,oldTextColor);
SetBkColor(hdc,oldBkColor);
} else {
TextOutA(hdc,hexStart+j*3*charWidth,rowY,temp,2);
TextOutA(hdc,asciiStart+j*(charWidth+2),rowY,(char*)&c,1);
2012-11-01 16:19:01 +01:00
}
}
}
SelectObject(hdc,oldFont);
SelectObject(hdc,oldPen);
SelectObject(hdc,oldBrush);
2013-06-25 02:43:31 +02:00
// copy bitmap to the actual hdc
BitBlt(actualHdc,0,0,rect.right,rect.bottom,hdc,0,0,SRCCOPY);
DeleteObject(hBM);
DeleteDC(hdc);
2012-11-01 16:19:01 +01:00
2013-06-25 02:43:31 +02:00
DeleteObject(standardPen);
DeleteObject(standardBrush);
2012-11-01 16:19:01 +01:00
EndPaint(wnd, &ps);
}
void CtrlMemView::onVScroll(WPARAM wParam, LPARAM lParam)
{
switch (wParam & 0xFFFF)
{
case SB_LINEDOWN:
2013-06-25 02:43:31 +02:00
scrollWindow(1);
2012-11-01 16:19:01 +01:00
break;
case SB_LINEUP:
2013-06-25 02:43:31 +02:00
scrollWindow(-1);
2012-11-01 16:19:01 +01:00
break;
case SB_PAGEDOWN:
2013-06-25 02:43:31 +02:00
scrollWindow(visibleRows);
2012-11-01 16:19:01 +01:00
break;
case SB_PAGEUP:
2013-06-25 02:43:31 +02:00
scrollWindow(-visibleRows);
2012-11-01 16:19:01 +01:00
break;
default:
return;
}
}
void CtrlMemView::onKeyDown(WPARAM wParam, LPARAM lParam)
{
if (ctrlDown && tolower(wParam & 0xFFFF) == 'g')
{
ctrlDown = false;
u32 addr;
if (executeExpressionWindow(wnd,debugger,addr) == false) return;
gotoAddr(addr);
return;
}
2012-11-01 16:19:01 +01:00
switch (wParam & 0xFFFF)
{
case VK_DOWN:
2013-06-25 02:43:31 +02:00
scrollCursor(rowSize);
2012-11-01 16:19:01 +01:00
break;
case VK_UP:
2013-06-25 02:43:31 +02:00
scrollCursor(-rowSize);
break;
case VK_LEFT:
scrollCursor(-1);
break;
case VK_RIGHT:
scrollCursor(1);
2012-11-01 16:19:01 +01:00
break;
case VK_NEXT:
2013-06-25 02:43:31 +02:00
scrollWindow(visibleRows);
2012-11-01 16:19:01 +01:00
break;
case VK_PRIOR:
2013-06-25 02:43:31 +02:00
scrollWindow(-visibleRows);
2012-11-01 16:19:01 +01:00
break;
case VK_CONTROL:
ctrlDown = true;
break;
case VK_TAB:
SendMessage(GetParent(wnd),WM_DEB_TABPRESSED,0,0);
break;
2012-11-01 16:19:01 +01:00
default:
return;
}
}
2013-06-25 02:43:31 +02:00
void CtrlMemView::onChar(WPARAM wParam, LPARAM lParam)
{
if (ctrlDown || wParam == VK_TAB) return;
2013-06-25 02:43:31 +02:00
if (!Memory::IsValidAddress(curAddress))
{
scrollCursor(1);
return;
}
bool active = Core_IsActive();
if (active) Core_EnableStepping(true);
if (asciiSelected)
{
u8 newValue = wParam;
Memory::WriteUnchecked_U8(newValue,curAddress);
scrollCursor(1);
} else {
wParam = tolower(wParam);
int inputValue = -1;
if (wParam >= '0' && wParam <= '9') inputValue = wParam - '0';
if (wParam >= 'a' && wParam <= 'f') inputValue = wParam -'a' + 10;
if (inputValue >= 0)
{
int shiftAmount = (1-selectedNibble)*4;
u8 oldValue = Memory::ReadUnchecked_U8(curAddress);
oldValue &= ~(0xF << shiftAmount);
u8 newValue = oldValue | (inputValue << shiftAmount);
Memory::WriteUnchecked_U8(newValue,curAddress);
scrollCursor(1);
}
}
if (active) Core_EnableStepping(false);
}
2012-11-01 16:19:01 +01:00
void CtrlMemView::redraw()
{
2013-06-25 02:43:31 +02:00
GetClientRect(wnd, &rect);
visibleRows = (rect.bottom/rowHeight);
2012-11-01 16:19:01 +01:00
InvalidateRect(wnd, NULL, FALSE);
UpdateWindow(wnd);
}
void CtrlMemView::onMouseDown(WPARAM wParam, LPARAM lParam, int button)
{
int x = LOWORD(lParam);
2013-06-25 02:43:31 +02:00
int y = HIWORD(lParam);
gotoPoint(x,y);
2012-11-01 16:19:01 +01:00
}
void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
{
if (button==2)
{
//popup menu?
POINT pt;
GetCursorPos(&pt);
FILE* outputfile;
2012-11-01 16:19:01 +01:00
switch (TrackPopupMenuEx(GetSubMenu(g_hPopupMenus,0),TPM_RIGHTBUTTON|TPM_RETURNCMD,pt.x,pt.y,wnd,0))
{
case ID_MEMVIEW_DUMP:
if (!Core_IsStepping()) // If emulator isn't paused
{
MessageBox(wnd,L"You have to pause the emulator first",0,0);
break;
}
else
{
2013-03-22 20:46:19 +01:00
outputfile = fopen("Ram.dump","wb"); // Could also dump Vram, but not useful for now.
fwrite(Memory::GetPointer(0x08800000), 1, 0x01800000, outputfile);
fclose(outputfile);
break;
2013-03-22 20:46:19 +01:00
}
2012-11-01 16:19:01 +01:00
case ID_MEMVIEW_COPYVALUE:
{
char temp[24];
// it's admittedly not really useful like this
if (asciiSelected)
{
unsigned char c = Memory::IsValidAddress(curAddress) ? Memory::ReadUnchecked_U8(curAddress) : '.';
if (c < 32 || c >= 128) c = '.';
sprintf(temp,"%c",c);
} else {
sprintf(temp,"%02X",Memory::IsValidAddress(curAddress) ? Memory::ReadUnchecked_U8(curAddress) : 0xFF);
}
2012-11-01 16:19:01 +01:00
W32Util::CopyTextToClipboard(wnd,temp);
}
break;
}
return;
}
2013-06-25 02:43:31 +02:00
2012-11-01 16:19:01 +01:00
int x = LOWORD(lParam);
2013-06-25 02:43:31 +02:00
int y = HIWORD(lParam);
ReleaseCapture();
gotoPoint(x,y);
2012-11-01 16:19:01 +01:00
}
void CtrlMemView::onMouseMove(WPARAM wParam, LPARAM lParam, int button)
{
2013-06-25 02:43:31 +02:00
}
2013-07-30 16:19:05 +02:00
void CtrlMemView::updateStatusBarText()
{
char text[64];
sprintf(text,"%08X",curAddress);
SendMessage(GetParent(wnd),WM_DEB_SETSTATUSBARTEXT,0,(LPARAM)text);
}
2013-06-25 02:43:31 +02:00
void CtrlMemView::gotoPoint(int x, int y)
{
int line = y/rowHeight;
int lineAddress = windowStart+line*rowSize;
if (x >= asciiStart)
2012-11-01 16:19:01 +01:00
{
2013-06-25 02:43:31 +02:00
int col = (x-asciiStart) / (charWidth+2);
if (col >= rowSize) return;
asciiSelected = true;
curAddress = lineAddress+col;
selectedNibble = 0;
2013-07-30 16:19:05 +02:00
updateStatusBarText();
2013-06-25 02:43:31 +02:00
redraw();
} else if (x >= hexStart)
{
int col = (x-hexStart) / charWidth;
if ((col/3) >= rowSize) return;
switch (col % 3)
2012-11-01 16:19:01 +01:00
{
2013-06-25 02:43:31 +02:00
case 0: selectedNibble = 0; break;
case 1: selectedNibble = 1; break;
case 2: return; // don't change position when clicking on the space
2012-11-01 16:19:01 +01:00
}
2013-06-25 02:43:31 +02:00
asciiSelected = false;
curAddress = lineAddress+col/3;
2013-07-30 16:19:05 +02:00
updateStatusBarText();
2013-06-25 02:43:31 +02:00
redraw();
2012-11-01 16:19:01 +01:00
}
2013-06-25 02:43:31 +02:00
}
2012-11-01 16:19:01 +01:00
2013-06-25 02:43:31 +02:00
void CtrlMemView::gotoAddr(unsigned int addr)
{
int lines=(rect.bottom/rowHeight);
2013-06-29 10:59:42 -07:00
u32 windowEnd = windowStart+lines*rowSize;
2013-06-25 02:43:31 +02:00
curAddress = addr;
selectedNibble = 0;
if (curAddress < windowStart || curAddress >= windowEnd)
{
windowStart = curAddress & ~15;
}
2013-07-30 16:19:05 +02:00
updateStatusBarText();
2013-06-25 02:43:31 +02:00
redraw();
}
2012-11-01 16:19:01 +01:00
2013-06-25 02:43:31 +02:00
void CtrlMemView::scrollWindow(int lines)
2012-11-01 16:19:01 +01:00
{
2013-06-25 02:43:31 +02:00
windowStart += lines*rowSize;
curAddress += lines*rowSize;
redraw();
2012-11-01 16:19:01 +01:00
}
2013-06-25 02:43:31 +02:00
void CtrlMemView::scrollCursor(int bytes)
{
if (!asciiSelected && bytes == 1)
{
if (selectedNibble == 0)
{
selectedNibble = 1;
bytes = 0;
} else {
selectedNibble = 0;
}
} else if (!asciiSelected && bytes == -1)
{
if (selectedNibble == 0)
{
selectedNibble = 1;
} else {
selectedNibble = 0;
bytes = 0;
}
}
curAddress += bytes;
2013-06-29 10:59:42 -07:00
u32 windowEnd = windowStart+visibleRows*rowSize;
2013-06-25 02:43:31 +02:00
if (curAddress < windowStart)
{
windowStart = curAddress & ~15;
} else if (curAddress >= windowEnd)
{
windowStart = (curAddress-(visibleRows-1)*rowSize) & ~15;
}
2013-07-30 16:19:05 +02:00
updateStatusBarText();
2013-06-25 02:43:31 +02:00
redraw();
}