Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/Debugger/Debugger_Lists.cpp
3185 views
1
#include "Windows/Debugger/Debugger_Lists.h"
2
#include "Common/CommonWindows.h"
3
#include <windowsx.h>
4
#include <commctrl.h>
5
#include "Windows/Debugger/BreakpointWindow.h"
6
#include "Windows/Debugger/CtrlDisAsmView.h"
7
#include "Windows/Debugger/DebuggerShared.h"
8
#include "Windows/Debugger/WatchItemWindow.h"
9
#include "Windows/W32Util/ContextMenu.h"
10
#include "Windows/MainWindow.h"
11
#include "Windows/resource.h"
12
#include "Windows/main.h"
13
#include "Common/Data/Encoding/Utf8.h"
14
#include "Core/HLE/sceKernelThread.h"
15
16
enum { TL_NAME, TL_PROGRAMCOUNTER, TL_ENTRYPOINT, TL_PRIORITY, TL_STATE, TL_WAITTYPE, TL_COLUMNCOUNT };
17
enum { BPL_ENABLED, BPL_TYPE, BPL_OFFSET, BPL_SIZELABEL, BPL_OPCODE, BPL_CONDITION, BPL_HITS, BPL_COLUMNCOUNT };
18
enum { SF_ENTRY, SF_ENTRYNAME, SF_CURPC, SF_CUROPCODE, SF_CURSP, SF_FRAMESIZE, SF_COLUMNCOUNT };
19
enum { ML_NAME, ML_ADDRESS, ML_SIZE, ML_ACTIVE, ML_COLUMNCOUNT };
20
enum { WL_NAME, WL_EXPRESSION, WL_VALUE, WL_COLUMNCOUNT };
21
22
GenericListViewColumn threadColumns[TL_COLUMNCOUNT] = {
23
{ L"Name", 0.20f },
24
{ L"PC", 0.15f },
25
{ L"Entry Point", 0.15f },
26
{ L"Priority", 0.15f },
27
{ L"State", 0.15f },
28
{ L"Wait type", 0.20f }
29
};
30
31
GenericListViewDef threadListDef = {
32
threadColumns, ARRAY_SIZE(threadColumns), NULL, false
33
};
34
35
GenericListViewColumn breakpointColumns[BPL_COLUMNCOUNT] = {
36
{ L"", 0.03f }, // enabled
37
{ L"Type", 0.15f },
38
{ L"Offset", 0.12f },
39
{ L"Size/Label", 0.20f },
40
{ L"Opcode", 0.28f },
41
{ L"Condition", 0.17f },
42
{ L"Hits", 0.05f },
43
};
44
45
GenericListViewDef breakpointListDef = {
46
breakpointColumns, ARRAY_SIZE(breakpointColumns), NULL, true
47
};
48
49
GenericListViewColumn stackTraceColumns[SF_COLUMNCOUNT] = {
50
{ L"Entry", 0.12f },
51
{ L"Name", 0.24f },
52
{ L"PC", 0.12f },
53
{ L"Opcode", 0.28f },
54
{ L"SP", 0.12f },
55
{ L"Frame Size", 0.12f }
56
};
57
58
GenericListViewDef stackTraceListDef = {
59
stackTraceColumns, ARRAY_SIZE(stackTraceColumns), NULL, false
60
};
61
62
GenericListViewColumn moduleListColumns[ML_COLUMNCOUNT] = {
63
{ L"Name", 0.25f },
64
{ L"Address", 0.25f },
65
{ L"Size", 0.25f },
66
{ L"Active", 0.25f },
67
};
68
69
GenericListViewDef moduleListDef = {
70
moduleListColumns, ARRAY_SIZE(moduleListColumns), NULL, false
71
};
72
73
GenericListViewColumn watchListColumns[WL_COLUMNCOUNT] = {
74
{ L"Name", 0.25f },
75
{ L"Expression", 0.5f },
76
{ L"Value", 0.25f },
77
};
78
79
GenericListViewDef watchListDef = {
80
watchListColumns, ARRAY_SIZE(watchListColumns), nullptr, false,
81
};
82
83
//
84
// CtrlThreadList
85
//
86
87
CtrlThreadList::CtrlThreadList(HWND hwnd): GenericListControl(hwnd,threadListDef)
88
{
89
Update();
90
}
91
92
bool CtrlThreadList::WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue)
93
{
94
switch (msg)
95
{
96
case WM_KEYDOWN:
97
if (wParam == VK_TAB)
98
{
99
SendMessage(GetParent(GetHandle()),WM_DEB_TABPRESSED,0,0);
100
returnValue = 0;
101
return true;
102
}
103
break;
104
case WM_GETDLGCODE:
105
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
106
{
107
if (wParam == VK_TAB)
108
{
109
returnValue = DLGC_WANTMESSAGE;
110
return true;
111
}
112
}
113
break;
114
}
115
116
return false;
117
}
118
119
void CtrlThreadList::showMenu(int itemIndex, const POINT &pt)
120
{
121
auto threadInfo = threads[itemIndex];
122
123
// Can't do it, sorry. Needs to not be running.
124
if (Core_IsActive())
125
return;
126
127
HMENU subMenu = GetContextMenu(ContextMenuID::THREADLIST);
128
switch (threadInfo.status) {
129
case THREADSTATUS_DEAD:
130
case THREADSTATUS_DORMANT:
131
case THREADSTATUS_RUNNING:
132
EnableMenuItem(subMenu, ID_DISASM_THREAD_FORCERUN, MF_BYCOMMAND | MF_DISABLED);
133
EnableMenuItem(subMenu, ID_DISASM_THREAD_KILL, MF_BYCOMMAND | MF_DISABLED);
134
break;
135
case THREADSTATUS_READY:
136
EnableMenuItem(subMenu, ID_DISASM_THREAD_FORCERUN, MF_BYCOMMAND | MF_DISABLED);
137
EnableMenuItem(subMenu, ID_DISASM_THREAD_KILL, MF_BYCOMMAND | MF_ENABLED);
138
break;
139
case THREADSTATUS_SUSPEND:
140
case THREADSTATUS_WAIT:
141
case THREADSTATUS_WAITSUSPEND:
142
default:
143
EnableMenuItem(subMenu, ID_DISASM_THREAD_FORCERUN, MF_BYCOMMAND | MF_ENABLED);
144
EnableMenuItem(subMenu, ID_DISASM_THREAD_KILL, MF_BYCOMMAND | MF_ENABLED);
145
break;
146
}
147
148
switch (TriggerContextMenu(ContextMenuID::THREADLIST, GetHandle(), ContextPoint::FromClient(pt)))
149
{
150
case ID_DISASM_THREAD_FORCERUN:
151
__KernelResumeThreadFromWait(threadInfo.id, 0);
152
reloadThreads();
153
break;
154
case ID_DISASM_THREAD_KILL:
155
sceKernelTerminateThread(threadInfo.id);
156
reloadThreads();
157
break;
158
}
159
}
160
161
void CtrlThreadList::GetColumnText(wchar_t* dest, size_t destSize, int row, int col)
162
{
163
if (row < 0 || row >= (int)threads.size()) {
164
return;
165
}
166
167
switch (col)
168
{
169
case TL_NAME:
170
wcscpy(dest, ConvertUTF8ToWString(threads[row].name).c_str());
171
break;
172
case TL_PROGRAMCOUNTER:
173
switch (threads[row].status)
174
{
175
case THREADSTATUS_DORMANT:
176
case THREADSTATUS_DEAD:
177
wcscpy(dest, L"N/A");
178
break;
179
default:
180
wsprintf(dest, L"0x%08X",threads[row].curPC);
181
break;
182
};
183
break;
184
case TL_ENTRYPOINT:
185
wsprintf(dest,L"0x%08X",threads[row].entrypoint);
186
break;
187
case TL_PRIORITY:
188
wsprintf(dest,L"%d",threads[row].priority);
189
break;
190
case TL_STATE:
191
switch (threads[row].status)
192
{
193
case THREADSTATUS_RUNNING:
194
wcscpy(dest,L"Running");
195
break;
196
case THREADSTATUS_READY:
197
wcscpy(dest,L"Ready");
198
break;
199
case THREADSTATUS_WAIT:
200
wcscpy(dest,L"Waiting");
201
break;
202
case THREADSTATUS_SUSPEND:
203
wcscpy(dest,L"Suspended");
204
break;
205
case THREADSTATUS_DORMANT:
206
wcscpy(dest,L"Dormant");
207
break;
208
case THREADSTATUS_DEAD:
209
wcscpy(dest,L"Dead");
210
break;
211
case THREADSTATUS_WAITSUSPEND:
212
wcscpy(dest,L"Waiting/Suspended");
213
break;
214
default:
215
wcscpy(dest,L"Invalid");
216
break;
217
}
218
break;
219
case TL_WAITTYPE:
220
wcscpy(dest, ConvertUTF8ToWString(WaitTypeToString(threads[row].waitType)).c_str());
221
break;
222
}
223
}
224
225
void CtrlThreadList::OnDoubleClick(int itemIndex, int column)
226
{
227
u32 address;
228
switch (threads[itemIndex].status)
229
{
230
case THREADSTATUS_DORMANT:
231
case THREADSTATUS_DEAD:
232
address = threads[itemIndex].entrypoint;
233
break;
234
default:
235
address = threads[itemIndex].curPC;
236
break;
237
}
238
239
SendMessage(GetParent(GetHandle()),WM_DEB_GOTOWPARAM,address,0);
240
}
241
242
void CtrlThreadList::OnRightClick(int itemIndex, int column, const POINT& point)
243
{
244
showMenu(itemIndex,point);
245
}
246
247
void CtrlThreadList::reloadThreads()
248
{
249
threads = GetThreadsInfo();
250
Update();
251
}
252
253
const char* CtrlThreadList::getCurrentThreadName()
254
{
255
for (size_t i = 0; i < threads.size(); i++)
256
{
257
if (threads[i].isCurrent) return threads[i].name;
258
}
259
260
return "N/A";
261
}
262
263
264
//
265
// CtrlBreakpointList
266
//
267
268
CtrlBreakpointList::CtrlBreakpointList(HWND hwnd, MIPSDebugInterface* cpu, CtrlDisAsmView* disasm)
269
: GenericListControl(hwnd,breakpointListDef),cpu(cpu),disasm(disasm)
270
{
271
SetSendInvalidRows(true);
272
Update();
273
}
274
275
bool CtrlBreakpointList::WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue)
276
{
277
switch(msg)
278
{
279
case WM_KEYDOWN:
280
returnValue = 0;
281
if(wParam == VK_RETURN)
282
{
283
int index = GetSelectedIndex();
284
editBreakpoint(index);
285
return true;
286
} else if (wParam == VK_DELETE)
287
{
288
int index = GetSelectedIndex();
289
removeBreakpoint(index);
290
return true;
291
} else if (wParam == VK_TAB)
292
{
293
SendMessage(GetParent(GetHandle()),WM_DEB_TABPRESSED,0,0);
294
return true;
295
} else if (wParam == VK_SPACE)
296
{
297
int index = GetSelectedIndex();
298
toggleEnabled(index);
299
return true;
300
}
301
break;
302
case WM_GETDLGCODE:
303
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
304
{
305
if (wParam == VK_TAB || wParam == VK_RETURN)
306
{
307
returnValue = DLGC_WANTMESSAGE;
308
return true;
309
}
310
}
311
break;
312
}
313
314
return false;
315
}
316
317
void CtrlBreakpointList::reloadBreakpoints()
318
{
319
// Update the items we're displaying from the debugger.
320
displayedBreakPoints_ = g_breakpoints.GetBreakpoints();
321
displayedMemChecks_= g_breakpoints.GetMemChecks();
322
323
for (int i = 0; i < GetRowCount(); i++)
324
{
325
bool isMemory;
326
int index = getBreakpointIndex(i, isMemory);
327
if (index < 0)
328
continue;
329
330
if (isMemory)
331
SetCheckState(i, displayedMemChecks_[index].IsEnabled());
332
else
333
SetCheckState(i, displayedBreakPoints_[index].IsEnabled());
334
}
335
336
Update();
337
}
338
339
void CtrlBreakpointList::editBreakpoint(int itemIndex)
340
{
341
bool isMemory;
342
int index = getBreakpointIndex(itemIndex, isMemory);
343
if (index == -1) return;
344
345
BreakpointWindow win(GetHandle(),cpu);
346
if (isMemory)
347
{
348
auto mem = displayedMemChecks_[index];
349
win.loadFromMemcheck(mem);
350
if (win.exec())
351
{
352
g_breakpoints.RemoveMemCheck(mem.start,mem.end);
353
win.addBreakpoint();
354
}
355
} else {
356
auto bp = displayedBreakPoints_[index];
357
win.loadFromBreakpoint(bp);
358
if (win.exec())
359
{
360
g_breakpoints.RemoveBreakPoint(bp.addr);
361
win.addBreakpoint();
362
}
363
}
364
}
365
366
void CtrlBreakpointList::toggleEnabled(int itemIndex)
367
{
368
bool isMemory;
369
int index = getBreakpointIndex(itemIndex, isMemory);
370
if (index == -1) return;
371
372
if (isMemory) {
373
MemCheck mcPrev = displayedMemChecks_[index];
374
g_breakpoints.ChangeMemCheck(mcPrev.start, mcPrev.end, mcPrev.cond, BreakAction(mcPrev.result ^ BREAK_ACTION_PAUSE));
375
} else {
376
BreakPoint bpPrev = displayedBreakPoints_[index];
377
g_breakpoints.ChangeBreakPoint(bpPrev.addr, BreakAction(bpPrev.result ^ BREAK_ACTION_PAUSE));
378
}
379
}
380
381
void CtrlBreakpointList::gotoBreakpointAddress(int itemIndex)
382
{
383
bool isMemory;
384
int index = getBreakpointIndex(itemIndex, isMemory);
385
if (index == -1)
386
return;
387
388
if (isMemory) {
389
u32 address = displayedMemChecks_[index].start;
390
MainWindow::CreateMemoryWindow();
391
if (memoryWindow)
392
memoryWindow->Goto(address);
393
} else {
394
u32 address = displayedBreakPoints_[index].addr;
395
MainWindow::CreateDisasmWindow();
396
if (disasmWindow)
397
disasmWindow->Goto(address);
398
}
399
}
400
401
void CtrlBreakpointList::removeBreakpoint(int itemIndex)
402
{
403
bool isMemory;
404
int index = getBreakpointIndex(itemIndex,isMemory);
405
if (index == -1) return;
406
407
if (isMemory) {
408
auto mc = displayedMemChecks_[index];
409
g_breakpoints.RemoveMemCheck(mc.start, mc.end);
410
} else {
411
u32 address = displayedBreakPoints_[index].addr;
412
g_breakpoints.RemoveBreakPoint(address);
413
}
414
}
415
416
int CtrlBreakpointList::getTotalBreakpointCount() {
417
int count = (int)displayedMemChecks_.size();
418
for (auto bp : displayedBreakPoints_) {
419
if (!bp.temporary)
420
++count;
421
}
422
423
return count;
424
}
425
426
int CtrlBreakpointList::getBreakpointIndex(int itemIndex, bool& isMemory)
427
{
428
// memory breakpoints first
429
if (itemIndex < (int)displayedMemChecks_.size())
430
{
431
isMemory = true;
432
return itemIndex;
433
}
434
435
itemIndex -= (int)displayedMemChecks_.size();
436
437
size_t i = 0;
438
while (i < displayedBreakPoints_.size())
439
{
440
if (displayedBreakPoints_[i].temporary)
441
{
442
i++;
443
continue;
444
}
445
446
// the index is 0 when there are no more breakpoints to skip
447
if (itemIndex == 0)
448
{
449
isMemory = false;
450
return (int)i;
451
}
452
453
i++;
454
itemIndex--;
455
}
456
457
return -1;
458
}
459
460
void CtrlBreakpointList::GetColumnText(wchar_t* dest, size_t destSize, int row, int col)
461
{
462
if (!PSP_IsInited()) {
463
return;
464
}
465
bool isMemory;
466
int index = getBreakpointIndex(row,isMemory);
467
if (index == -1) return;
468
469
switch (col)
470
{
471
case BPL_TYPE:
472
{
473
if (isMemory) {
474
switch ((int)displayedMemChecks_[index].cond) {
475
case MEMCHECK_READ:
476
wcscpy(dest,L"Read");
477
break;
478
case MEMCHECK_WRITE:
479
wcscpy(dest,L"Write");
480
break;
481
case MEMCHECK_READWRITE:
482
wcscpy(dest,L"Read/Write");
483
break;
484
case MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE:
485
wcscpy(dest,L"Write Change");
486
break;
487
case MEMCHECK_READWRITE | MEMCHECK_WRITE_ONCHANGE:
488
wcscpy(dest,L"Read/Write Change");
489
break;
490
}
491
} else {
492
wcscpy(dest, L"Execute");
493
}
494
}
495
break;
496
case BPL_OFFSET:
497
{
498
if (isMemory) {
499
wsprintf(dest,L"0x%08X",displayedMemChecks_[index].start);
500
} else {
501
wsprintf(dest,L"0x%08X",displayedBreakPoints_[index].addr);
502
}
503
}
504
break;
505
case BPL_SIZELABEL:
506
{
507
if (isMemory) {
508
auto mc = displayedMemChecks_[index];
509
if (mc.end == 0)
510
wsprintf(dest,L"0x%08X",1);
511
else
512
wsprintf(dest,L"0x%08X",mc.end-mc.start);
513
} else {
514
const std::string sym = g_symbolMap->GetLabelString(displayedBreakPoints_[index].addr);
515
if (!sym.empty()) {
516
ConvertUTF8ToWString(dest, destSize, sym);
517
} else {
518
wcscpy(dest,L"-");
519
}
520
}
521
}
522
break;
523
case BPL_OPCODE:
524
{
525
if (isMemory) {
526
wcscpy(dest,L"-");
527
} else {
528
char temp[256];
529
disasm->getOpcodeText(displayedBreakPoints_[index].addr, temp, sizeof(temp));
530
ConvertUTF8ToWString(dest, destSize, temp);
531
}
532
}
533
break;
534
case BPL_CONDITION:
535
{
536
if (isMemory || displayedBreakPoints_[index].hasCond == false) {
537
wcscpy(dest,L"-");
538
} else {
539
std::wstring s = ConvertUTF8ToWString(displayedBreakPoints_[index].cond.expressionString);
540
wcscpy(dest,s.c_str());
541
}
542
}
543
break;
544
case BPL_HITS:
545
{
546
if (isMemory) {
547
wsprintf(dest,L"%d",displayedMemChecks_[index].numHits);
548
} else {
549
wsprintf(dest,L"-");
550
}
551
}
552
break;
553
case BPL_ENABLED:
554
{
555
wsprintf(dest,L"\xFFFE");
556
}
557
break;
558
}
559
}
560
561
void CtrlBreakpointList::OnDoubleClick(int itemIndex, int column)
562
{
563
gotoBreakpointAddress(itemIndex);
564
}
565
566
void CtrlBreakpointList::OnRightClick(int itemIndex, int column, const POINT& point)
567
{
568
showBreakpointMenu(itemIndex,point);
569
}
570
571
void CtrlBreakpointList::OnToggle(int item, bool newValue)
572
{
573
toggleEnabled(item);
574
}
575
576
void CtrlBreakpointList::showBreakpointMenu(int itemIndex, const POINT &pt)
577
{
578
bool isMemory;
579
int index = getBreakpointIndex(itemIndex, isMemory);
580
if (index == -1)
581
{
582
switch (TriggerContextMenu(ContextMenuID::NEWBREAKPOINT, GetHandle(), ContextPoint::FromClient(pt)))
583
{
584
case ID_DISASM_ADDNEWBREAKPOINT:
585
{
586
BreakpointWindow bpw(GetHandle(),cpu);
587
if (bpw.exec()) bpw.addBreakpoint();
588
}
589
break;
590
}
591
} else {
592
MemCheck mcPrev;
593
BreakPoint bpPrev;
594
if (isMemory) {
595
mcPrev = displayedMemChecks_[index];
596
} else {
597
bpPrev = displayedBreakPoints_[index];
598
}
599
600
HMENU subMenu = GetContextMenu(ContextMenuID::BREAKPOINTLIST);
601
if (isMemory) {
602
CheckMenuItem(subMenu, ID_DISASM_DISABLEBREAKPOINT, MF_BYCOMMAND | (mcPrev.IsEnabled() ? MF_CHECKED : MF_UNCHECKED));
603
} else {
604
CheckMenuItem(subMenu, ID_DISASM_DISABLEBREAKPOINT, MF_BYCOMMAND | (bpPrev.IsEnabled() ? MF_CHECKED : MF_UNCHECKED));
605
}
606
607
switch (TriggerContextMenu(ContextMenuID::BREAKPOINTLIST, GetHandle(), ContextPoint::FromClient(pt)))
608
{
609
case ID_DISASM_DISABLEBREAKPOINT:
610
if (isMemory) {
611
g_breakpoints.ChangeMemCheck(mcPrev.start, mcPrev.end, mcPrev.cond, BreakAction(mcPrev.result ^ BREAK_ACTION_PAUSE));
612
} else {
613
g_breakpoints.ChangeBreakPoint(bpPrev.addr, BreakAction(bpPrev.result ^ BREAK_ACTION_PAUSE));
614
}
615
break;
616
case ID_DISASM_EDITBREAKPOINT:
617
editBreakpoint(itemIndex);
618
break;
619
case ID_DISASM_ADDNEWBREAKPOINT:
620
{
621
BreakpointWindow bpw(GetHandle(),cpu);
622
if (bpw.exec()) bpw.addBreakpoint();
623
}
624
break;
625
case ID_DISASM_DELETEBREAKPOINT:
626
removeBreakpoint(itemIndex);
627
break;
628
}
629
}
630
}
631
632
//
633
// CtrlStackTraceView
634
//
635
636
CtrlStackTraceView::CtrlStackTraceView(HWND hwnd, DebugInterface* cpu, CtrlDisAsmView* disasm)
637
: GenericListControl(hwnd,stackTraceListDef),cpu(cpu),disasm(disasm)
638
{
639
Update();
640
}
641
642
bool CtrlStackTraceView::WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue)
643
{
644
switch(msg)
645
{
646
case WM_KEYDOWN:
647
if (wParam == VK_TAB)
648
{
649
returnValue = 0;
650
SendMessage(GetParent(GetHandle()),WM_DEB_TABPRESSED,0,0);
651
return true;
652
}
653
break;
654
case WM_GETDLGCODE:
655
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
656
{
657
if (wParam == VK_TAB || wParam == VK_RETURN)
658
{
659
returnValue = DLGC_WANTMESSAGE;
660
return true;
661
}
662
}
663
break;
664
}
665
666
return false;
667
}
668
669
void CtrlStackTraceView::GetColumnText(wchar_t* dest, size_t destSize, int row, int col)
670
{
671
// We should have emptied the list if g_symbolMap is nullptr, but apparently we don't,
672
// so let's have a sanity check here.
673
if (row < 0 || row >= (int)frames.size() || !g_symbolMap) {
674
return;
675
}
676
677
switch (col)
678
{
679
case SF_ENTRY:
680
wsprintf(dest,L"%08X",frames[row].entry);
681
break;
682
case SF_ENTRYNAME:
683
{
684
const std::string sym = g_symbolMap->GetLabelString(frames[row].entry);
685
if (!sym.empty()) {
686
wcscpy(dest, ConvertUTF8ToWString(sym).c_str());
687
} else {
688
wcscpy(dest,L"-");
689
}
690
}
691
break;
692
case SF_CURPC:
693
wsprintf(dest,L"%08X",frames[row].pc);
694
break;
695
case SF_CUROPCODE:
696
{
697
char temp[512];
698
disasm->getOpcodeText(frames[row].pc, temp, sizeof(temp));
699
wcscpy(dest, ConvertUTF8ToWString(temp).c_str());
700
}
701
break;
702
case SF_CURSP:
703
wsprintf(dest,L"%08X",frames[row].sp);
704
break;
705
case SF_FRAMESIZE:
706
wsprintf(dest,L"%08X",frames[row].stackSize);
707
break;
708
}
709
}
710
711
void CtrlStackTraceView::OnDoubleClick(int itemIndex, int column)
712
{
713
SendMessage(GetParent(GetHandle()),WM_DEB_GOTOWPARAM,frames[itemIndex].pc,0);
714
}
715
716
void CtrlStackTraceView::loadStackTrace() {
717
auto memLock = Memory::Lock();
718
if (!PSP_IsInited())
719
return;
720
721
auto threads = GetThreadsInfo();
722
723
u32 entry = 0, stackTop = 0;
724
for (size_t i = 0; i < threads.size(); i++)
725
{
726
if (threads[i].isCurrent)
727
{
728
entry = threads[i].entrypoint;
729
stackTop = threads[i].initialStack;
730
break;
731
}
732
}
733
734
if (entry != 0) {
735
frames = MIPSStackWalk::Walk(cpu->GetPC(),cpu->GetRegValue(0,31),cpu->GetRegValue(0,29),entry,stackTop);
736
} else {
737
frames.clear();
738
}
739
Update();
740
}
741
742
//
743
// CtrlModuleList
744
//
745
746
CtrlModuleList::CtrlModuleList(HWND hwnd, DebugInterface* cpu)
747
: GenericListControl(hwnd,moduleListDef),cpu(cpu)
748
{
749
Update();
750
}
751
752
bool CtrlModuleList::WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT& returnValue)
753
{
754
switch(msg)
755
{
756
case WM_KEYDOWN:
757
if (wParam == VK_TAB)
758
{
759
returnValue = 0;
760
SendMessage(GetParent(GetHandle()),WM_DEB_TABPRESSED,0,0);
761
return true;
762
}
763
break;
764
case WM_GETDLGCODE:
765
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
766
{
767
if (wParam == VK_TAB || wParam == VK_RETURN)
768
{
769
returnValue = DLGC_WANTMESSAGE;
770
return true;
771
}
772
}
773
break;
774
}
775
776
return false;
777
}
778
779
void CtrlModuleList::GetColumnText(wchar_t* dest, size_t destSize, int row, int col)
780
{
781
if (row < 0 || row >= (int)modules.size()) {
782
return;
783
}
784
785
switch (col) {
786
case ML_NAME:
787
ConvertUTF8ToWString(dest, destSize, modules[row].name);
788
break;
789
case ML_ADDRESS:
790
wsprintf(dest,L"%08X",modules[row].address);
791
break;
792
case ML_SIZE:
793
wsprintf(dest,L"%08X",modules[row].size);
794
break;
795
case ML_ACTIVE:
796
wcscpy(dest,modules[row].active ? L"true" : L"false");
797
break;
798
}
799
}
800
801
void CtrlModuleList::OnDoubleClick(int itemIndex, int column)
802
{
803
SendMessage(GetParent(GetHandle()),WM_DEB_GOTOWPARAM,modules[itemIndex].address,0);
804
}
805
806
void CtrlModuleList::loadModules()
807
{
808
if (g_symbolMap) {
809
modules = g_symbolMap->getAllModules();
810
} else {
811
modules.clear();
812
}
813
Update();
814
}
815
816
// In case you modify things in the memory view.
817
static constexpr UINT_PTR IDT_CHECK_REFRESH = 0xC0DE0044;
818
819
CtrlWatchList::CtrlWatchList(HWND hwnd, DebugInterface *cpu)
820
: GenericListControl(hwnd, watchListDef), cpu_(cpu) {
821
SetSendInvalidRows(true);
822
Update();
823
824
SetTimer(GetHandle(), IDT_CHECK_REFRESH, 1000U, nullptr);
825
}
826
827
void CtrlWatchList::RefreshValues() {
828
int steppingCounter = Core_GetSteppingCounter();
829
int changes = false;
830
for (auto &watch : watches_) {
831
if (watch.steppingCounter != steppingCounter) {
832
watch.lastValue = watch.currentValue;
833
watch.steppingCounter = steppingCounter;
834
changes = true;
835
}
836
837
uint32_t prevValue = watch.currentValue;
838
watch.evaluateFailed = !parseExpression(cpu_, watch.expression, watch.currentValue);
839
if (prevValue != watch.currentValue)
840
changes = true;
841
}
842
843
if (changes)
844
Update();
845
}
846
847
bool CtrlWatchList::WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) {
848
switch (msg) {
849
case WM_KEYDOWN:
850
switch (wParam) {
851
case VK_TAB:
852
returnValue = 0;
853
SendMessage(GetParent(GetHandle()), WM_DEB_TABPRESSED, 0, 0);
854
return true;
855
case VK_RETURN:
856
returnValue = 0;
857
EditWatch(GetSelectedIndex());
858
return true;
859
case VK_DELETE:
860
returnValue = 0;
861
DeleteWatch(GetSelectedIndex());
862
return true;
863
default:
864
break;
865
}
866
break;
867
case WM_GETDLGCODE:
868
if (lParam && ((MSG *)lParam)->message == WM_KEYDOWN) {
869
if (wParam == VK_TAB || wParam == VK_RETURN || wParam == VK_DELETE) {
870
returnValue = DLGC_WANTMESSAGE;
871
return true;
872
}
873
}
874
break;
875
case WM_TIMER:
876
if (wParam == IDT_CHECK_REFRESH) {
877
RefreshValues();
878
return true;
879
}
880
break;
881
}
882
883
return false;
884
}
885
886
void CtrlWatchList::GetColumnText(wchar_t *dest, size_t destSize, int row, int col) {
887
const auto &watch = watches_[row];
888
switch (col) {
889
case WL_NAME:
890
wcsncpy(dest, ConvertUTF8ToWString(watch.name).c_str(), 255);
891
dest[255] = 0;
892
break;
893
case WL_EXPRESSION:
894
wcsncpy(dest, ConvertUTF8ToWString(watch.originalExpression).c_str(), 255);
895
dest[255] = 0;
896
break;
897
case WL_VALUE:
898
if (watch.evaluateFailed) {
899
wcscpy(dest, L"(failed to evaluate)");
900
} else {
901
const uint32_t &value = watch.currentValue;
902
float valuef = 0.0f;
903
switch (watch.format) {
904
case WatchFormat::HEX:
905
wsprintf(dest, L"0x%08X", value);
906
break;
907
case WatchFormat::INT:
908
wsprintf(dest, L"%d", (int32_t)value);
909
break;
910
case WatchFormat::FLOAT:
911
memcpy(&valuef, &value, sizeof(valuef));
912
swprintf_s(dest, destSize, L"%f", valuef);
913
break;
914
case WatchFormat::STR:
915
if (Memory::IsValidAddress(value)) {
916
uint32_t len = Memory::ValidSize(value, 255);
917
swprintf_s(dest, destSize, L"%.*S", len, Memory::GetCharPointer(value));
918
} else {
919
wsprintf(dest, L"(0x%08X)", value);
920
}
921
break;
922
}
923
}
924
break;
925
}
926
}
927
928
void CtrlWatchList::OnRightClick(int itemIndex, int column, const POINT &pt) {
929
if (itemIndex == -1) {
930
switch (TriggerContextMenu(ContextMenuID::CPUADDWATCH, GetHandle(), ContextPoint::FromClient(pt))) {
931
case ID_DISASM_ADDNEWBREAKPOINT:
932
AddWatch();
933
break;
934
}
935
} else {
936
switch (TriggerContextMenu(ContextMenuID::CPUWATCHLIST, GetHandle(), ContextPoint::FromClient(pt))) {
937
case ID_DISASM_EDITBREAKPOINT:
938
EditWatch(itemIndex);
939
break;
940
case ID_DISASM_DELETEBREAKPOINT:
941
DeleteWatch(itemIndex);
942
break;
943
case ID_DISASM_ADDNEWBREAKPOINT:
944
AddWatch();
945
break;
946
}
947
}
948
}
949
950
bool CtrlWatchList::OnRowPrePaint(int row, LPNMLVCUSTOMDRAW msg) {
951
if (row >= 0 && HasWatchChanged(row)) {
952
msg->clrText = RGB(255, 0, 0);
953
return true;
954
}
955
return false;
956
}
957
958
void CtrlWatchList::AddWatch() {
959
WatchItemWindow win(nullptr, GetHandle(), cpu_);
960
if (win.Exec()) {
961
WatchInfo info;
962
if (initExpression(cpu_, win.GetExpression().c_str(), info.expression)) {
963
info.name = win.GetName();
964
info.originalExpression = win.GetExpression();
965
info.format = win.GetFormat();
966
watches_.push_back(info);
967
RefreshValues();
968
} else {
969
char errorMessage[512];
970
snprintf(errorMessage, sizeof(errorMessage), "Invalid expression \"%s\": %s", win.GetExpression().c_str(), getExpressionError());
971
MessageBoxA(GetHandle(), errorMessage, "Error", MB_OK);
972
}
973
}
974
}
975
976
void CtrlWatchList::EditWatch(int pos) {
977
auto &watch = watches_[pos];
978
WatchItemWindow win(nullptr, GetHandle(), cpu_);
979
win.Init(watch.name, watch.originalExpression, watch.format);
980
if (win.Exec()) {
981
if (initExpression(cpu_, win.GetExpression().c_str(), watch.expression)) {
982
watch.name = win.GetName();
983
watch.originalExpression = win.GetExpression();
984
watch.format = win.GetFormat();
985
RefreshValues();
986
} else {
987
char errorMessage[512];
988
snprintf(errorMessage, sizeof(errorMessage), "Invalid expression \"%s\": %s", win.GetExpression().c_str(), getExpressionError());
989
MessageBoxA(GetHandle(), errorMessage, "Error", MB_OK);
990
}
991
}
992
}
993
994
void CtrlWatchList::DeleteWatch(int pos) {
995
watches_.erase(watches_.begin() + pos);
996
Update();
997
}
998
999
bool CtrlWatchList::HasWatchChanged(int pos) {
1000
return watches_[pos].lastValue != watches_[pos].currentValue;
1001
}
1002
1003