2006-12-26 21:53:04 +00:00
|
|
|
#include <boost/bind.hpp>
|
2006-06-15 04:19:30 +00:00
|
|
|
#include "CallStackWnd.h"
|
|
|
|
#include "PtrMacro.h"
|
2006-12-29 04:51:50 +00:00
|
|
|
#include "string_cast.h"
|
|
|
|
#include "lexical_cast_ex.h"
|
2006-07-13 02:44:13 +00:00
|
|
|
#include "../MIPS.h"
|
2006-06-15 04:19:30 +00:00
|
|
|
|
2006-12-29 04:51:50 +00:00
|
|
|
#define CLSNAME _T("CallStackWnd")
|
2006-06-15 04:19:30 +00:00
|
|
|
|
|
|
|
using namespace Framework;
|
2006-12-26 21:53:04 +00:00
|
|
|
using namespace boost;
|
2006-12-29 04:51:50 +00:00
|
|
|
using namespace std;
|
2006-06-15 04:19:30 +00:00
|
|
|
|
2007-12-01 04:08:34 +00:00
|
|
|
CCallStackWnd::CCallStackWnd(HWND hParent, CVirtualMachine& virtualMachine, CMIPS* pCtx) :
|
|
|
|
m_virtualMachine(virtualMachine),
|
|
|
|
m_pCtx(pCtx)
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetRect(&rc, 0, 0, 320, 240);
|
|
|
|
|
2006-12-29 04:51:50 +00:00
|
|
|
Create(NULL, CLSNAME, _T("Call Stack"), WS_CLIPCHILDREN | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_CHILD | WS_MAXIMIZEBOX, &rc, hParent, NULL);
|
2006-06-15 04:19:30 +00:00
|
|
|
SetClassPtr();
|
|
|
|
|
|
|
|
SetRect(&rc, 0, 0, 1, 1);
|
|
|
|
|
2007-01-11 02:44:56 +00:00
|
|
|
m_pList = new Win32::CListView(m_hWnd, &rc, LVS_REPORT);
|
2006-06-15 04:19:30 +00:00
|
|
|
m_pList->SetExtendedListViewStyle(m_pList->GetExtendedListViewStyle() | LVS_EX_FULLROWSELECT);
|
|
|
|
|
2007-12-01 04:08:34 +00:00
|
|
|
m_virtualMachine.m_OnMachineStateChange.connect(bind(&CCallStackWnd::OnMachineStateChange, this));
|
|
|
|
m_virtualMachine.m_OnRunningStateChange.connect(bind(&CCallStackWnd::OnRunningStateChange, this));
|
2006-06-15 04:19:30 +00:00
|
|
|
|
|
|
|
CreateColumns();
|
|
|
|
|
|
|
|
RefreshLayout();
|
|
|
|
Update();
|
|
|
|
}
|
|
|
|
|
|
|
|
CCallStackWnd::~CCallStackWnd()
|
|
|
|
{
|
|
|
|
DELETEPTR(m_pList);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
long CCallStackWnd::OnNotify(WPARAM wParam, NMHDR* pHDR)
|
|
|
|
{
|
|
|
|
switch(pHDR->code)
|
|
|
|
{
|
|
|
|
case NM_DBLCLK:
|
|
|
|
OnListDblClick();
|
|
|
|
return FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-06-26 09:31:14 +00:00
|
|
|
return FALSE;
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCallStackWnd::RefreshLayout()
|
|
|
|
{
|
|
|
|
RECT rc;
|
|
|
|
|
|
|
|
GetClientRect(&rc);
|
|
|
|
|
|
|
|
if(m_pList != NULL)
|
|
|
|
{
|
|
|
|
m_pList->SetSize(rc.right, rc.bottom);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pList->GetClientRect(&rc);
|
|
|
|
|
|
|
|
m_pList->SetColumnWidth(0, rc.right / 2);
|
|
|
|
m_pList->SetColumnWidth(1, rc.right / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCallStackWnd::CreateColumns()
|
|
|
|
{
|
|
|
|
LVCOLUMN col;
|
|
|
|
RECT rc;
|
|
|
|
|
|
|
|
m_pList->GetClientRect(&rc);
|
|
|
|
|
|
|
|
memset(&col, 0, sizeof(LVCOLUMN));
|
2006-12-29 04:51:50 +00:00
|
|
|
col.pszText = _T("Function");
|
2006-06-15 04:19:30 +00:00
|
|
|
col.mask = LVCF_TEXT;
|
|
|
|
m_pList->InsertColumn(0, &col);
|
|
|
|
|
|
|
|
memset(&col, 0, sizeof(LVCOLUMN));
|
2006-12-29 04:51:50 +00:00
|
|
|
col.pszText = _T("Caller");
|
2006-06-15 04:19:30 +00:00
|
|
|
col.mask = LVCF_TEXT;
|
|
|
|
m_pList->InsertColumn(1, &col);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCallStackWnd::Update()
|
|
|
|
{
|
|
|
|
uint32 nPC, nRA, nSP;
|
2006-10-12 06:16:48 +00:00
|
|
|
CMIPSAnalysis::SUBROUTINE* pRoutine;
|
2006-06-15 04:19:30 +00:00
|
|
|
LVITEM item;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
nPC = m_pCtx->m_State.nPC;
|
|
|
|
nRA = m_pCtx->m_State.nGPR[CMIPS::RA].nV[0];
|
|
|
|
nSP = m_pCtx->m_State.nGPR[CMIPS::SP].nV[0];
|
|
|
|
|
|
|
|
m_pList->SetRedraw(false);
|
|
|
|
|
|
|
|
m_pList->DeleteAllItems();
|
|
|
|
|
|
|
|
pRoutine = m_pCtx->m_pAnalysis->FindSubroutine(nPC);
|
|
|
|
if(pRoutine == NULL)
|
|
|
|
{
|
|
|
|
//Cannot go further
|
|
|
|
memset(&item, 0, sizeof(LVITEM));
|
2006-12-29 04:51:50 +00:00
|
|
|
item.pszText = _T("Call stack unavailable at this state.");
|
2006-06-15 04:19:30 +00:00
|
|
|
item.mask = LVIF_TEXT | LVIF_PARAM;
|
|
|
|
item.lParam = MIPS_INVALID_PC;
|
|
|
|
m_pList->InsertItem(&item);
|
|
|
|
|
|
|
|
m_pList->SetRedraw(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//We need to get to a state where we're ready to dig into the previous function's
|
|
|
|
//stack
|
|
|
|
|
|
|
|
//Check if we need to check into the stack to get the RA
|
|
|
|
if(m_pCtx->m_pAnalysis->FindSubroutine(nRA) == pRoutine)
|
|
|
|
{
|
|
|
|
nRA = m_pCtx->m_pMemoryMap->GetWord(nSP + pRoutine->nReturnAddrPos);
|
|
|
|
nSP += pRoutine->nStackSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//We haven't called a sub routine yet... The RA is good, but we
|
|
|
|
//don't know wether stack memory has been allocated or not
|
|
|
|
|
|
|
|
//ADDIU SP, SP, 0x????
|
|
|
|
//If the PC is after this instruction, then, we've allocated stack
|
|
|
|
|
|
|
|
if(nPC > pRoutine->nStackAllocStart)
|
|
|
|
{
|
|
|
|
if(nPC <= pRoutine->nStackAllocEnd)
|
|
|
|
{
|
|
|
|
nSP += pRoutine->nStackSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
2006-12-29 04:51:50 +00:00
|
|
|
const char* sName;
|
|
|
|
|
2006-06-15 04:19:30 +00:00
|
|
|
//Add the current function
|
|
|
|
memset(&item, 0, sizeof(LVITEM));
|
2006-12-29 04:51:50 +00:00
|
|
|
item.pszText = _T("");
|
2006-06-15 04:19:30 +00:00
|
|
|
item.iItem = m_pList->GetItemCount();
|
|
|
|
item.mask = LVIF_TEXT | LVIF_PARAM;
|
|
|
|
item.lParam = pRoutine->nStart;
|
|
|
|
i = m_pList->InsertItem(&item);
|
|
|
|
|
|
|
|
sName = m_pCtx->m_Functions.Find(pRoutine->nStart);
|
|
|
|
|
2006-12-29 04:51:50 +00:00
|
|
|
m_pList->SetItemText(i, 0, (
|
|
|
|
_T("0x") + lexical_cast_hex<tstring>(pRoutine->nStart, 8) +
|
|
|
|
(sName != NULL ? (_T(" (") + string_cast<tstring>(sName) + _T(")")) : _T(""))
|
|
|
|
).c_str());
|
2006-06-15 04:19:30 +00:00
|
|
|
|
2006-12-29 04:51:50 +00:00
|
|
|
m_pList->SetItemText(i, 1, (
|
|
|
|
_T("0x") + lexical_cast_hex<tstring>(nRA - 4, 8)
|
|
|
|
).c_str());
|
2006-06-15 04:19:30 +00:00
|
|
|
|
|
|
|
//Go to previous routine
|
|
|
|
nPC = nRA - 4;
|
|
|
|
|
|
|
|
//Check if we can go on...
|
|
|
|
pRoutine = m_pCtx->m_pAnalysis->FindSubroutine(nPC);
|
|
|
|
if(pRoutine == NULL) break;
|
|
|
|
|
|
|
|
//Get the next RA
|
|
|
|
nRA = m_pCtx->m_pMemoryMap->GetWord(nSP + pRoutine->nReturnAddrPos);
|
|
|
|
nSP += pRoutine->nStackSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pList->SetRedraw(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCallStackWnd::OnListDblClick()
|
|
|
|
{
|
|
|
|
int nSelection;
|
|
|
|
uint32 nAddress;
|
|
|
|
|
|
|
|
nSelection = m_pList->GetSelection();
|
|
|
|
if(nSelection != -1)
|
|
|
|
{
|
|
|
|
nAddress = m_pList->GetItemData(nSelection);
|
|
|
|
if(nAddress != MIPS_INVALID_PC)
|
|
|
|
{
|
2006-12-29 04:51:50 +00:00
|
|
|
m_OnFunctionDblClick(nAddress);
|
2006-06-15 04:19:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-26 21:53:04 +00:00
|
|
|
void CCallStackWnd::OnMachineStateChange()
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
|
|
|
Update();
|
|
|
|
}
|
|
|
|
|
2006-12-26 21:53:04 +00:00
|
|
|
void CCallStackWnd::OnRunningStateChange()
|
2006-06-15 04:19:30 +00:00
|
|
|
{
|
|
|
|
Update();
|
|
|
|
}
|