Play-/Source/ui_win32/CallStackWnd.cpp
2018-04-30 21:01:23 +01:00

165 lines
3.8 KiB
C++

#include "CallStackWnd.h"
#include "PtrMacro.h"
#include "string_cast.h"
#include "lexical_cast_ex.h"
#include "DebugUtils.h"
#include "../MIPS.h"
#define CLSNAME _T("CallStackWnd")
CCallStackWnd::CCallStackWnd(HWND hParent, CVirtualMachine& virtualMachine, CMIPS* context, CBiosDebugInfoProvider* biosDebugInfoProvider)
: m_virtualMachine(virtualMachine)
, m_context(context)
, m_list(nullptr)
, m_biosDebugInfoProvider(biosDebugInfoProvider)
{
if(!DoesWindowClassExist(CLSNAME))
{
WNDCLASSEX wc;
memset(&wc, 0, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = CLSNAME;
wc.lpfnWndProc = CWindow::WndProc;
RegisterClassEx(&wc);
}
Create(NULL, CLSNAME, _T("Call Stack"), WS_CLIPCHILDREN | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_CHILD | WS_MAXIMIZEBOX, Framework::Win32::CRect(0, 0, 320, 240), hParent, NULL);
SetClassPtr();
m_list = new Framework::Win32::CListView(m_hWnd, Framework::Win32::CRect(0, 0, 1, 1), LVS_REPORT);
m_list->SetExtendedListViewStyle(m_list->GetExtendedListViewStyle() | LVS_EX_FULLROWSELECT);
m_virtualMachine.OnMachineStateChange.connect(boost::bind(&CCallStackWnd::Update, this));
m_virtualMachine.OnRunningStateChange.connect(boost::bind(&CCallStackWnd::Update, this));
CreateColumns();
RefreshLayout();
Update();
}
CCallStackWnd::~CCallStackWnd()
{
delete m_list;
}
long CCallStackWnd::OnSize(unsigned int nType, unsigned int nX, unsigned int nY)
{
RefreshLayout();
return TRUE;
}
long CCallStackWnd::OnSysCommand(unsigned int nCmd, LPARAM lParam)
{
switch(nCmd)
{
case SC_CLOSE:
Show(SW_HIDE);
return FALSE;
}
return TRUE;
}
LRESULT CCallStackWnd::OnNotify(WPARAM wParam, NMHDR* pHDR)
{
switch(pHDR->code)
{
case NM_DBLCLK:
OnListDblClick();
return FALSE;
break;
}
return FALSE;
}
void CCallStackWnd::RefreshLayout()
{
if(m_list != NULL)
{
{
RECT rc = GetClientRect();
m_list->SetSize(rc.right, rc.bottom);
}
{
RECT rc = m_list->GetClientRect();
m_list->SetColumnWidth(0, rc.right);
}
}
}
void CCallStackWnd::CreateColumns()
{
LVCOLUMN col;
RECT rc = m_list->GetClientRect();
memset(&col, 0, sizeof(LVCOLUMN));
col.pszText = _T("Function");
col.mask = LVCF_TEXT;
m_list->InsertColumn(0, col);
}
void CCallStackWnd::Update()
{
uint32 nPC = m_context->m_State.nPC;
uint32 nRA = m_context->m_State.nGPR[CMIPS::RA].nV[0];
uint32 nSP = m_context->m_State.nGPR[CMIPS::SP].nV[0];
m_list->SetRedraw(false);
m_list->DeleteAllItems();
auto callStackItems = CMIPSAnalysis::GetCallStack(m_context, nPC, nSP, nRA);
if(callStackItems.size() == 0)
{
//Cannot go further
LVITEM item;
memset(&item, 0, sizeof(LVITEM));
item.pszText = _T("Call stack unavailable at this state.");
item.mask = LVIF_TEXT | LVIF_PARAM;
item.lParam = MIPS_INVALID_PC;
m_list->InsertItem(item);
m_list->SetRedraw(true);
return;
}
auto modules = m_biosDebugInfoProvider ? m_biosDebugInfoProvider->GetModulesDebugInfo() : BiosDebugModuleInfoArray();
for(const auto& callStackItem : callStackItems)
{
//Add the current function
LVITEM item;
memset(&item, 0, sizeof(LVITEM));
item.pszText = _T("");
item.iItem = m_list->GetItemCount();
item.mask = LVIF_TEXT | LVIF_PARAM;
item.lParam = callStackItem;
unsigned int i = m_list->InsertItem(item);
auto locationString = DebugUtils::PrintAddressLocation(callStackItem, m_context, modules);
m_list->SetItemText(i, 0, locationString.c_str());
}
m_list->SetRedraw(true);
}
void CCallStackWnd::OnListDblClick()
{
int nSelection = m_list->GetSelection();
if(nSelection != -1)
{
uint32 nAddress = m_list->GetItemData(nSelection);
if(nAddress != MIPS_INVALID_PC)
{
OnFunctionDblClick(nAddress);
}
}
}