CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Windows/Debugger/Debugger_Disasm.cpp
Views: 1401
#include "Core/Config.h"1#include "Core/MemMap.h"2#include "Windows/resource.h"3#include "Windows/InputBox.h"45#include "Core/Debugger/Breakpoints.h"6#include "Core/Debugger/SymbolMap.h"7#include "Windows/Debugger/BreakpointWindow.h"8#include "Windows/Debugger/CtrlDisAsmView.h"9#include "Windows/Debugger/Debugger_MemoryDlg.h"10#include "Windows/Debugger/Debugger_Disasm.h"11#include "Windows/Debugger/Debugger_VFPUDlg.h"12#include "Windows/Debugger/DebuggerShared.h"13// #include "Windows/W32Util/DarkMode.h"1415#include "Windows/main.h"16#include "Windows/Debugger/CtrlRegisterList.h"17#include "Windows/Debugger/CtrlMemView.h"18#include "Windows/Debugger/Debugger_Lists.h"19#include "Windows/MainWindow.h"2021#include "Core/Core.h"22#include "Core/HLE/HLE.h"23#include "Core/CoreTiming.h"24#include "Core/MIPS/MIPSAnalyst.h"2526#include "Common/Data/Encoding/Utf8.h"2728#include "Common/CommonWindows.h"29#include "Common/StringUtils.h"3031#include <windowsx.h>32#include <commctrl.h>3334static FAR WNDPROC DefGotoEditProc;3536LRESULT CALLBACK GotoEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)37{38switch(message)39{40case WM_KEYDOWN:41if( wParam == VK_RETURN )42{43SendMessage(GetParent(hDlg),WM_DEB_GOTOADDRESSEDIT,0,0);44return 0;45}46break;47case WM_KEYUP:48if( wParam == VK_RETURN ) return 0;49break;50case WM_CHAR:51if( wParam == VK_RETURN ) return 0;52break;53case WM_GETDLGCODE:54if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)55{56if (wParam == VK_RETURN) return DLGC_WANTMESSAGE;57}58break;59};6061return (LRESULT)CallWindowProc((WNDPROC)DefGotoEditProc,hDlg,message,wParam,lParam);62}6364static FAR WNDPROC DefFuncListProc;6566LRESULT CALLBACK FuncListProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)67{68switch(message)69{70case WM_KEYDOWN:71if( wParam == VK_RETURN )72{73SendMessage(GetParent(hDlg),WM_COMMAND,MAKEWPARAM(IDC_FUNCTIONLIST,CBN_DBLCLK),0);74SetFocus(hDlg); // it's more natural to keep the focus when using keyboard controls75return 0;76}77break;78case WM_GETDLGCODE:79if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)80{81if (wParam == VK_RETURN) return DLGC_WANTMESSAGE;82}83break;84};8586return (LRESULT)CallWindowProc((WNDPROC)DefFuncListProc,hDlg,message,wParam,lParam);87}8889static constexpr UINT_PTR IDT_UPDATE = 0xC0DE0042;90static constexpr UINT UPDATE_DELAY = 1000 / 60;9192CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Dialog((LPCSTR)IDD_DISASM, _hInstance, _hParent) {93cpu = _cpu;94lastTicks = PSP_IsInited() ? CoreTiming::GetTicks() : 0;9596SetWindowText(m_hDlg, ConvertUTF8ToWString(_cpu->GetName()).c_str());9798RECT windowRect;99GetWindowRect(m_hDlg,&windowRect);100int defaultWidth = windowRect.right-windowRect.left;101int defaultHeight = windowRect.bottom-windowRect.top;102minWidth = defaultWidth - 100;103minHeight = defaultHeight - 200;104105int x = g_Config.iDisasmWindowX == -1 ? windowRect.left : g_Config.iDisasmWindowX;106int y = g_Config.iDisasmWindowY == -1 ? windowRect.top : g_Config.iDisasmWindowY;107int w = g_Config.iDisasmWindowW == -1 ? defaultWidth : g_Config.iDisasmWindowW;108int h = g_Config.iDisasmWindowH == -1 ? defaultHeight : g_Config.iDisasmWindowH;109110// init status bar111statusBarWnd = CreateWindowEx(0, STATUSCLASSNAME, L"", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, m_hDlg, (HMENU)IDC_DISASMSTATUSBAR, _hInstance, NULL);112if (g_Config.bDisplayStatusBar == false) {113ShowWindow(statusBarWnd,SW_HIDE);114}115116// set it to use two parts117RECT statusBarRect;118GetClientRect(statusBarWnd,&statusBarRect);119120int parts[2];121parts[1] = statusBarRect.right-statusBarRect.left;122parts[0] = parts[1]*2./3.;123124SendMessage(statusBarWnd, SB_SETPARTS, (WPARAM) 2, (LPARAM) parts);125126// init other controls127CtrlDisAsmView *ptr = DisAsmView();128ptr->setDebugger(cpu);129ptr->gotoAddr(0x00000000);130131CtrlRegisterList *rl = CtrlRegisterList::getFrom(GetDlgItem(m_hDlg,IDC_REGLIST));132rl->setCPU(cpu);133134leftTabs = new TabControl(GetDlgItem(m_hDlg,IDC_LEFTTABS));135leftTabs->SetIgnoreBottomMargin(true);136leftTabs->AddTab(GetDlgItem(m_hDlg,IDC_REGLIST),L"Regs");137leftTabs->AddTab(GetDlgItem(m_hDlg,IDC_FUNCTIONLIST),L"Funcs");138leftTabs->ShowTab(0);139140// subclass the goto edit box141HWND editWnd = GetDlgItem(m_hDlg,IDC_ADDRESS);142DefGotoEditProc = (WNDPROC)GetWindowLongPtr(editWnd,GWLP_WNDPROC);143SetWindowLongPtr(editWnd,GWLP_WNDPROC,(LONG_PTR)GotoEditProc);144145// subclass the function list146HWND funcListWnd = GetDlgItem(m_hDlg,IDC_FUNCTIONLIST);147DefFuncListProc = (WNDPROC)GetWindowLongPtr(funcListWnd,GWLP_WNDPROC);148SetWindowLongPtr(funcListWnd,GWLP_WNDPROC,(LONG_PTR)FuncListProc);149150// init bottom tabs151bottomTabs = new TabControl(GetDlgItem(m_hDlg,IDC_DEBUG_BOTTOMTABS));152153HWND memHandle = GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW);154CtrlMemView *mem = CtrlMemView::getFrom(memHandle);155mem->setDebugger(_cpu);156bottomTabs->AddTab(memHandle,L"Memory");157158breakpointList = new CtrlBreakpointList(GetDlgItem(m_hDlg,IDC_BREAKPOINTLIST),cpu,ptr);159breakpointList->reloadBreakpoints();160bottomTabs->AddTab(breakpointList->GetHandle(),L"Breakpoints");161162threadList = new CtrlThreadList(GetDlgItem(m_hDlg,IDC_THREADLIST));163threadList->reloadThreads();164bottomTabs->AddTab(threadList->GetHandle(),L"Threads");165166stackTraceView = new CtrlStackTraceView(GetDlgItem(m_hDlg,IDC_STACKFRAMES),cpu,ptr);167stackTraceView->loadStackTrace();168bottomTabs->AddTab(stackTraceView->GetHandle(),L"Stack frames");169170moduleList = new CtrlModuleList(GetDlgItem(m_hDlg,IDC_MODULELIST),cpu);171moduleList->loadModules();172bottomTabs->AddTab(moduleList->GetHandle(),L"Modules");173174watchList_ = new CtrlWatchList(GetDlgItem(m_hDlg, IDC_WATCHLIST), cpu);175bottomTabs->AddTab(watchList_->GetHandle(), L"Watch");176177bottomTabs->SetShowTabTitles(g_Config.bShowBottomTabTitles);178bottomTabs->ShowTab(memHandle);179180// Actually resize the window to the proper size (after the above setup.)181// do it twice so that the window definitely receives a WM_SIZE message with182// the correct size (the default from the .rc tends to be off)183MoveWindow(m_hDlg,x,y,1,1,FALSE);184MoveWindow(m_hDlg,x,y,w,h,TRUE);185SetDebugMode(true, true);186}187188CDisasm::~CDisasm()189{190DestroyWindow(statusBarWnd);191192delete leftTabs;193delete bottomTabs;194delete breakpointList;195delete threadList;196delete stackTraceView;197delete moduleList;198}199200void CDisasm::stepInto()201{202if (!PSP_IsInited() || !Core_IsStepping()) {203return;204}205206CtrlDisAsmView *ptr = DisAsmView();207lastTicks = CoreTiming::GetTicks();208u32 currentPc = cpu->GetPC();209210// If the current PC is on a breakpoint, the user doesn't want to do nothing.211CBreakPoints::SetSkipFirst(currentMIPS->pc);212u32 newAddress = currentPc+ptr->getInstructionSizeAt(currentPc);213214MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu,currentPc);215if (info.isBranch)216{217ptr->scrollStepping(newAddress);218} else {219bool scroll = true;220if (currentMIPS->inDelaySlot)221{222MIPSAnalyst::MipsOpcodeInfo prevInfo = MIPSAnalyst::GetOpcodeInfo(cpu,currentPc-cpu->getInstructionSize(0));223if (!prevInfo.isConditional || prevInfo.conditionMet)224scroll = false;225}226227if (scroll)228{229ptr->scrollStepping(newAddress);230}231}232233for (u32 i = 0; i < (newAddress-currentPc)/4; i++)234{235Core_DoSingleStep();236Sleep(1);237}238239ptr->gotoPC();240UpdateDialog();241242threadList->reloadThreads();243stackTraceView->loadStackTrace();244}245246void CDisasm::stepOver()247{248if (!PSP_IsInited() || Core_IsActive()) {249return;250}251252CtrlDisAsmView *ptr = DisAsmView();253lastTicks = CoreTiming::GetTicks();254255// If the current PC is on a breakpoint, the user doesn't want to do nothing.256CBreakPoints::SetSkipFirst(currentMIPS->pc);257u32 currentPc = cpu->GetPC();258259MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu,cpu->GetPC());260ptr->setDontRedraw(true);261u32 breakpointAddress = currentPc+ptr->getInstructionSizeAt(currentPc);262if (info.isBranch)263{264if (info.isConditional == false)265{266if (info.isLinkedBranch) // jal, jalr267{268// it's a function call with a delay slot - skip that too269breakpointAddress += cpu->getInstructionSize(0);270} else { // j, ...271// in case of absolute branches, set the breakpoint at the branch target272breakpointAddress = info.branchTarget;273}274} else { // beq, ...275if (info.conditionMet)276{277breakpointAddress = info.branchTarget;278} else {279breakpointAddress = currentPc+2*cpu->getInstructionSize(0);280ptr->scrollStepping(breakpointAddress);281}282}283} else {284ptr->scrollStepping(breakpointAddress);285}286287CBreakPoints::AddBreakPoint(breakpointAddress,true);288Core_EnableStepping(false);289Sleep(1);290ptr->gotoAddr(breakpointAddress);291UpdateDialog();292}293294void CDisasm::stepOut() {295auto memLock = Memory::Lock();296if (!PSP_IsInited())297return;298299auto threads = GetThreadsInfo();300301u32 entry = cpu->GetPC(), stackTop = 0;302for (size_t i = 0; i < threads.size(); i++)303{304if (threads[i].isCurrent)305{306entry = threads[i].entrypoint;307stackTop = threads[i].initialStack;308break;309}310}311312auto frames = MIPSStackWalk::Walk(cpu->GetPC(),cpu->GetRegValue(0,31),cpu->GetRegValue(0,29),entry,stackTop);313if (frames.size() < 2) return;314u32 breakpointAddress = frames[1].pc;315lastTicks = CoreTiming::GetTicks();316317// If the current PC is on a breakpoint, the user doesn't want to do nothing.318CBreakPoints::SetSkipFirst(currentMIPS->pc);319320CtrlDisAsmView *ptr = DisAsmView();321ptr->setDontRedraw(true);322323CBreakPoints::AddBreakPoint(breakpointAddress,true);324Core_EnableStepping(false);325Sleep(1);326ptr->gotoAddr(breakpointAddress);327UpdateDialog();328}329330void CDisasm::runToLine()331{332if (!PSP_IsInited()) {333return;334}335336CtrlDisAsmView *ptr = DisAsmView();337u32 pos = ptr->getSelection();338339lastTicks = CoreTiming::GetTicks();340ptr->setDontRedraw(true);341CBreakPoints::AddBreakPoint(pos,true);342Core_EnableStepping(false);343}344345BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)346{347//if (!m_hDlg) return FALSE;348switch(message)349{350case WM_INITDIALOG:351// DarkModeInitDialog(m_hDlg);352return TRUE;353354case WM_NOTIFY:355switch (wParam)356{357case IDC_LEFTTABS:358leftTabs->HandleNotify(lParam);359break;360case IDC_BREAKPOINTLIST:361SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, breakpointList->HandleNotify(lParam));362return TRUE;363case IDC_THREADLIST:364SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, threadList->HandleNotify(lParam));365return TRUE;366case IDC_STACKFRAMES:367SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, stackTraceView->HandleNotify(lParam));368return TRUE;369case IDC_MODULELIST:370SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, moduleList->HandleNotify(lParam));371return TRUE;372case IDC_WATCHLIST:373SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, watchList_->HandleNotify(lParam));374return TRUE;375case IDC_DEBUG_BOTTOMTABS:376bottomTabs->HandleNotify(lParam);377break;378}379break;380case WM_COMMAND:381{382CtrlDisAsmView *ptr = DisAsmView();383switch (LOWORD(wParam)) {384case ID_TOGGLE_BREAK:385SendMessage(MainWindow::GetHWND(), WM_COMMAND, ID_TOGGLE_BREAK, 0);386break;387388case ID_DEBUG_DISPLAYMEMVIEW:389bottomTabs->ShowTab(GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW));390break;391392case ID_DEBUG_DISPLAYBREAKPOINTLIST:393bottomTabs->ShowTab(breakpointList->GetHandle());394break;395396case ID_DEBUG_DISPLAYTHREADLIST:397bottomTabs->ShowTab(threadList->GetHandle());398break;399400case ID_DEBUG_DISPLAYSTACKFRAMELIST:401bottomTabs->ShowTab(stackTraceView->GetHandle());402break;403404case ID_DEBUG_DISPLAYREGISTERLIST:405leftTabs->ShowTab(0);406break;407408case ID_DEBUG_DISPLAYFUNCTIONLIST:409leftTabs->ShowTab(1);410break;411412case ID_DEBUG_ADDBREAKPOINT:413{414CtrlDisAsmView *view = DisAsmView();415keepStatusBarText = true;416view->LockPosition();417bool isRunning = Core_IsActive();418if (isRunning)419{420Core_EnableStepping(true, "cpu.breakpoint.add", 0);421Core_WaitInactive(200);422}423424BreakpointWindow bpw(m_hDlg,cpu);425if (bpw.exec()) bpw.addBreakpoint();426427if (isRunning)428Core_EnableStepping(false);429view->UnlockPosition();430keepStatusBarText = false;431}432break;433434case ID_DEBUG_STEPOVER:435if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) stepOver();436break;437438case ID_DEBUG_STEPINTO:439if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) stepInto();440break;441442case ID_DEBUG_RUNTOLINE:443if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) runToLine();444break;445446case ID_DEBUG_STEPOUT:447if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) stepOut();448break;449450case ID_DEBUG_HIDEBOTTOMTABS:451{452RECT rect;453hideBottomTabs = !hideBottomTabs;454GetClientRect(m_hDlg,&rect);455UpdateSize(rect.right-rect.left,rect.bottom-rect.top);456}457break;458459case ID_DEBUG_TOGGLEBOTTOMTABTITLES:460bottomTabs->SetShowTabTitles(!bottomTabs->GetShowTabTitles());461break;462463case IDC_SHOWVFPU:464MainWindow::CreateVFPUWindow();465vfpudlg->Show(true);466break;467468case IDC_FUNCTIONLIST:469switch (HIWORD(wParam))470{471case CBN_DBLCLK:472{473HWND lb = GetDlgItem(m_hDlg,LOWORD(wParam));474int n = ListBox_GetCurSel(lb);475if (n!=-1)476{477unsigned int addr = (unsigned int)ListBox_GetItemData(lb,n);478ptr->gotoAddr(addr);479SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));480}481}482break;483case CBN_SELCHANGE:484{485HWND lb = GetDlgItem(m_hDlg,LOWORD(wParam));486int n = ListBox_GetCurSel(lb);487488wchar_t buffer[512];489ListBox_GetText(lb,n,buffer);490SendMessage(statusBarWnd,SB_SETTEXT,1,(LPARAM) buffer);491}492};493break;494495case IDC_GOTOINT:496switch (HIWORD(wParam))497{498case LBN_SELCHANGE:499{500HWND lb =GetDlgItem(m_hDlg,LOWORD(wParam));501int n = ComboBox_GetCurSel(lb);502unsigned int addr = (unsigned int)ComboBox_GetItemData(lb,n);503if (addr != 0xFFFFFFFF)504{505ptr->gotoAddr(addr);506SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));507}508}509break;510};511break;512513case IDC_STOPGO:514{515if (!PSP_IsInited()) {516break;517}518if (!Core_IsStepping()) // stop519{520ptr->setDontRedraw(false);521Core_EnableStepping(true, "ui.break", 0);522Sleep(1); //let cpu catch up523ptr->gotoPC();524UpdateDialog();525} else { // go526lastTicks = CoreTiming::GetTicks();527528// If the current PC is on a breakpoint, the user doesn't want to do nothing.529CBreakPoints::SetSkipFirst(currentMIPS->pc);530531Core_EnableStepping(false);532}533}534break;535536case IDC_STEP:537stepInto();538break;539540case IDC_STEPOVER:541stepOver();542break;543544case IDC_STEPOUT:545stepOut();546break;547548case IDC_STEPHLE:549{550if (Core_IsActive())551break;552lastTicks = CoreTiming::GetTicks();553554// If the current PC is on a breakpoint, the user doesn't want to do nothing.555CBreakPoints::SetSkipFirst(currentMIPS->pc);556557hleDebugBreak();558Core_EnableStepping(false);559}560break;561562case IDC_MEMCHECK:563SendMessage(m_hDlg,WM_COMMAND,ID_DEBUG_ADDBREAKPOINT,0);564break;565566case IDC_GOTOPC:567{568ptr->gotoPC();569SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));570UpdateDialog();571}572break;573case IDC_GOTOLR:574{575ptr->gotoAddr(cpu->GetLR());576SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));577}578break;579580default:581return FALSE;582}583return TRUE;584}585586case WM_DEB_MAPLOADED:587NotifyMapLoaded();588break;589590case WM_DEB_GOTOWPARAM:591{592CtrlDisAsmView *ptr = DisAsmView();593ptr->gotoAddr(wParam);594SetFocus(GetDlgItem(m_hDlg,IDC_DISASMVIEW));595break;596}597case WM_DEB_GOTOADDRESSEDIT:598{599if (!PSP_IsInited()) {600break;601}602wchar_t szBuffer[256];603CtrlDisAsmView *ptr = DisAsmView();604GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),szBuffer,256);605606u32 addr;607if (parseExpression(ConvertWStringToUTF8(szBuffer).c_str(),cpu,addr) == false)608{609displayExpressionError(GetDlgItem(m_hDlg,IDC_ADDRESS));610} else {611ptr->gotoAddr(addr);612SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));613}614UpdateDialog();615}616break;617618case WM_DEB_SETDEBUGLPARAM:619SetDebugMode(lParam != 0, true);620return TRUE;621622case WM_DEB_UPDATE:623Update();624return TRUE;625626case WM_DEB_TABPRESSED:627bottomTabs->NextTab(true);628SetFocus(bottomTabs->CurrentTabHandle());629break;630631case WM_DEB_SETSTATUSBARTEXT:632if (!keepStatusBarText)633{634if (wParam == 0)635{636// erase the second part if the first is set637SendMessage(statusBarWnd,SB_SETTEXT,0,(LPARAM)ConvertUTF8ToWString((const char *)lParam).c_str());638SendMessage(statusBarWnd,SB_SETTEXT,1,(LPARAM)L"");639} else if (wParam == 1)640{641SendMessage(statusBarWnd,SB_SETTEXT,1,(LPARAM)ConvertUTF8ToWString((const char *)lParam).c_str());642}643}644break;645case WM_DEB_GOTOHEXEDIT:646{647CtrlMemView *memory = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW));648memory->gotoAddr(wParam);649650// display the memory viewer too651bottomTabs->ShowTab(GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW));652}653break;654case WM_SIZE:655{656UpdateSize(LOWORD(lParam), HIWORD(lParam));657SendMessage(statusBarWnd,WM_SIZE,0,10);658SavePosition();659return TRUE;660}661662case WM_MOVE:663SavePosition();664break;665case WM_GETMINMAXINFO:666{667MINMAXINFO *m = (MINMAXINFO *)lParam;668// Reduce the minimum size slightly, so they can size it however they like.669m->ptMinTrackSize.x = minWidth;670//m->ptMaxTrackSize.x = m->ptMinTrackSize.x;671m->ptMinTrackSize.y = minHeight;672}673return TRUE;674case WM_CLOSE:675Show(false);676return TRUE;677case WM_ACTIVATE:678if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) {679g_activeWindow = WINDOW_CPUDEBUGGER;680} else {681g_activeWindow = WINDOW_OTHER;682}683break;684685case WM_TIMER:686if (wParam == IDT_UPDATE) {687ProcessUpdateDialog();688updateDialogScheduled_ = false;689KillTimer(GetDlgHandle(), wParam);690}691break;692}693return 0; // DarkModeDlgProc(m_hDlg, message, wParam, lParam);694}695696void CDisasm::updateThreadLabel(bool clear)697{698char label[512];699if (clear) {700snprintf(label, sizeof(label), "Thread: -");701} else {702snprintf(label, sizeof(label), "Thread: %s", threadList->getCurrentThreadName());703}704705SetDlgItemText(m_hDlg, IDC_THREADNAME, ConvertUTF8ToWString(label).c_str());706}707708void CDisasm::UpdateSize(WORD width, WORD height)709{710struct Position711{712int x,y;713int w,h;714};715716RECT windowRect;717Position positions[3];718719HWND disasm = GetDlgItem(m_hDlg, IDC_DISASMVIEW);720HWND leftTabs = GetDlgItem(m_hDlg,IDC_LEFTTABS);721HWND bottomTabs = GetDlgItem(m_hDlg, IDC_DEBUG_BOTTOMTABS);722723// ignore the status bar724int topHeightOffset = 0;725if (g_Config.bDisplayStatusBar)726{727GetWindowRect(statusBarWnd,&windowRect);728topHeightOffset = (windowRect.bottom-windowRect.top);729}730731CtrlDisAsmView *ptr = DisAsmView();732int disassemblyRowHeight = ptr->getRowHeight();733734// disassembly735GetWindowRect(disasm,&windowRect);736MapWindowPoints(HWND_DESKTOP,m_hDlg,(LPPOINT)&windowRect,2);737positions[0].x = windowRect.left;738positions[0].y = windowRect.top;739740// compute border height of the disassembly741int totalHeight = windowRect.bottom-windowRect.top;742GetClientRect(disasm,&windowRect);743int clientHeight = windowRect.bottom-windowRect.top;744int borderHeight = totalHeight-clientHeight;745746// left tabs747GetWindowRect(leftTabs,&windowRect);748MapWindowPoints(HWND_DESKTOP,m_hDlg,(LPPOINT)&windowRect,2);749positions[1].x = windowRect.left;750positions[1].y = windowRect.top;751positions[1].w = positions[0].x-2*windowRect.left;752int borderMargin = positions[1].x;753754float weight = hideBottomTabs ? 1.f : 390.f/500.f;755756// don't use the part above the disassembly for the computations757int bottomHeightOffset = positions[0].y;758positions[0].w = width-borderMargin-positions[0].x;759positions[0].h = (height-bottomHeightOffset-topHeightOffset) * weight;760positions[0].h = ((positions[0].h-borderHeight)/disassemblyRowHeight)*disassemblyRowHeight+borderHeight;761positions[1].h = positions[0].h-(positions[1].y-positions[0].y);762763// bottom tabs764positions[2].x = borderMargin;765positions[2].y = positions[0].y+positions[0].h+borderMargin;766positions[2].w = width-2*borderMargin;767positions[2].h = hideBottomTabs ? 0 : height-bottomHeightOffset-positions[2].y;768769// now actually move all the windows770MoveWindow(disasm,positions[0].x,positions[0].y,positions[0].w,positions[0].h,TRUE);771MoveWindow(leftTabs,positions[1].x,positions[1].y,positions[1].w,positions[1].h,TRUE);772MoveWindow(bottomTabs,positions[2].x,positions[2].y,positions[2].w,positions[2].h,TRUE);773ShowWindow(bottomTabs,hideBottomTabs ? SW_HIDE : SW_NORMAL);774}775776void CDisasm::SavePosition()777{778RECT rc;779if (GetWindowRect(m_hDlg, &rc))780{781g_Config.iDisasmWindowX = rc.left;782g_Config.iDisasmWindowY = rc.top;783g_Config.iDisasmWindowW = rc.right - rc.left;784g_Config.iDisasmWindowH = rc.bottom - rc.top;785}786}787788void CDisasm::SetDebugMode(bool _bDebug, bool switchPC)789{790HWND hDlg = m_hDlg;791bool ingame = (GetUIState() == UISTATE_INGAME || GetUIState() == UISTATE_EXCEPTION) && PSP_IsInited();792793// If we're stepping, update debugging windows.794// This is called potentially asynchronously, so state might've changed.795if (Core_IsStepping() && ingame) {796breakpointList->reloadBreakpoints();797threadList->reloadThreads();798stackTraceView->loadStackTrace();799moduleList->loadModules();800watchList_->RefreshValues();801802EnableWindow(GetDlgItem(hDlg, IDC_STOPGO), TRUE);803EnableWindow(GetDlgItem(hDlg, IDC_STEP), TRUE);804EnableWindow(GetDlgItem(hDlg, IDC_STEPOVER), TRUE);805EnableWindow(GetDlgItem(hDlg, IDC_STEPHLE), TRUE);806EnableWindow(GetDlgItem(hDlg, IDC_STEPOUT), TRUE);807EnableWindow(GetDlgItem(hDlg, IDC_GOTOPC), TRUE);808EnableWindow(GetDlgItem(hDlg, IDC_GOTOLR), TRUE);809CtrlDisAsmView *ptr = DisAsmView();810ptr->setDontRedraw(false);811if (switchPC)812ptr->gotoPC();813814ptr->scanFunctions();815}816else817{818if (ingame)819EnableWindow(GetDlgItem(hDlg, IDC_STOPGO), TRUE);820else821EnableWindow(GetDlgItem(hDlg, IDC_STOPGO), FALSE);822EnableWindow(GetDlgItem(hDlg, IDC_STEP), FALSE);823EnableWindow(GetDlgItem(hDlg, IDC_STEPOVER), FALSE);824EnableWindow(GetDlgItem(hDlg, IDC_STEPHLE), FALSE);825EnableWindow(GetDlgItem(hDlg, IDC_STEPOUT), FALSE);826EnableWindow(GetDlgItem(hDlg, IDC_GOTOPC), FALSE);827EnableWindow(GetDlgItem(hDlg, IDC_GOTOLR), FALSE);828CtrlRegisterList *reglist = CtrlRegisterList::getFrom(GetDlgItem(m_hDlg,IDC_REGLIST));829reglist->redraw();830}831832UpdateDialog();833}834835void CDisasm::Show(bool bShow, bool includeToTop) {836if (deferredSymbolFill_ && bShow) {837if (g_symbolMap) {838g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), ST_FUNCTION);839deferredSymbolFill_ = false;840}841}842Dialog::Show(bShow, includeToTop);843}844845void CDisasm::NotifyMapLoaded() {846if (m_bShowState != SW_HIDE && g_symbolMap) {847g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), ST_FUNCTION);848} else {849deferredSymbolFill_ = true;850}851CtrlDisAsmView *ptr = DisAsmView();852ptr->clearFunctions();853ptr->redraw();854}855856void CDisasm::Goto(u32 addr)857{858CtrlDisAsmView *ptr = DisAsmView();859ptr->gotoAddr(addr);860SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));861ptr->redraw();862}863864void CDisasm::UpdateDialog() {865if (!updateDialogScheduled_) {866SetTimer(GetDlgHandle(), IDT_UPDATE, UPDATE_DELAY, nullptr);867updateDialogScheduled_ = true;868}869870// Since these update on a delay, it's okay to do them immediately.871CtrlDisAsmView *ptr = DisAsmView();872ptr->redraw();873CtrlRegisterList *rl = CtrlRegisterList::getFrom(GetDlgItem(m_hDlg, IDC_REGLIST));874rl->redraw();875876// Repaint windows at the bottom. only the memory view needs to be forced to redraw.877// All others are updated manually878CtrlMemView *memview = CtrlMemView::getFrom(GetDlgItem(m_hDlg, IDC_DEBUGMEMVIEW));879memview->redraw();880881// Update memory window too.882if (memoryWindow)883memoryWindow->Update();884if (vfpudlg)885vfpudlg->Update();886}887888void CDisasm::ProcessUpdateDialog() {889/*890HWND gotoInt = GetDlgItem(m_hDlg, IDC_GOTOINT);891ComboBox_ResetContent(gotoInt);892for (int i=0; i<numRegions; i++)893{894// TODO: wchar_t895int n = ComboBox_AddString(gotoInt,regions[i].name);896ComboBox_SetItemData(gotoInt,n,regions[i].start);897}898ComboBox_InsertString(gotoInt,0,"[Goto Rgn]");899ComboBox_SetItemData(gotoInt,0,0xFFFFFFFF);900ComboBox_SetCurSel(gotoInt,0);901*/902903// Update Debug Counter904if (PSP_IsInited()) {905wchar_t tempTicks[24]{};906_snwprintf(tempTicks, 23, L"%lld", CoreTiming::GetTicks() - lastTicks);907SetDlgItemText(m_hDlg, IDC_DEBUG_COUNT, tempTicks);908}909910bool ingame = (GetUIState() == UISTATE_INGAME || GetUIState() == UISTATE_EXCEPTION) && PSP_IsInited();911if (Core_IsStepping() || !ingame) {912SetDlgItemText(m_hDlg, IDC_STOPGO, L"Go");913} else {914SetDlgItemText(m_hDlg, IDC_STOPGO, L"Break");915}916917updateThreadLabel(!ingame || !Core_IsStepping());918}919920CtrlDisAsmView *CDisasm::DisAsmView() {921return CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg, IDC_DISASMVIEW));922}923924925