CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/Debugger/Debugger_Disasm.cpp
Views: 1401
1
#include "Core/Config.h"
2
#include "Core/MemMap.h"
3
#include "Windows/resource.h"
4
#include "Windows/InputBox.h"
5
6
#include "Core/Debugger/Breakpoints.h"
7
#include "Core/Debugger/SymbolMap.h"
8
#include "Windows/Debugger/BreakpointWindow.h"
9
#include "Windows/Debugger/CtrlDisAsmView.h"
10
#include "Windows/Debugger/Debugger_MemoryDlg.h"
11
#include "Windows/Debugger/Debugger_Disasm.h"
12
#include "Windows/Debugger/Debugger_VFPUDlg.h"
13
#include "Windows/Debugger/DebuggerShared.h"
14
// #include "Windows/W32Util/DarkMode.h"
15
16
#include "Windows/main.h"
17
#include "Windows/Debugger/CtrlRegisterList.h"
18
#include "Windows/Debugger/CtrlMemView.h"
19
#include "Windows/Debugger/Debugger_Lists.h"
20
#include "Windows/MainWindow.h"
21
22
#include "Core/Core.h"
23
#include "Core/HLE/HLE.h"
24
#include "Core/CoreTiming.h"
25
#include "Core/MIPS/MIPSAnalyst.h"
26
27
#include "Common/Data/Encoding/Utf8.h"
28
29
#include "Common/CommonWindows.h"
30
#include "Common/StringUtils.h"
31
32
#include <windowsx.h>
33
#include <commctrl.h>
34
35
static FAR WNDPROC DefGotoEditProc;
36
37
LRESULT CALLBACK GotoEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
38
{
39
switch(message)
40
{
41
case WM_KEYDOWN:
42
if( wParam == VK_RETURN )
43
{
44
SendMessage(GetParent(hDlg),WM_DEB_GOTOADDRESSEDIT,0,0);
45
return 0;
46
}
47
break;
48
case WM_KEYUP:
49
if( wParam == VK_RETURN ) return 0;
50
break;
51
case WM_CHAR:
52
if( wParam == VK_RETURN ) return 0;
53
break;
54
case WM_GETDLGCODE:
55
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
56
{
57
if (wParam == VK_RETURN) return DLGC_WANTMESSAGE;
58
}
59
break;
60
};
61
62
return (LRESULT)CallWindowProc((WNDPROC)DefGotoEditProc,hDlg,message,wParam,lParam);
63
}
64
65
static FAR WNDPROC DefFuncListProc;
66
67
LRESULT CALLBACK FuncListProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
68
{
69
switch(message)
70
{
71
case WM_KEYDOWN:
72
if( wParam == VK_RETURN )
73
{
74
SendMessage(GetParent(hDlg),WM_COMMAND,MAKEWPARAM(IDC_FUNCTIONLIST,CBN_DBLCLK),0);
75
SetFocus(hDlg); // it's more natural to keep the focus when using keyboard controls
76
return 0;
77
}
78
break;
79
case WM_GETDLGCODE:
80
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
81
{
82
if (wParam == VK_RETURN) return DLGC_WANTMESSAGE;
83
}
84
break;
85
};
86
87
return (LRESULT)CallWindowProc((WNDPROC)DefFuncListProc,hDlg,message,wParam,lParam);
88
}
89
90
static constexpr UINT_PTR IDT_UPDATE = 0xC0DE0042;
91
static constexpr UINT UPDATE_DELAY = 1000 / 60;
92
93
CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Dialog((LPCSTR)IDD_DISASM, _hInstance, _hParent) {
94
cpu = _cpu;
95
lastTicks = PSP_IsInited() ? CoreTiming::GetTicks() : 0;
96
97
SetWindowText(m_hDlg, ConvertUTF8ToWString(_cpu->GetName()).c_str());
98
99
RECT windowRect;
100
GetWindowRect(m_hDlg,&windowRect);
101
int defaultWidth = windowRect.right-windowRect.left;
102
int defaultHeight = windowRect.bottom-windowRect.top;
103
minWidth = defaultWidth - 100;
104
minHeight = defaultHeight - 200;
105
106
int x = g_Config.iDisasmWindowX == -1 ? windowRect.left : g_Config.iDisasmWindowX;
107
int y = g_Config.iDisasmWindowY == -1 ? windowRect.top : g_Config.iDisasmWindowY;
108
int w = g_Config.iDisasmWindowW == -1 ? defaultWidth : g_Config.iDisasmWindowW;
109
int h = g_Config.iDisasmWindowH == -1 ? defaultHeight : g_Config.iDisasmWindowH;
110
111
// init status bar
112
statusBarWnd = CreateWindowEx(0, STATUSCLASSNAME, L"", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, m_hDlg, (HMENU)IDC_DISASMSTATUSBAR, _hInstance, NULL);
113
if (g_Config.bDisplayStatusBar == false) {
114
ShowWindow(statusBarWnd,SW_HIDE);
115
}
116
117
// set it to use two parts
118
RECT statusBarRect;
119
GetClientRect(statusBarWnd,&statusBarRect);
120
121
int parts[2];
122
parts[1] = statusBarRect.right-statusBarRect.left;
123
parts[0] = parts[1]*2./3.;
124
125
SendMessage(statusBarWnd, SB_SETPARTS, (WPARAM) 2, (LPARAM) parts);
126
127
// init other controls
128
CtrlDisAsmView *ptr = DisAsmView();
129
ptr->setDebugger(cpu);
130
ptr->gotoAddr(0x00000000);
131
132
CtrlRegisterList *rl = CtrlRegisterList::getFrom(GetDlgItem(m_hDlg,IDC_REGLIST));
133
rl->setCPU(cpu);
134
135
leftTabs = new TabControl(GetDlgItem(m_hDlg,IDC_LEFTTABS));
136
leftTabs->SetIgnoreBottomMargin(true);
137
leftTabs->AddTab(GetDlgItem(m_hDlg,IDC_REGLIST),L"Regs");
138
leftTabs->AddTab(GetDlgItem(m_hDlg,IDC_FUNCTIONLIST),L"Funcs");
139
leftTabs->ShowTab(0);
140
141
// subclass the goto edit box
142
HWND editWnd = GetDlgItem(m_hDlg,IDC_ADDRESS);
143
DefGotoEditProc = (WNDPROC)GetWindowLongPtr(editWnd,GWLP_WNDPROC);
144
SetWindowLongPtr(editWnd,GWLP_WNDPROC,(LONG_PTR)GotoEditProc);
145
146
// subclass the function list
147
HWND funcListWnd = GetDlgItem(m_hDlg,IDC_FUNCTIONLIST);
148
DefFuncListProc = (WNDPROC)GetWindowLongPtr(funcListWnd,GWLP_WNDPROC);
149
SetWindowLongPtr(funcListWnd,GWLP_WNDPROC,(LONG_PTR)FuncListProc);
150
151
// init bottom tabs
152
bottomTabs = new TabControl(GetDlgItem(m_hDlg,IDC_DEBUG_BOTTOMTABS));
153
154
HWND memHandle = GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW);
155
CtrlMemView *mem = CtrlMemView::getFrom(memHandle);
156
mem->setDebugger(_cpu);
157
bottomTabs->AddTab(memHandle,L"Memory");
158
159
breakpointList = new CtrlBreakpointList(GetDlgItem(m_hDlg,IDC_BREAKPOINTLIST),cpu,ptr);
160
breakpointList->reloadBreakpoints();
161
bottomTabs->AddTab(breakpointList->GetHandle(),L"Breakpoints");
162
163
threadList = new CtrlThreadList(GetDlgItem(m_hDlg,IDC_THREADLIST));
164
threadList->reloadThreads();
165
bottomTabs->AddTab(threadList->GetHandle(),L"Threads");
166
167
stackTraceView = new CtrlStackTraceView(GetDlgItem(m_hDlg,IDC_STACKFRAMES),cpu,ptr);
168
stackTraceView->loadStackTrace();
169
bottomTabs->AddTab(stackTraceView->GetHandle(),L"Stack frames");
170
171
moduleList = new CtrlModuleList(GetDlgItem(m_hDlg,IDC_MODULELIST),cpu);
172
moduleList->loadModules();
173
bottomTabs->AddTab(moduleList->GetHandle(),L"Modules");
174
175
watchList_ = new CtrlWatchList(GetDlgItem(m_hDlg, IDC_WATCHLIST), cpu);
176
bottomTabs->AddTab(watchList_->GetHandle(), L"Watch");
177
178
bottomTabs->SetShowTabTitles(g_Config.bShowBottomTabTitles);
179
bottomTabs->ShowTab(memHandle);
180
181
// Actually resize the window to the proper size (after the above setup.)
182
// do it twice so that the window definitely receives a WM_SIZE message with
183
// the correct size (the default from the .rc tends to be off)
184
MoveWindow(m_hDlg,x,y,1,1,FALSE);
185
MoveWindow(m_hDlg,x,y,w,h,TRUE);
186
SetDebugMode(true, true);
187
}
188
189
CDisasm::~CDisasm()
190
{
191
DestroyWindow(statusBarWnd);
192
193
delete leftTabs;
194
delete bottomTabs;
195
delete breakpointList;
196
delete threadList;
197
delete stackTraceView;
198
delete moduleList;
199
}
200
201
void CDisasm::stepInto()
202
{
203
if (!PSP_IsInited() || !Core_IsStepping()) {
204
return;
205
}
206
207
CtrlDisAsmView *ptr = DisAsmView();
208
lastTicks = CoreTiming::GetTicks();
209
u32 currentPc = cpu->GetPC();
210
211
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
212
CBreakPoints::SetSkipFirst(currentMIPS->pc);
213
u32 newAddress = currentPc+ptr->getInstructionSizeAt(currentPc);
214
215
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu,currentPc);
216
if (info.isBranch)
217
{
218
ptr->scrollStepping(newAddress);
219
} else {
220
bool scroll = true;
221
if (currentMIPS->inDelaySlot)
222
{
223
MIPSAnalyst::MipsOpcodeInfo prevInfo = MIPSAnalyst::GetOpcodeInfo(cpu,currentPc-cpu->getInstructionSize(0));
224
if (!prevInfo.isConditional || prevInfo.conditionMet)
225
scroll = false;
226
}
227
228
if (scroll)
229
{
230
ptr->scrollStepping(newAddress);
231
}
232
}
233
234
for (u32 i = 0; i < (newAddress-currentPc)/4; i++)
235
{
236
Core_DoSingleStep();
237
Sleep(1);
238
}
239
240
ptr->gotoPC();
241
UpdateDialog();
242
243
threadList->reloadThreads();
244
stackTraceView->loadStackTrace();
245
}
246
247
void CDisasm::stepOver()
248
{
249
if (!PSP_IsInited() || Core_IsActive()) {
250
return;
251
}
252
253
CtrlDisAsmView *ptr = DisAsmView();
254
lastTicks = CoreTiming::GetTicks();
255
256
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
257
CBreakPoints::SetSkipFirst(currentMIPS->pc);
258
u32 currentPc = cpu->GetPC();
259
260
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(cpu,cpu->GetPC());
261
ptr->setDontRedraw(true);
262
u32 breakpointAddress = currentPc+ptr->getInstructionSizeAt(currentPc);
263
if (info.isBranch)
264
{
265
if (info.isConditional == false)
266
{
267
if (info.isLinkedBranch) // jal, jalr
268
{
269
// it's a function call with a delay slot - skip that too
270
breakpointAddress += cpu->getInstructionSize(0);
271
} else { // j, ...
272
// in case of absolute branches, set the breakpoint at the branch target
273
breakpointAddress = info.branchTarget;
274
}
275
} else { // beq, ...
276
if (info.conditionMet)
277
{
278
breakpointAddress = info.branchTarget;
279
} else {
280
breakpointAddress = currentPc+2*cpu->getInstructionSize(0);
281
ptr->scrollStepping(breakpointAddress);
282
}
283
}
284
} else {
285
ptr->scrollStepping(breakpointAddress);
286
}
287
288
CBreakPoints::AddBreakPoint(breakpointAddress,true);
289
Core_EnableStepping(false);
290
Sleep(1);
291
ptr->gotoAddr(breakpointAddress);
292
UpdateDialog();
293
}
294
295
void CDisasm::stepOut() {
296
auto memLock = Memory::Lock();
297
if (!PSP_IsInited())
298
return;
299
300
auto threads = GetThreadsInfo();
301
302
u32 entry = cpu->GetPC(), stackTop = 0;
303
for (size_t i = 0; i < threads.size(); i++)
304
{
305
if (threads[i].isCurrent)
306
{
307
entry = threads[i].entrypoint;
308
stackTop = threads[i].initialStack;
309
break;
310
}
311
}
312
313
auto frames = MIPSStackWalk::Walk(cpu->GetPC(),cpu->GetRegValue(0,31),cpu->GetRegValue(0,29),entry,stackTop);
314
if (frames.size() < 2) return;
315
u32 breakpointAddress = frames[1].pc;
316
lastTicks = CoreTiming::GetTicks();
317
318
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
319
CBreakPoints::SetSkipFirst(currentMIPS->pc);
320
321
CtrlDisAsmView *ptr = DisAsmView();
322
ptr->setDontRedraw(true);
323
324
CBreakPoints::AddBreakPoint(breakpointAddress,true);
325
Core_EnableStepping(false);
326
Sleep(1);
327
ptr->gotoAddr(breakpointAddress);
328
UpdateDialog();
329
}
330
331
void CDisasm::runToLine()
332
{
333
if (!PSP_IsInited()) {
334
return;
335
}
336
337
CtrlDisAsmView *ptr = DisAsmView();
338
u32 pos = ptr->getSelection();
339
340
lastTicks = CoreTiming::GetTicks();
341
ptr->setDontRedraw(true);
342
CBreakPoints::AddBreakPoint(pos,true);
343
Core_EnableStepping(false);
344
}
345
346
BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
347
{
348
//if (!m_hDlg) return FALSE;
349
switch(message)
350
{
351
case WM_INITDIALOG:
352
// DarkModeInitDialog(m_hDlg);
353
return TRUE;
354
355
case WM_NOTIFY:
356
switch (wParam)
357
{
358
case IDC_LEFTTABS:
359
leftTabs->HandleNotify(lParam);
360
break;
361
case IDC_BREAKPOINTLIST:
362
SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, breakpointList->HandleNotify(lParam));
363
return TRUE;
364
case IDC_THREADLIST:
365
SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, threadList->HandleNotify(lParam));
366
return TRUE;
367
case IDC_STACKFRAMES:
368
SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, stackTraceView->HandleNotify(lParam));
369
return TRUE;
370
case IDC_MODULELIST:
371
SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, moduleList->HandleNotify(lParam));
372
return TRUE;
373
case IDC_WATCHLIST:
374
SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, watchList_->HandleNotify(lParam));
375
return TRUE;
376
case IDC_DEBUG_BOTTOMTABS:
377
bottomTabs->HandleNotify(lParam);
378
break;
379
}
380
break;
381
case WM_COMMAND:
382
{
383
CtrlDisAsmView *ptr = DisAsmView();
384
switch (LOWORD(wParam)) {
385
case ID_TOGGLE_BREAK:
386
SendMessage(MainWindow::GetHWND(), WM_COMMAND, ID_TOGGLE_BREAK, 0);
387
break;
388
389
case ID_DEBUG_DISPLAYMEMVIEW:
390
bottomTabs->ShowTab(GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW));
391
break;
392
393
case ID_DEBUG_DISPLAYBREAKPOINTLIST:
394
bottomTabs->ShowTab(breakpointList->GetHandle());
395
break;
396
397
case ID_DEBUG_DISPLAYTHREADLIST:
398
bottomTabs->ShowTab(threadList->GetHandle());
399
break;
400
401
case ID_DEBUG_DISPLAYSTACKFRAMELIST:
402
bottomTabs->ShowTab(stackTraceView->GetHandle());
403
break;
404
405
case ID_DEBUG_DISPLAYREGISTERLIST:
406
leftTabs->ShowTab(0);
407
break;
408
409
case ID_DEBUG_DISPLAYFUNCTIONLIST:
410
leftTabs->ShowTab(1);
411
break;
412
413
case ID_DEBUG_ADDBREAKPOINT:
414
{
415
CtrlDisAsmView *view = DisAsmView();
416
keepStatusBarText = true;
417
view->LockPosition();
418
bool isRunning = Core_IsActive();
419
if (isRunning)
420
{
421
Core_EnableStepping(true, "cpu.breakpoint.add", 0);
422
Core_WaitInactive(200);
423
}
424
425
BreakpointWindow bpw(m_hDlg,cpu);
426
if (bpw.exec()) bpw.addBreakpoint();
427
428
if (isRunning)
429
Core_EnableStepping(false);
430
view->UnlockPosition();
431
keepStatusBarText = false;
432
}
433
break;
434
435
case ID_DEBUG_STEPOVER:
436
if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) stepOver();
437
break;
438
439
case ID_DEBUG_STEPINTO:
440
if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) stepInto();
441
break;
442
443
case ID_DEBUG_RUNTOLINE:
444
if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) runToLine();
445
break;
446
447
case ID_DEBUG_STEPOUT:
448
if (GetFocus() == GetDlgItem(m_hDlg,IDC_DISASMVIEW)) stepOut();
449
break;
450
451
case ID_DEBUG_HIDEBOTTOMTABS:
452
{
453
RECT rect;
454
hideBottomTabs = !hideBottomTabs;
455
GetClientRect(m_hDlg,&rect);
456
UpdateSize(rect.right-rect.left,rect.bottom-rect.top);
457
}
458
break;
459
460
case ID_DEBUG_TOGGLEBOTTOMTABTITLES:
461
bottomTabs->SetShowTabTitles(!bottomTabs->GetShowTabTitles());
462
break;
463
464
case IDC_SHOWVFPU:
465
MainWindow::CreateVFPUWindow();
466
vfpudlg->Show(true);
467
break;
468
469
case IDC_FUNCTIONLIST:
470
switch (HIWORD(wParam))
471
{
472
case CBN_DBLCLK:
473
{
474
HWND lb = GetDlgItem(m_hDlg,LOWORD(wParam));
475
int n = ListBox_GetCurSel(lb);
476
if (n!=-1)
477
{
478
unsigned int addr = (unsigned int)ListBox_GetItemData(lb,n);
479
ptr->gotoAddr(addr);
480
SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
481
}
482
}
483
break;
484
case CBN_SELCHANGE:
485
{
486
HWND lb = GetDlgItem(m_hDlg,LOWORD(wParam));
487
int n = ListBox_GetCurSel(lb);
488
489
wchar_t buffer[512];
490
ListBox_GetText(lb,n,buffer);
491
SendMessage(statusBarWnd,SB_SETTEXT,1,(LPARAM) buffer);
492
}
493
};
494
break;
495
496
case IDC_GOTOINT:
497
switch (HIWORD(wParam))
498
{
499
case LBN_SELCHANGE:
500
{
501
HWND lb =GetDlgItem(m_hDlg,LOWORD(wParam));
502
int n = ComboBox_GetCurSel(lb);
503
unsigned int addr = (unsigned int)ComboBox_GetItemData(lb,n);
504
if (addr != 0xFFFFFFFF)
505
{
506
ptr->gotoAddr(addr);
507
SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
508
}
509
}
510
break;
511
};
512
break;
513
514
case IDC_STOPGO:
515
{
516
if (!PSP_IsInited()) {
517
break;
518
}
519
if (!Core_IsStepping()) // stop
520
{
521
ptr->setDontRedraw(false);
522
Core_EnableStepping(true, "ui.break", 0);
523
Sleep(1); //let cpu catch up
524
ptr->gotoPC();
525
UpdateDialog();
526
} else { // go
527
lastTicks = CoreTiming::GetTicks();
528
529
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
530
CBreakPoints::SetSkipFirst(currentMIPS->pc);
531
532
Core_EnableStepping(false);
533
}
534
}
535
break;
536
537
case IDC_STEP:
538
stepInto();
539
break;
540
541
case IDC_STEPOVER:
542
stepOver();
543
break;
544
545
case IDC_STEPOUT:
546
stepOut();
547
break;
548
549
case IDC_STEPHLE:
550
{
551
if (Core_IsActive())
552
break;
553
lastTicks = CoreTiming::GetTicks();
554
555
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
556
CBreakPoints::SetSkipFirst(currentMIPS->pc);
557
558
hleDebugBreak();
559
Core_EnableStepping(false);
560
}
561
break;
562
563
case IDC_MEMCHECK:
564
SendMessage(m_hDlg,WM_COMMAND,ID_DEBUG_ADDBREAKPOINT,0);
565
break;
566
567
case IDC_GOTOPC:
568
{
569
ptr->gotoPC();
570
SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
571
UpdateDialog();
572
}
573
break;
574
case IDC_GOTOLR:
575
{
576
ptr->gotoAddr(cpu->GetLR());
577
SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
578
}
579
break;
580
581
default:
582
return FALSE;
583
}
584
return TRUE;
585
}
586
587
case WM_DEB_MAPLOADED:
588
NotifyMapLoaded();
589
break;
590
591
case WM_DEB_GOTOWPARAM:
592
{
593
CtrlDisAsmView *ptr = DisAsmView();
594
ptr->gotoAddr(wParam);
595
SetFocus(GetDlgItem(m_hDlg,IDC_DISASMVIEW));
596
break;
597
}
598
case WM_DEB_GOTOADDRESSEDIT:
599
{
600
if (!PSP_IsInited()) {
601
break;
602
}
603
wchar_t szBuffer[256];
604
CtrlDisAsmView *ptr = DisAsmView();
605
GetWindowText(GetDlgItem(m_hDlg,IDC_ADDRESS),szBuffer,256);
606
607
u32 addr;
608
if (parseExpression(ConvertWStringToUTF8(szBuffer).c_str(),cpu,addr) == false)
609
{
610
displayExpressionError(GetDlgItem(m_hDlg,IDC_ADDRESS));
611
} else {
612
ptr->gotoAddr(addr);
613
SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
614
}
615
UpdateDialog();
616
}
617
break;
618
619
case WM_DEB_SETDEBUGLPARAM:
620
SetDebugMode(lParam != 0, true);
621
return TRUE;
622
623
case WM_DEB_UPDATE:
624
Update();
625
return TRUE;
626
627
case WM_DEB_TABPRESSED:
628
bottomTabs->NextTab(true);
629
SetFocus(bottomTabs->CurrentTabHandle());
630
break;
631
632
case WM_DEB_SETSTATUSBARTEXT:
633
if (!keepStatusBarText)
634
{
635
if (wParam == 0)
636
{
637
// erase the second part if the first is set
638
SendMessage(statusBarWnd,SB_SETTEXT,0,(LPARAM)ConvertUTF8ToWString((const char *)lParam).c_str());
639
SendMessage(statusBarWnd,SB_SETTEXT,1,(LPARAM)L"");
640
} else if (wParam == 1)
641
{
642
SendMessage(statusBarWnd,SB_SETTEXT,1,(LPARAM)ConvertUTF8ToWString((const char *)lParam).c_str());
643
}
644
}
645
break;
646
case WM_DEB_GOTOHEXEDIT:
647
{
648
CtrlMemView *memory = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW));
649
memory->gotoAddr(wParam);
650
651
// display the memory viewer too
652
bottomTabs->ShowTab(GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW));
653
}
654
break;
655
case WM_SIZE:
656
{
657
UpdateSize(LOWORD(lParam), HIWORD(lParam));
658
SendMessage(statusBarWnd,WM_SIZE,0,10);
659
SavePosition();
660
return TRUE;
661
}
662
663
case WM_MOVE:
664
SavePosition();
665
break;
666
case WM_GETMINMAXINFO:
667
{
668
MINMAXINFO *m = (MINMAXINFO *)lParam;
669
// Reduce the minimum size slightly, so they can size it however they like.
670
m->ptMinTrackSize.x = minWidth;
671
//m->ptMaxTrackSize.x = m->ptMinTrackSize.x;
672
m->ptMinTrackSize.y = minHeight;
673
}
674
return TRUE;
675
case WM_CLOSE:
676
Show(false);
677
return TRUE;
678
case WM_ACTIVATE:
679
if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) {
680
g_activeWindow = WINDOW_CPUDEBUGGER;
681
} else {
682
g_activeWindow = WINDOW_OTHER;
683
}
684
break;
685
686
case WM_TIMER:
687
if (wParam == IDT_UPDATE) {
688
ProcessUpdateDialog();
689
updateDialogScheduled_ = false;
690
KillTimer(GetDlgHandle(), wParam);
691
}
692
break;
693
}
694
return 0; // DarkModeDlgProc(m_hDlg, message, wParam, lParam);
695
}
696
697
void CDisasm::updateThreadLabel(bool clear)
698
{
699
char label[512];
700
if (clear) {
701
snprintf(label, sizeof(label), "Thread: -");
702
} else {
703
snprintf(label, sizeof(label), "Thread: %s", threadList->getCurrentThreadName());
704
}
705
706
SetDlgItemText(m_hDlg, IDC_THREADNAME, ConvertUTF8ToWString(label).c_str());
707
}
708
709
void CDisasm::UpdateSize(WORD width, WORD height)
710
{
711
struct Position
712
{
713
int x,y;
714
int w,h;
715
};
716
717
RECT windowRect;
718
Position positions[3];
719
720
HWND disasm = GetDlgItem(m_hDlg, IDC_DISASMVIEW);
721
HWND leftTabs = GetDlgItem(m_hDlg,IDC_LEFTTABS);
722
HWND bottomTabs = GetDlgItem(m_hDlg, IDC_DEBUG_BOTTOMTABS);
723
724
// ignore the status bar
725
int topHeightOffset = 0;
726
if (g_Config.bDisplayStatusBar)
727
{
728
GetWindowRect(statusBarWnd,&windowRect);
729
topHeightOffset = (windowRect.bottom-windowRect.top);
730
}
731
732
CtrlDisAsmView *ptr = DisAsmView();
733
int disassemblyRowHeight = ptr->getRowHeight();
734
735
// disassembly
736
GetWindowRect(disasm,&windowRect);
737
MapWindowPoints(HWND_DESKTOP,m_hDlg,(LPPOINT)&windowRect,2);
738
positions[0].x = windowRect.left;
739
positions[0].y = windowRect.top;
740
741
// compute border height of the disassembly
742
int totalHeight = windowRect.bottom-windowRect.top;
743
GetClientRect(disasm,&windowRect);
744
int clientHeight = windowRect.bottom-windowRect.top;
745
int borderHeight = totalHeight-clientHeight;
746
747
// left tabs
748
GetWindowRect(leftTabs,&windowRect);
749
MapWindowPoints(HWND_DESKTOP,m_hDlg,(LPPOINT)&windowRect,2);
750
positions[1].x = windowRect.left;
751
positions[1].y = windowRect.top;
752
positions[1].w = positions[0].x-2*windowRect.left;
753
int borderMargin = positions[1].x;
754
755
float weight = hideBottomTabs ? 1.f : 390.f/500.f;
756
757
// don't use the part above the disassembly for the computations
758
int bottomHeightOffset = positions[0].y;
759
positions[0].w = width-borderMargin-positions[0].x;
760
positions[0].h = (height-bottomHeightOffset-topHeightOffset) * weight;
761
positions[0].h = ((positions[0].h-borderHeight)/disassemblyRowHeight)*disassemblyRowHeight+borderHeight;
762
positions[1].h = positions[0].h-(positions[1].y-positions[0].y);
763
764
// bottom tabs
765
positions[2].x = borderMargin;
766
positions[2].y = positions[0].y+positions[0].h+borderMargin;
767
positions[2].w = width-2*borderMargin;
768
positions[2].h = hideBottomTabs ? 0 : height-bottomHeightOffset-positions[2].y;
769
770
// now actually move all the windows
771
MoveWindow(disasm,positions[0].x,positions[0].y,positions[0].w,positions[0].h,TRUE);
772
MoveWindow(leftTabs,positions[1].x,positions[1].y,positions[1].w,positions[1].h,TRUE);
773
MoveWindow(bottomTabs,positions[2].x,positions[2].y,positions[2].w,positions[2].h,TRUE);
774
ShowWindow(bottomTabs,hideBottomTabs ? SW_HIDE : SW_NORMAL);
775
}
776
777
void CDisasm::SavePosition()
778
{
779
RECT rc;
780
if (GetWindowRect(m_hDlg, &rc))
781
{
782
g_Config.iDisasmWindowX = rc.left;
783
g_Config.iDisasmWindowY = rc.top;
784
g_Config.iDisasmWindowW = rc.right - rc.left;
785
g_Config.iDisasmWindowH = rc.bottom - rc.top;
786
}
787
}
788
789
void CDisasm::SetDebugMode(bool _bDebug, bool switchPC)
790
{
791
HWND hDlg = m_hDlg;
792
bool ingame = (GetUIState() == UISTATE_INGAME || GetUIState() == UISTATE_EXCEPTION) && PSP_IsInited();
793
794
// If we're stepping, update debugging windows.
795
// This is called potentially asynchronously, so state might've changed.
796
if (Core_IsStepping() && ingame) {
797
breakpointList->reloadBreakpoints();
798
threadList->reloadThreads();
799
stackTraceView->loadStackTrace();
800
moduleList->loadModules();
801
watchList_->RefreshValues();
802
803
EnableWindow(GetDlgItem(hDlg, IDC_STOPGO), TRUE);
804
EnableWindow(GetDlgItem(hDlg, IDC_STEP), TRUE);
805
EnableWindow(GetDlgItem(hDlg, IDC_STEPOVER), TRUE);
806
EnableWindow(GetDlgItem(hDlg, IDC_STEPHLE), TRUE);
807
EnableWindow(GetDlgItem(hDlg, IDC_STEPOUT), TRUE);
808
EnableWindow(GetDlgItem(hDlg, IDC_GOTOPC), TRUE);
809
EnableWindow(GetDlgItem(hDlg, IDC_GOTOLR), TRUE);
810
CtrlDisAsmView *ptr = DisAsmView();
811
ptr->setDontRedraw(false);
812
if (switchPC)
813
ptr->gotoPC();
814
815
ptr->scanFunctions();
816
}
817
else
818
{
819
if (ingame)
820
EnableWindow(GetDlgItem(hDlg, IDC_STOPGO), TRUE);
821
else
822
EnableWindow(GetDlgItem(hDlg, IDC_STOPGO), FALSE);
823
EnableWindow(GetDlgItem(hDlg, IDC_STEP), FALSE);
824
EnableWindow(GetDlgItem(hDlg, IDC_STEPOVER), FALSE);
825
EnableWindow(GetDlgItem(hDlg, IDC_STEPHLE), FALSE);
826
EnableWindow(GetDlgItem(hDlg, IDC_STEPOUT), FALSE);
827
EnableWindow(GetDlgItem(hDlg, IDC_GOTOPC), FALSE);
828
EnableWindow(GetDlgItem(hDlg, IDC_GOTOLR), FALSE);
829
CtrlRegisterList *reglist = CtrlRegisterList::getFrom(GetDlgItem(m_hDlg,IDC_REGLIST));
830
reglist->redraw();
831
}
832
833
UpdateDialog();
834
}
835
836
void CDisasm::Show(bool bShow, bool includeToTop) {
837
if (deferredSymbolFill_ && bShow) {
838
if (g_symbolMap) {
839
g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), ST_FUNCTION);
840
deferredSymbolFill_ = false;
841
}
842
}
843
Dialog::Show(bShow, includeToTop);
844
}
845
846
void CDisasm::NotifyMapLoaded() {
847
if (m_bShowState != SW_HIDE && g_symbolMap) {
848
g_symbolMap->FillSymbolListBox(GetDlgItem(m_hDlg, IDC_FUNCTIONLIST), ST_FUNCTION);
849
} else {
850
deferredSymbolFill_ = true;
851
}
852
CtrlDisAsmView *ptr = DisAsmView();
853
ptr->clearFunctions();
854
ptr->redraw();
855
}
856
857
void CDisasm::Goto(u32 addr)
858
{
859
CtrlDisAsmView *ptr = DisAsmView();
860
ptr->gotoAddr(addr);
861
SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
862
ptr->redraw();
863
}
864
865
void CDisasm::UpdateDialog() {
866
if (!updateDialogScheduled_) {
867
SetTimer(GetDlgHandle(), IDT_UPDATE, UPDATE_DELAY, nullptr);
868
updateDialogScheduled_ = true;
869
}
870
871
// Since these update on a delay, it's okay to do them immediately.
872
CtrlDisAsmView *ptr = DisAsmView();
873
ptr->redraw();
874
CtrlRegisterList *rl = CtrlRegisterList::getFrom(GetDlgItem(m_hDlg, IDC_REGLIST));
875
rl->redraw();
876
877
// Repaint windows at the bottom. only the memory view needs to be forced to redraw.
878
// All others are updated manually
879
CtrlMemView *memview = CtrlMemView::getFrom(GetDlgItem(m_hDlg, IDC_DEBUGMEMVIEW));
880
memview->redraw();
881
882
// Update memory window too.
883
if (memoryWindow)
884
memoryWindow->Update();
885
if (vfpudlg)
886
vfpudlg->Update();
887
}
888
889
void CDisasm::ProcessUpdateDialog() {
890
/*
891
HWND gotoInt = GetDlgItem(m_hDlg, IDC_GOTOINT);
892
ComboBox_ResetContent(gotoInt);
893
for (int i=0; i<numRegions; i++)
894
{
895
// TODO: wchar_t
896
int n = ComboBox_AddString(gotoInt,regions[i].name);
897
ComboBox_SetItemData(gotoInt,n,regions[i].start);
898
}
899
ComboBox_InsertString(gotoInt,0,"[Goto Rgn]");
900
ComboBox_SetItemData(gotoInt,0,0xFFFFFFFF);
901
ComboBox_SetCurSel(gotoInt,0);
902
*/
903
904
// Update Debug Counter
905
if (PSP_IsInited()) {
906
wchar_t tempTicks[24]{};
907
_snwprintf(tempTicks, 23, L"%lld", CoreTiming::GetTicks() - lastTicks);
908
SetDlgItemText(m_hDlg, IDC_DEBUG_COUNT, tempTicks);
909
}
910
911
bool ingame = (GetUIState() == UISTATE_INGAME || GetUIState() == UISTATE_EXCEPTION) && PSP_IsInited();
912
if (Core_IsStepping() || !ingame) {
913
SetDlgItemText(m_hDlg, IDC_STOPGO, L"Go");
914
} else {
915
SetDlgItemText(m_hDlg, IDC_STOPGO, L"Break");
916
}
917
918
updateThreadLabel(!ingame || !Core_IsStepping());
919
}
920
921
CtrlDisAsmView *CDisasm::DisAsmView() {
922
return CtrlDisAsmView::getFrom(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
923
}
924
925