mirror of
https://github.com/libretro/Play-.git
synced 2024-11-28 03:00:49 +00:00
165 lines
3.8 KiB
C++
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);
|
|
}
|
|
}
|
|
}
|