Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/Debugger/CtrlDisAsmView.cpp
5654 views
1
#include "Windows/resource.h"
2
#include "Core/MemMap.h"
3
#include "Windows/W32Util/ContextMenu.h"
4
#include "Windows/W32Util/Misc.h"
5
#include "Windows/W32Util/ShellUtil.h"
6
#include "Windows/MainWindow.h"
7
#include "Windows/InputBox.h"
8
9
#include "Core/MIPS/MIPSAsm.h"
10
#include "Core/MIPS/MIPSAnalyst.h"
11
#include "Core/MIPS/MIPSTables.h"
12
#include "Core/Config.h"
13
#include "Core/Debugger/SymbolMap.h"
14
#include "Core/Reporting.h"
15
#include "Common/StringUtils.h"
16
#include "Windows/Debugger/CtrlDisAsmView.h"
17
#include "Windows/Debugger/DebuggerShared.h"
18
#include "Windows/Debugger/BreakpointWindow.h"
19
#include "Windows/Debugger/EditSymbolsWindow.h"
20
#include "Core/RetroAchievements.h"
21
#include "Windows/main.h"
22
23
#include "Common/CommonWindows.h"
24
#include "Common/Data/Encoding/Utf8.h"
25
#include "Common/System/Display.h"
26
27
#include <set>
28
29
constexpr const wchar_t *szClassName = L"CtrlDisAsmView";
30
31
static constexpr UINT_PTR IDT_REDRAW = 0xC0DE0001;
32
static constexpr UINT REDRAW_DELAY = 1000 / 60;
33
34
void CtrlDisAsmView::init()
35
{
36
WNDCLASSEX wc;
37
38
wc.cbSize = sizeof(wc);
39
wc.lpszClassName = szClassName;
40
wc.hInstance = GetModuleHandle(0);
41
wc.lpfnWndProc = CtrlDisAsmView::wndProc;
42
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
43
wc.hIcon = 0;
44
wc.lpszMenuName = 0;
45
wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
46
wc.style = 0;
47
wc.cbClsExtra = 0;
48
wc.cbWndExtra = sizeof( CtrlDisAsmView * );
49
wc.hIconSm = 0;
50
51
RegisterClassEx(&wc);
52
}
53
54
void CtrlDisAsmView::deinit()
55
{
56
//UnregisterClass(szClassName, hInst)
57
}
58
59
void CtrlDisAsmView::scanVisibleFunctions()
60
{
61
g_disassemblyManager.analyze(windowStart, g_disassemblyManager.getNthNextAddress(windowStart,visibleRows)-windowStart);
62
}
63
64
LRESULT CALLBACK CtrlDisAsmView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
65
{
66
CtrlDisAsmView *ccp = CtrlDisAsmView::getFrom(hwnd);
67
static bool lmbDown=false,rmbDown=false;
68
switch(msg)
69
{
70
case WM_NCCREATE:
71
// Allocate a new CustCtrl structure for this window.
72
ccp = new CtrlDisAsmView(hwnd);
73
74
// Continue with window creation.
75
return ccp != NULL;
76
77
// Clean up when the window is destroyed.
78
case WM_NCDESTROY:
79
delete ccp;
80
break;
81
case WM_SETFONT:
82
break;
83
case WM_SIZE:
84
ccp->redraw();
85
break;
86
case WM_PAINT:
87
ccp->onPaint(wParam,lParam);
88
break;
89
case WM_VSCROLL:
90
ccp->onVScroll(wParam,lParam);
91
break;
92
case WM_MOUSEWHEEL:
93
ccp->dontRedraw = false;
94
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
95
{
96
ccp->scrollWindow(-3);
97
} else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {
98
ccp->scrollWindow(3);
99
}
100
break;
101
case WM_ERASEBKGND:
102
return FALSE;
103
case WM_KEYDOWN:
104
ccp->onKeyDown(wParam,lParam);
105
return 0;
106
case WM_CHAR:
107
ccp->onChar(wParam,lParam);
108
return 0;
109
case WM_SYSKEYDOWN:
110
ccp->onKeyDown(wParam,lParam);
111
return 0; // return a value so that windows doesn't execute the standard syskey action
112
case WM_KEYUP:
113
ccp->onKeyUp(wParam,lParam);
114
return 0;
115
case WM_LBUTTONDOWN: lmbDown=true; ccp->onMouseDown(wParam,lParam,1); break;
116
case WM_RBUTTONDOWN: rmbDown=true; ccp->onMouseDown(wParam,lParam,2); break;
117
case WM_MOUSEMOVE: ccp->onMouseMove(wParam,lParam,(lmbDown?1:0) | (rmbDown?2:0)); break;
118
case WM_LBUTTONUP: lmbDown=false; ccp->onMouseUp(wParam,lParam,1); break;
119
case WM_RBUTTONUP: rmbDown=false; ccp->onMouseUp(wParam,lParam,2); break;
120
case WM_SETFOCUS:
121
SetFocus(hwnd);
122
ccp->hasFocus=true;
123
ccp->redraw();
124
break;
125
case WM_KILLFOCUS:
126
ccp->hasFocus=false;
127
lmbDown = false;
128
rmbDown = false;
129
ccp->redraw();
130
break;
131
case WM_GETDLGCODE:
132
if (lParam && ((MSG*)lParam)->message == WM_KEYDOWN)
133
{
134
switch (wParam)
135
{
136
case VK_TAB:
137
return DLGC_WANTMESSAGE;
138
default:
139
return DLGC_WANTCHARS|DLGC_WANTARROWS;
140
}
141
}
142
return DLGC_WANTCHARS|DLGC_WANTARROWS;
143
144
case WM_TIMER:
145
if (wParam == IDT_REDRAW) {
146
InvalidateRect(hwnd, nullptr, FALSE);
147
UpdateWindow(hwnd);
148
ccp->redrawScheduled_ = false;
149
KillTimer(hwnd, wParam);
150
}
151
break;
152
153
default:
154
break;
155
}
156
157
return DefWindowProc(hwnd, msg, wParam, lParam);
158
}
159
160
161
CtrlDisAsmView *CtrlDisAsmView::getFrom(HWND hwnd)
162
{
163
return (CtrlDisAsmView *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
164
}
165
166
CtrlDisAsmView::CtrlDisAsmView(HWND _wnd)
167
{
168
wnd=_wnd;
169
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this);
170
SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL);
171
SetScrollRange(wnd, SB_VERT, -1, 1, TRUE);
172
173
const float fontScale = 1.0f / g_display.dpi_scale_real_y;
174
charWidth = g_Config.iFontWidth * fontScale;
175
rowHeight = (g_Config.iFontHeight + 2) * fontScale;
176
int scaledFontHeight = g_Config.iFontHeight * fontScale;
177
font = CreateFont(scaledFontHeight, charWidth, 0, 0,
178
FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
179
L"Lucida Console");
180
boldfont = CreateFont(scaledFontHeight, charWidth, 0, 0,
181
FW_DEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,
182
L"Lucida Console");
183
184
curAddress = 0;
185
showHex = false;
186
hasFocus = false;
187
dontRedraw = false;
188
keyTaken = false;
189
190
matchAddress = -1;
191
searching = false;
192
searchQuery.clear();
193
windowStart = curAddress;
194
whiteBackground = false;
195
displaySymbols = true;
196
calculatePixelPositions();
197
}
198
199
200
CtrlDisAsmView::~CtrlDisAsmView()
201
{
202
DeleteObject(font);
203
DeleteObject(boldfont);
204
g_disassemblyManager.clear();
205
}
206
207
static COLORREF scaleColor(COLORREF color, float factor)
208
{
209
unsigned char r = color & 0xFF;
210
unsigned char g = (color >> 8) & 0xFF;
211
unsigned char b = (color >> 16) & 0xFF;
212
213
r = std::min(255, std::max((int)(r * factor), 0));
214
g = std::min(255, std::max((int)(g * factor), 0));
215
b = std::min(255, std::max((int)(b * factor), 0));
216
217
return (color & 0xFF000000) | (b << 16) | (g << 8) | r;
218
}
219
220
std::string trimString(std::string input)
221
{
222
size_t pos = input.find_first_not_of(" \t");
223
if (pos != 0 && pos != std::string::npos)
224
{
225
input = input.erase(0,pos);
226
}
227
228
pos = input.find_last_not_of(" \t");
229
if (pos != std::string::npos)
230
{
231
size_t size = input.length()-pos-1;
232
input = input.erase(pos+1,size);
233
}
234
235
return input;
236
}
237
238
void CtrlDisAsmView::assembleOpcode(u32 address, const std::string &defaultText)
239
{
240
auto memLock = Memory::Lock();
241
if (!Core_IsStepping()) {
242
MessageBox(wnd,L"Cannot change code while the core is running!",L"Error",MB_OK);
243
return;
244
}
245
std::string op;
246
bool result = InputBox_GetString(MainWindow::GetHInstance(), wnd, L"Assemble opcode", defaultText, op, InputBoxFlags::Default);
247
if (!result) {
248
return;
249
}
250
251
// check if it changes registers first
252
auto separator = op.find('=');
253
if (separator != std::string::npos)
254
{
255
std::string registerName = trimString(op.substr(0,separator));
256
std::string expression = trimString(op.substr(separator+1));
257
258
u32 value;
259
if (parseExpression(expression.c_str(),debugger,value) == true)
260
{
261
for (int cat = 0; cat < debugger->GetNumCategories(); cat++)
262
{
263
for (int reg = 0; reg < debugger->GetNumRegsInCategory(cat); reg++)
264
{
265
if (strcasecmp(debugger->GetRegName(cat,reg).c_str(), registerName.c_str()) == 0)
266
{
267
debugger->SetRegValue(cat,reg,value);
268
Reporting::NotifyDebugger();
269
SendMessage(GetParent(wnd),WM_DEB_UPDATE,0,0);
270
return;
271
}
272
}
273
}
274
}
275
276
// try to assemble the input if it failed
277
}
278
279
std::string error;
280
result = MipsAssembleOpcode(op, debugger, address, &error);
281
Reporting::NotifyDebugger();
282
if (result) {
283
scanVisibleFunctions();
284
285
if (address == curAddress) {
286
gotoAddr(g_disassemblyManager.getNthNextAddress(curAddress, 1));
287
}
288
redraw();
289
} else {
290
std::wstring werror = ConvertUTF8ToWString(error.c_str());
291
MessageBox(wnd, werror.c_str(), L"Error", MB_OK);
292
}
293
}
294
295
void CtrlDisAsmView::drawBranchLine(HDC hdc, std::map<u32,int> &addressPositions, const BranchLine &line) {
296
HPEN pen;
297
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart,visibleRows);
298
299
int topY;
300
int bottomY;
301
if (line.first < windowStart) {
302
topY = -1;
303
} else if (line.first >= windowEnd) {
304
topY = rect.bottom+1;
305
} else {
306
topY = addressPositions[line.first] + rowHeight/2;
307
}
308
309
if (line.second < windowStart) {
310
bottomY = -1;
311
} else if (line.second >= windowEnd) {
312
bottomY = rect.bottom+1;
313
} else {
314
bottomY = addressPositions[line.second] + rowHeight/2;
315
}
316
317
if ((topY < 0 && bottomY < 0) || (topY > rect.bottom && bottomY > rect.bottom)) {
318
return;
319
}
320
321
// highlight line in a different color if it affects the currently selected opcode
322
if (line.first == curAddress || line.second == curAddress) {
323
pen = CreatePen(0,0,0x257AFA);
324
} else {
325
pen = CreatePen(0,0,0xFF3020);
326
}
327
328
HPEN oldPen = (HPEN) SelectObject(hdc,pen);
329
int x = pixelPositions.arrowsStart+line.laneIndex*8;
330
331
if (topY < 0) // first is not visible, but second is
332
{
333
MoveToEx(hdc,x-2,bottomY,0);
334
LineTo(hdc,x+2,bottomY);
335
LineTo(hdc,x+2,0);
336
337
if (line.type == LINE_DOWN)
338
{
339
MoveToEx(hdc,x,bottomY-4,0);
340
LineTo(hdc,x-4,bottomY);
341
LineTo(hdc,x+1,bottomY+5);
342
}
343
} else if (bottomY > rect.bottom) // second is not visible, but first is
344
{
345
MoveToEx(hdc,x-2,topY,0);
346
LineTo(hdc,x+2,topY);
347
LineTo(hdc,x+2,rect.bottom);
348
349
if (line.type == LINE_UP)
350
{
351
MoveToEx(hdc,x,topY-4,0);
352
LineTo(hdc,x-4,topY);
353
LineTo(hdc,x+1,topY+5);
354
}
355
} else { // both are visible
356
if (line.type == LINE_UP)
357
{
358
MoveToEx(hdc,x-2,bottomY,0);
359
LineTo(hdc,x+2,bottomY);
360
LineTo(hdc,x+2,topY);
361
LineTo(hdc,x-4,topY);
362
363
MoveToEx(hdc,x,topY-4,0);
364
LineTo(hdc,x-4,topY);
365
LineTo(hdc,x+1,topY+5);
366
} else {
367
MoveToEx(hdc,x-2,topY,0);
368
LineTo(hdc,x+2,topY);
369
LineTo(hdc,x+2,bottomY);
370
LineTo(hdc,x-4,bottomY);
371
372
MoveToEx(hdc,x,bottomY-4,0);
373
LineTo(hdc,x-4,bottomY);
374
LineTo(hdc,x+1,bottomY+5);
375
}
376
}
377
378
SelectObject(hdc,oldPen);
379
DeleteObject(pen);
380
}
381
382
std::set<std::string> CtrlDisAsmView::getSelectedLineArguments() {
383
std::set<std::string> args;
384
385
DisassemblyLineInfo line;
386
for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) {
387
g_disassemblyManager.getLine(addr, displaySymbols, line, debugger);
388
size_t p = 0, nextp = line.params.find(',');
389
while (nextp != line.params.npos) {
390
args.emplace(line.params.substr(p, nextp - p));
391
p = nextp + 1;
392
nextp = line.params.find(',', p);
393
}
394
if (p < line.params.size()) {
395
args.emplace(line.params.substr(p));
396
}
397
}
398
399
return args;
400
}
401
402
void CtrlDisAsmView::drawArguments(HDC hdc, const DisassemblyLineInfo &line, int x, int y, int textColor, const std::set<std::string> &currentArguments) {
403
if (line.params.empty()) {
404
return;
405
}
406
// Don't highlight the selected lines.
407
if (isInInterval(selectRangeStart, selectRangeEnd - selectRangeStart, line.info.opcodeAddress)) {
408
TextOutA(hdc, x, y, line.params.c_str(), (int)line.params.size());
409
return;
410
}
411
412
int highlightedColor = 0xaabb00;
413
if (textColor == 0x0000ff) {
414
highlightedColor = 0xaabb77;
415
}
416
417
UINT prevAlign = SetTextAlign(hdc, TA_UPDATECP);
418
MoveToEx(hdc, x, y, NULL);
419
420
size_t p = 0, nextp = line.params.find(',');
421
while (nextp != line.params.npos) {
422
const std::string arg = line.params.substr(p, nextp - p);
423
if (currentArguments.find(arg) != currentArguments.end() && textColor != 0xffffff) {
424
SetTextColor(hdc, highlightedColor);
425
}
426
TextOutA(hdc, 0, 0, arg.c_str(), (int)arg.size());
427
SetTextColor(hdc,textColor);
428
p = nextp + 1;
429
nextp = line.params.find(',', p);
430
TextOutA(hdc, 0, 0, ",", 1);
431
}
432
if (p < line.params.size()) {
433
const std::string arg = line.params.substr(p);
434
if (currentArguments.find(arg) != currentArguments.end() && textColor != 0xffffff) {
435
SetTextColor(hdc, highlightedColor);
436
}
437
TextOutA(hdc, 0, 0, arg.c_str(), (int)arg.size());
438
SetTextColor(hdc,textColor);
439
}
440
441
SetTextAlign(hdc, prevAlign);
442
}
443
444
void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam)
445
{
446
auto memLock = Memory::Lock();
447
if (!debugger->isAlive() || Achievements::HardcoreModeActive()) return;
448
449
PAINTSTRUCT ps;
450
HDC actualHdc = BeginPaint(wnd, &ps);
451
HDC hdc = CreateCompatibleDC(actualHdc);
452
HBITMAP hBM = CreateCompatibleBitmap(actualHdc, rect.right-rect.left, rect.bottom-rect.top);
453
SelectObject(hdc, hBM);
454
455
SetBkMode(hdc, TRANSPARENT);
456
457
HPEN nullPen=CreatePen(0,0,0xffffff);
458
HBRUSH nullBrush=CreateSolidBrush(0xffffff);
459
HBRUSH currentBrush=CreateSolidBrush(0xffefe8);
460
461
HPEN oldPen=(HPEN)SelectObject(hdc,nullPen);
462
HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,nullBrush);
463
HFONT oldFont = (HFONT)SelectObject(hdc,(HGDIOBJ)font);
464
HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCWSTR)IDI_STOP);
465
HICON breakPointDisable = (HICON)LoadIcon(GetModuleHandle(0),(LPCWSTR)IDI_STOPDISABLE);
466
467
unsigned int address = windowStart;
468
std::map<u32,int> addressPositions;
469
470
const std::set<std::string> currentArguments = getSelectedLineArguments();
471
DisassemblyLineInfo line;
472
for (int i = 0; i < visibleRows; i++)
473
{
474
g_disassemblyManager.getLine(address,displaySymbols,line, debugger);
475
476
int rowY1 = rowHeight*i;
477
int rowY2 = rowHeight*(i+1);
478
479
addressPositions[address] = rowY1;
480
481
// draw background
482
COLORREF backgroundColor = whiteBackground ? 0xFFFFFF : (debugger->getColor(address, false) & 0xFFFFFF);
483
COLORREF textColor = 0x000000;
484
485
if (isInInterval(address, line.totalSize, debugger->GetPC()))
486
{
487
backgroundColor = scaleColor(backgroundColor,1.05f);
488
}
489
490
if (address >= selectRangeStart && address < selectRangeEnd && searching == false)
491
{
492
if (hasFocus)
493
{
494
backgroundColor = address == curAddress ? 0xFF8822 : 0xFF9933;
495
textColor = 0xFFFFFF;
496
} else {
497
backgroundColor = 0xC0C0C0;
498
}
499
}
500
501
HBRUSH backgroundBrush = CreateSolidBrush(backgroundColor);
502
HPEN backgroundPen = CreatePen(0,0,backgroundColor);
503
SelectObject(hdc,backgroundBrush);
504
SelectObject(hdc,backgroundPen);
505
Rectangle(hdc,0,rowY1,rect.right,rowY1+rowHeight);
506
507
SelectObject(hdc,currentBrush);
508
SelectObject(hdc,nullPen);
509
510
DeleteObject(backgroundBrush);
511
DeleteObject(backgroundPen);
512
513
// display address/symbol
514
bool enabled;
515
if (g_breakpoints.IsAddressBreakPoint(address,&enabled))
516
{
517
if (enabled) textColor = 0x0000FF;
518
int yOffset = std::max(-1, (rowHeight - 14 + 1) / 2);
519
if (!enabled) yOffset++;
520
DrawIconEx(hdc,2,rowY1+1+yOffset,enabled ? breakPoint : breakPointDisable,32,32,0,0,DI_NORMAL);
521
}
522
SetTextColor(hdc,textColor);
523
524
char addressText[64];
525
GetDisasmAddressText(address, addressText, sizeof(addressText), true, line.type == DISTYPE_OPCODE, displaySymbols);
526
TextOutA(hdc, pixelPositions.addressStart, rowY1+2, addressText, (int)strlen(addressText));
527
528
if (isInInterval(address,line.totalSize,debugger->GetPC()))
529
{
530
TextOut(hdc,pixelPositions.opcodeStart-8,rowY1,L"\x25A0",1);
531
}
532
533
// display whether the condition of a branch is met
534
if (line.info.isConditional && address == debugger->GetPC())
535
{
536
line.params += line.info.conditionMet ? " ; true" : " ; false";
537
}
538
539
drawArguments(hdc, line, pixelPositions.argumentsStart, rowY1 + 2, textColor, currentArguments);
540
541
SelectObject(hdc,boldfont);
542
TextOutA(hdc,pixelPositions.opcodeStart,rowY1+2,line.name.c_str(),(int)line.name.size());
543
SelectObject(hdc,font);
544
545
address += line.totalSize;
546
}
547
548
std::vector<BranchLine> branchLines = g_disassemblyManager.getBranchLines(windowStart,address-windowStart);
549
for (size_t i = 0; i < branchLines.size(); i++)
550
{
551
drawBranchLine(hdc,addressPositions,branchLines[i]);
552
}
553
554
SelectObject(hdc,oldFont);
555
SelectObject(hdc,oldPen);
556
SelectObject(hdc,oldBrush);
557
558
// copy bitmap to the actual hdc
559
BitBlt(actualHdc, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);
560
DeleteObject(hBM);
561
DeleteDC(hdc);
562
563
DeleteObject(nullPen);
564
565
DeleteObject(nullBrush);
566
DeleteObject(currentBrush);
567
568
DestroyIcon(breakPoint);
569
DestroyIcon(breakPointDisable);
570
571
EndPaint(wnd, &ps);
572
}
573
574
575
576
void CtrlDisAsmView::onVScroll(WPARAM wParam, LPARAM lParam)
577
{
578
switch (wParam & 0xFFFF)
579
{
580
case SB_LINEDOWN:
581
windowStart = g_disassemblyManager.getNthNextAddress(windowStart,1);
582
break;
583
case SB_LINEUP:
584
windowStart = g_disassemblyManager.getNthPreviousAddress(windowStart,1);
585
break;
586
case SB_PAGEDOWN:
587
windowStart = g_disassemblyManager.getNthNextAddress(windowStart,visibleRows);
588
break;
589
case SB_PAGEUP:
590
windowStart = g_disassemblyManager.getNthPreviousAddress(windowStart,visibleRows);
591
break;
592
default:
593
return;
594
}
595
596
scanVisibleFunctions();
597
redraw();
598
}
599
600
void CtrlDisAsmView::followBranch()
601
{
602
DisassemblyLineInfo line;
603
g_disassemblyManager.getLine(curAddress, true, line, debugger);
604
605
if (line.type == DISTYPE_OPCODE || line.type == DISTYPE_MACRO)
606
{
607
if (line.info.isBranch)
608
{
609
jumpStack.push_back(curAddress);
610
gotoAddr(line.info.branchTarget);
611
} else if (line.info.hasRelevantAddress)
612
{
613
// well, not exactly a branch, but we can do something anyway
614
SendMessage(GetParent(wnd),WM_DEB_GOTOHEXEDIT,line.info.relevantAddress,0);
615
SetFocus(wnd);
616
}
617
} else if (line.type == DISTYPE_DATA)
618
{
619
// jump to the start of the current line
620
SendMessage(GetParent(wnd),WM_DEB_GOTOHEXEDIT,curAddress,0);
621
SetFocus(wnd);
622
}
623
}
624
625
void CtrlDisAsmView::onChar(WPARAM wParam, LPARAM lParam)
626
{
627
if (Achievements::HardcoreModeActive())
628
return;
629
630
if (keyTaken) return;
631
632
char str[2];
633
str[0] = wParam;
634
str[1] = 0;
635
assembleOpcode(curAddress,str);
636
}
637
638
639
void CtrlDisAsmView::editBreakpoint()
640
{
641
BreakpointWindow win(wnd,debugger);
642
643
bool exists = false;
644
if (g_breakpoints.IsAddressBreakPoint(curAddress))
645
{
646
auto breakpoints = g_breakpoints.GetBreakpoints();
647
for (size_t i = 0; i < breakpoints.size(); i++)
648
{
649
if (breakpoints[i].addr == curAddress)
650
{
651
win.loadFromBreakpoint(breakpoints[i]);
652
exists = true;
653
break;
654
}
655
}
656
}
657
658
if (!exists)
659
win.initBreakpoint(curAddress);
660
661
if (win.exec())
662
{
663
if (exists)
664
g_breakpoints.RemoveBreakPoint(curAddress);
665
win.addBreakpoint();
666
}
667
}
668
669
void CtrlDisAsmView::onKeyDown(WPARAM wParam, LPARAM lParam)
670
{
671
if (Achievements::HardcoreModeActive())
672
return;
673
674
dontRedraw = false;
675
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart,visibleRows);
676
keyTaken = true;
677
678
if (KeyDownAsync(VK_CONTROL))
679
{
680
switch (tolower(wParam & 0xFFFF))
681
{
682
case 'f':
683
case 's':
684
search(false);
685
break;
686
case 'c':
687
case VK_INSERT:
688
CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::DISASM);
689
break;
690
case 'x':
691
disassembleToFile();
692
break;
693
case 'a':
694
assembleOpcode(curAddress,"");
695
break;
696
case 'g':
697
{
698
u32 addr;
699
if (executeExpressionWindow(wnd,debugger,addr) == false) return;
700
gotoAddr(addr);
701
}
702
break;
703
case 'e': // edit breakpoint
704
editBreakpoint();
705
break;
706
case 'd': // toogle breakpoint enabled
707
toggleBreakpoint(true);
708
break;
709
case VK_UP:
710
scrollWindow(-1);
711
scanVisibleFunctions();
712
break;
713
case VK_DOWN:
714
scrollWindow(1);
715
scanVisibleFunctions();
716
break;
717
case VK_NEXT:
718
setCurAddress(g_disassemblyManager.getNthPreviousAddress(windowEnd,1),KeyDownAsync(VK_SHIFT));
719
break;
720
case VK_PRIOR:
721
setCurAddress(windowStart,KeyDownAsync(VK_SHIFT));
722
break;
723
}
724
} else {
725
switch (wParam & 0xFFFF)
726
{
727
case VK_DOWN:
728
setCurAddress(g_disassemblyManager.getNthNextAddress(curAddress,1), KeyDownAsync(VK_SHIFT));
729
scrollAddressIntoView();
730
break;
731
case VK_UP:
732
setCurAddress(g_disassemblyManager.getNthPreviousAddress(curAddress,1), KeyDownAsync(VK_SHIFT));
733
scrollAddressIntoView();
734
break;
735
case VK_NEXT:
736
if (g_disassemblyManager.getNthNextAddress(curAddress,1) != windowEnd && curAddressIsVisible()) {
737
setCurAddress(g_disassemblyManager.getNthPreviousAddress(windowEnd,1), KeyDownAsync(VK_SHIFT));
738
scrollAddressIntoView();
739
} else {
740
setCurAddress(g_disassemblyManager.getNthNextAddress(windowEnd,visibleRows-1), KeyDownAsync(VK_SHIFT));
741
scrollAddressIntoView();
742
}
743
break;
744
case VK_PRIOR:
745
if (curAddress != windowStart && curAddressIsVisible()) {
746
setCurAddress(windowStart, KeyDownAsync(VK_SHIFT));
747
scrollAddressIntoView();
748
} else {
749
setCurAddress(g_disassemblyManager.getNthPreviousAddress(windowStart,visibleRows), KeyDownAsync(VK_SHIFT));
750
scrollAddressIntoView();
751
}
752
break;
753
case VK_LEFT:
754
if (jumpStack.empty())
755
{
756
gotoPC();
757
} else {
758
u32 addr = jumpStack[jumpStack.size()-1];
759
jumpStack.pop_back();
760
gotoAddr(addr);
761
}
762
return;
763
case VK_RIGHT:
764
followBranch();
765
return;
766
case VK_TAB:
767
displaySymbols = !displaySymbols;
768
break;
769
case VK_SPACE:
770
debugger->toggleBreakpoint(curAddress);
771
break;
772
case VK_F3:
773
search(true);
774
break;
775
default:
776
keyTaken = false;
777
return;
778
}
779
}
780
redraw();
781
}
782
783
void CtrlDisAsmView::onKeyUp(WPARAM wParam, LPARAM lParam)
784
{
785
786
}
787
788
void CtrlDisAsmView::scrollAddressIntoView()
789
{
790
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart,visibleRows);
791
792
if (curAddress < windowStart)
793
windowStart = curAddress;
794
else if (curAddress >= windowEnd)
795
windowStart = g_disassemblyManager.getNthPreviousAddress(curAddress,visibleRows-1);
796
797
scanVisibleFunctions();
798
}
799
800
bool CtrlDisAsmView::curAddressIsVisible()
801
{
802
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart,visibleRows);
803
return curAddress >= windowStart && curAddress < windowEnd;
804
}
805
806
void CtrlDisAsmView::redraw()
807
{
808
if (dontRedraw == true) return;
809
810
GetClientRect(wnd, &rect);
811
visibleRows = rect.bottom/rowHeight;
812
813
if (!redrawScheduled_) {
814
SetTimer(wnd, IDT_REDRAW, REDRAW_DELAY, nullptr);
815
redrawScheduled_ = true;
816
}
817
}
818
819
void CtrlDisAsmView::toggleBreakpoint(bool toggleEnabled)
820
{
821
bool enabled;
822
if (g_breakpoints.IsAddressBreakPoint(curAddress, &enabled)) {
823
if (!enabled) {
824
// enable disabled breakpoints
825
g_breakpoints.ChangeBreakPoint(curAddress, true);
826
} else if (!toggleEnabled && g_breakpoints.GetBreakPointCondition(curAddress) != nullptr) {
827
// don't just delete a breakpoint with a custom condition
828
int ret = MessageBox(wnd,L"This breakpoint has a custom condition.\nDo you want to remove it?",L"Confirmation",MB_YESNO);
829
if (ret == IDYES)
830
g_breakpoints.RemoveBreakPoint(curAddress);
831
} else if (toggleEnabled) {
832
// disable breakpoint
833
g_breakpoints.ChangeBreakPoint(curAddress, false);
834
} else {
835
// otherwise just remove breakpoint
836
g_breakpoints.RemoveBreakPoint(curAddress);
837
}
838
} else {
839
g_breakpoints.AddBreakPoint(curAddress);
840
}
841
}
842
843
void CtrlDisAsmView::onMouseDown(WPARAM wParam, LPARAM lParam, int button)
844
{
845
if (Achievements::HardcoreModeActive())
846
return;
847
dontRedraw = false;
848
int y = HIWORD(lParam);
849
850
u32 newAddress = yToAddress(y);
851
bool extend = KeyDownAsync(VK_SHIFT);
852
if (button == 1)
853
{
854
if (newAddress == curAddress && hasFocus)
855
{
856
toggleBreakpoint();
857
}
858
}
859
else if (button == 2)
860
{
861
// Maintain the current selection if right clicking into it.
862
if (newAddress >= selectRangeStart && newAddress < selectRangeEnd)
863
extend = true;
864
}
865
setCurAddress(newAddress, extend);
866
867
SetFocus(wnd);
868
redraw();
869
}
870
871
void CtrlDisAsmView::CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode) {
872
_assert_msg_((startAddr & 3) == 0, "readMemory() can't handle unaligned reads");
873
874
if (mode != CopyInstructionsMode::DISASM) {
875
int instructionSize = debugger->getInstructionSize(0);
876
int count = (endAddr - startAddr) / instructionSize;
877
int space = count * 32;
878
char *temp = new char[space];
879
880
char *p = temp, *end = temp + space;
881
for (u32 pos = startAddr; pos < endAddr && p < end; pos += instructionSize)
882
{
883
u32 data = mode == CopyInstructionsMode::OPCODES ? debugger->readMemory(pos) : pos;
884
p += snprintf(p, end - p, "%08X", data);
885
886
// Don't leave a trailing newline.
887
if (pos + instructionSize < endAddr && p < end)
888
p += snprintf(p, end - p, "\r\n");
889
}
890
W32Util::CopyTextToClipboard(wnd, temp);
891
delete [] temp;
892
} else {
893
std::string disassembly = DisassembleRange(startAddr,endAddr-startAddr, displaySymbols, debugger);
894
W32Util::CopyTextToClipboard(wnd, disassembly.c_str());
895
}
896
}
897
898
void CtrlDisAsmView::NopInstructions(u32 selectRangeStart, u32 selectRangeEnd) {
899
for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) {
900
Memory::Write_U32(0, addr);
901
}
902
903
if (currentMIPS) {
904
currentMIPS->InvalidateICache(selectRangeStart, selectRangeEnd - selectRangeStart);
905
}
906
}
907
908
void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button)
909
{
910
if (Achievements::HardcoreModeActive())
911
return;
912
913
if (button == 1)
914
{
915
int y = HIWORD(lParam);
916
setCurAddress(yToAddress(y), KeyDownAsync(VK_SHIFT));
917
redraw();
918
}
919
else if (button == 2)
920
{
921
// We don't want to let the users play with deallocated or uninitialized debugging objects
922
GlobalUIState state = GetUIState();
923
if (state != UISTATE_INGAME && state != UISTATE_PAUSEMENU) {
924
return;
925
}
926
927
switch (TriggerContextMenu(ContextMenuID::DISASM, wnd, ContextPoint::FromEvent(lParam)))
928
{
929
case ID_DISASM_GOTOINMEMORYVIEW:
930
SendMessage(GetParent(wnd),WM_DEB_GOTOHEXEDIT,curAddress,0);
931
break;
932
case ID_DISASM_TOGGLEBREAKPOINT:
933
toggleBreakpoint();
934
redraw();
935
break;
936
case ID_DISASM_ASSEMBLE:
937
assembleOpcode(curAddress,"");
938
break;
939
case ID_DISASM_COPYINSTRUCTIONDISASM:
940
CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::DISASM);
941
break;
942
case ID_DISASM_COPYADDRESS:
943
CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::ADDRESSES);
944
break;
945
case ID_DISASM_COPYINSTRUCTIONHEX:
946
CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::OPCODES);
947
break;
948
case ID_DISASM_NOPINSTRUCTION:
949
NopInstructions(selectRangeStart, selectRangeEnd);
950
redraw();
951
break;
952
case ID_DISASM_EDITSYMBOLS:
953
{
954
EditSymbolsWindow esw(wnd, debugger);
955
if (esw.exec()) {
956
esw.eval();
957
SendMessage(GetParent(wnd), WM_DEB_MAPLOADED, 0, 0);
958
redraw();
959
}
960
}
961
break;
962
case ID_DISASM_SETPCTOHERE:
963
debugger->SetPC(curAddress);
964
redraw();
965
break;
966
case ID_DISASM_FOLLOWBRANCH:
967
followBranch();
968
break;
969
case ID_DISASM_RUNTOHERE:
970
{
971
SendMessage(GetParent(wnd), WM_COMMAND, ID_DEBUG_RUNTOLINE, 0);
972
redraw();
973
}
974
break;
975
case ID_DISASM_RENAMEFUNCTION:
976
{
977
u32 funcBegin = g_symbolMap->GetFunctionStart(curAddress);
978
if (funcBegin != -1)
979
{
980
char name[256];
981
std::string newname;
982
truncate_cpy(name, g_symbolMap->GetLabelString(funcBegin));
983
if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), L"New function name", name, newname)) {
984
g_symbolMap->SetLabelName(newname.c_str(), funcBegin);
985
u32 funcSize = g_symbolMap->GetFunctionSize(funcBegin);
986
MIPSAnalyst::RegisterFunction(funcBegin, funcSize, newname.c_str());
987
MIPSAnalyst::UpdateHashMap();
988
MIPSAnalyst::ApplyHashMap();
989
SendMessage(GetParent(wnd),WM_DEB_MAPLOADED,0,0);
990
redraw();
991
}
992
}
993
else
994
{
995
MessageBox(MainWindow::GetHWND(), L"No symbol selected",0,0);
996
}
997
}
998
break;
999
case ID_DISASM_REMOVEFUNCTION:
1000
{
1001
char statusBarTextBuff[256];
1002
u32 funcBegin = g_symbolMap->GetFunctionStart(curAddress);
1003
if (funcBegin != -1)
1004
{
1005
u32 prevBegin = g_symbolMap->GetFunctionStart(funcBegin-1);
1006
if (prevBegin != -1)
1007
{
1008
u32 expandedSize = g_symbolMap->GetFunctionSize(prevBegin) + g_symbolMap->GetFunctionSize(funcBegin);
1009
g_symbolMap->SetFunctionSize(prevBegin,expandedSize);
1010
}
1011
1012
g_symbolMap->RemoveFunction(funcBegin,true);
1013
g_symbolMap->SortSymbols();
1014
g_disassemblyManager.clear();
1015
1016
SendMessage(GetParent(wnd), WM_DEB_MAPLOADED, 0, 0);
1017
}
1018
else
1019
{
1020
snprintf(statusBarTextBuff,256, "WARNING: unable to find function symbol here");
1021
SendMessage(GetParent(wnd), WM_DEB_SETSTATUSBARTEXT, 0, (LPARAM) statusBarTextBuff);
1022
}
1023
redraw();
1024
}
1025
break;
1026
case ID_DISASM_ADDFUNCTION:
1027
{
1028
char statusBarTextBuff[256];
1029
u32 prevBegin = g_symbolMap->GetFunctionStart(curAddress);
1030
if (prevBegin != -1)
1031
{
1032
if (prevBegin == curAddress)
1033
{
1034
snprintf(statusBarTextBuff,256, "WARNING: There's already a function entry point at this adress");
1035
SendMessage(GetParent(wnd), WM_DEB_SETSTATUSBARTEXT, 0, (LPARAM) statusBarTextBuff);
1036
}
1037
else
1038
{
1039
char symname[128];
1040
u32 prevSize = g_symbolMap->GetFunctionSize(prevBegin);
1041
u32 newSize = curAddress-prevBegin;
1042
g_symbolMap->SetFunctionSize(prevBegin,newSize);
1043
1044
newSize = prevSize-newSize;
1045
snprintf(symname,128,"u_un_%08X",curAddress);
1046
g_symbolMap->AddFunction(symname,curAddress,newSize);
1047
g_symbolMap->SortSymbols();
1048
g_disassemblyManager.clear();
1049
1050
SendMessage(GetParent(wnd), WM_DEB_MAPLOADED, 0, 0);
1051
}
1052
}
1053
else
1054
{
1055
char symname[128];
1056
int newSize = selectRangeEnd - selectRangeStart;
1057
snprintf(symname, 128, "u_un_%08X", selectRangeStart);
1058
g_symbolMap->AddFunction(symname, selectRangeStart, newSize);
1059
g_symbolMap->SortSymbols();
1060
1061
SendMessage(GetParent(wnd), WM_DEB_MAPLOADED, 0, 0);
1062
}
1063
redraw();
1064
}
1065
break;
1066
case ID_DISASM_DISASSEMBLETOFILE:
1067
disassembleToFile();
1068
break;
1069
}
1070
return;
1071
}
1072
1073
redraw();
1074
}
1075
1076
void CtrlDisAsmView::onMouseMove(WPARAM wParam, LPARAM lParam, int button)
1077
{
1078
if (Achievements::HardcoreModeActive())
1079
return;
1080
1081
if ((button & 1) != 0)
1082
{
1083
int y = HIWORD(lParam);
1084
setCurAddress(yToAddress(y), KeyDownAsync(VK_SHIFT));
1085
redraw();
1086
}
1087
}
1088
1089
void CtrlDisAsmView::updateStatusBarText()
1090
{
1091
auto memLock = Memory::Lock();
1092
if (!PSP_IsInited())
1093
return;
1094
1095
char text[512];
1096
DisassemblyLineInfo line;
1097
g_disassemblyManager.getLine(curAddress,true,line, debugger);
1098
1099
text[0] = 0;
1100
if (line.type == DISTYPE_OPCODE || line.type == DISTYPE_MACRO)
1101
{
1102
if (line.info.hasRelevantAddress && IsLikelyStringAt(line.info.relevantAddress)) {
1103
snprintf(text, sizeof(text), "[%08X] = \"%s\"", line.info.relevantAddress, Memory::GetCharPointer(line.info.relevantAddress));
1104
}
1105
1106
if (line.info.isDataAccess) {
1107
if (!Memory::IsValidAddress(line.info.dataAddress)) {
1108
snprintf(text, sizeof(text), "Invalid address %08X",line.info.dataAddress);
1109
} else {
1110
bool isFloat = MIPSGetInfo(line.info.encodedOpcode) & (IS_FPU | IS_VFPU);
1111
switch (line.info.dataSize) {
1112
case 1:
1113
snprintf(text, sizeof(text), "[%08X] = %02X",line.info.dataAddress,Memory::Read_U8(line.info.dataAddress));
1114
break;
1115
case 2:
1116
snprintf(text, sizeof(text), "[%08X] = %04X",line.info.dataAddress,Memory::Read_U16(line.info.dataAddress));
1117
break;
1118
case 4:
1119
{
1120
u32 dataInt = Memory::Read_U32(line.info.dataAddress);
1121
u32 dataFloat = Memory::Read_Float(line.info.dataAddress);
1122
std::string dataString;
1123
if (isFloat)
1124
dataString = StringFromFormat("%08X / %f", dataInt, dataFloat);
1125
else
1126
dataString = StringFromFormat("%08X", dataInt);
1127
1128
const std::string addressSymbol = g_symbolMap->GetLabelString(dataInt);
1129
if (!addressSymbol.empty()) {
1130
snprintf(text, sizeof(text), "[%08X] = %s (%s)", line.info.dataAddress, addressSymbol.c_str(), dataString.c_str());
1131
} else {
1132
snprintf(text, sizeof(text), "[%08X] = %s", line.info.dataAddress, dataString.c_str());
1133
}
1134
break;
1135
}
1136
case 16:
1137
{
1138
uint32_t dataInt[4];
1139
float dataFloat[4];
1140
for (int i = 0; i < 4; ++i) {
1141
dataInt[i] = Memory::Read_U32(line.info.dataAddress + i * 4);
1142
dataFloat[i] = Memory::Read_Float(line.info.dataAddress + i * 4);
1143
}
1144
std::string dataIntString = StringFromFormat("%08X,%08X,%08X,%08X", dataInt[0], dataInt[1], dataInt[2], dataInt[3]);
1145
std::string dataFloatString = StringFromFormat("%f,%f,%f,%f", dataFloat[0], dataFloat[1], dataFloat[2], dataFloat[3]);
1146
1147
snprintf(text, sizeof(text), "[%08X] = %s / %s", line.info.dataAddress, dataIntString.c_str(), dataFloatString.c_str());
1148
break;
1149
}
1150
}
1151
}
1152
}
1153
1154
if (line.info.isBranch)
1155
{
1156
const std::string addressSymbol = g_symbolMap->GetLabelString(line.info.branchTarget);
1157
if (addressSymbol.empty())
1158
{
1159
snprintf(text, sizeof(text), "%08X", line.info.branchTarget);
1160
} else {
1161
snprintf(text, sizeof(text), "%08X = %s",line.info.branchTarget,addressSymbol.c_str());
1162
}
1163
}
1164
} else if (line.type == DISTYPE_DATA) {
1165
u32 start = g_symbolMap->GetDataStart(curAddress);
1166
if (start == -1)
1167
start = curAddress;
1168
1169
u32 diff = curAddress-start;
1170
const std::string label = g_symbolMap->GetLabelString(start);
1171
1172
if (!label.empty()) {
1173
if (diff != 0)
1174
snprintf(text, sizeof(text), "%08X (%s) + %08X",start,label.c_str(),diff);
1175
else
1176
snprintf(text, sizeof(text), "%08X (%s)",start,label.c_str());
1177
} else {
1178
if (diff != 0)
1179
snprintf(text, sizeof(text), "%08X + %08X",start,diff);
1180
else
1181
snprintf(text, sizeof(text), "%08X",start);
1182
}
1183
}
1184
1185
SendMessage(GetParent(wnd),WM_DEB_SETSTATUSBARTEXT,0,(LPARAM)text);
1186
1187
const std::string label = g_symbolMap->GetLabelString(line.info.opcodeAddress);
1188
if (!label.empty()) {
1189
SendMessage(GetParent(wnd),WM_DEB_SETSTATUSBARTEXT,1,(LPARAM)label.c_str());
1190
}
1191
}
1192
1193
u32 CtrlDisAsmView::yToAddress(int y)
1194
{
1195
int line = y/rowHeight;
1196
return g_disassemblyManager.getNthNextAddress(windowStart,line);
1197
}
1198
1199
void CtrlDisAsmView::calculatePixelPositions()
1200
{
1201
pixelPositions.addressStart = 16;
1202
pixelPositions.opcodeStart = pixelPositions.addressStart + 18*charWidth;
1203
pixelPositions.argumentsStart = pixelPositions.opcodeStart + 9*charWidth;
1204
pixelPositions.arrowsStart = pixelPositions.argumentsStart + 30*charWidth;
1205
}
1206
1207
void CtrlDisAsmView::search(bool continueSearch)
1208
{
1209
auto memLock = Memory::Lock();
1210
u32 searchAddress;
1211
1212
if (continueSearch == false || searchQuery[0] == 0)
1213
{
1214
if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), L"Search for:", searchQuery, searchQuery) == false
1215
|| searchQuery[0] == 0)
1216
{
1217
SetFocus(wnd);
1218
return;
1219
}
1220
1221
for (size_t i = 0; i < searchQuery.size(); i++)
1222
{
1223
searchQuery[i] = tolower(searchQuery[i]);
1224
}
1225
SetFocus(wnd);
1226
searchAddress = g_disassemblyManager.getNthNextAddress(curAddress,1);
1227
} else {
1228
searchAddress = g_disassemblyManager.getNthNextAddress(matchAddress,1);
1229
}
1230
1231
// limit address to sensible ranges
1232
if (searchAddress < 0x04000000) searchAddress = 0x04000000;
1233
if (searchAddress >= 0x04200000 && searchAddress < 0x08000000) searchAddress = 0x08000000;
1234
if (searchAddress >= 0x0A000000) {
1235
MessageBox(wnd,L"Not found",L"Search",MB_OK);
1236
return;
1237
}
1238
1239
searching = true;
1240
redraw(); // so the cursor is disabled
1241
1242
DisassemblyLineInfo lineInfo;
1243
while (searchAddress < 0x0A000000)
1244
{
1245
g_disassemblyManager.getLine(searchAddress,displaySymbols,lineInfo, debugger);
1246
1247
char addressText[64];
1248
GetDisasmAddressText(searchAddress, addressText, sizeof(addressText), true, lineInfo.type == DISTYPE_OPCODE, displaySymbols);
1249
1250
const char* opcode = lineInfo.name.c_str();
1251
const char* arguments = lineInfo.params.c_str();
1252
1253
char merged[512];
1254
int mergePos = 0;
1255
1256
// I'm doing it manually to convert everything to lowercase at the same time
1257
for (int i = 0; addressText[i] != 0; i++) merged[mergePos++] = tolower(addressText[i]);
1258
merged[mergePos++] = ' ';
1259
for (int i = 0; opcode[i] != 0; i++) merged[mergePos++] = tolower(opcode[i]);
1260
merged[mergePos++] = ' ';
1261
for (int i = 0; arguments[i] != 0; i++) merged[mergePos++] = tolower(arguments[i]);
1262
merged[mergePos] = 0;
1263
1264
// match!
1265
if (strstr(merged, searchQuery.c_str()) != NULL)
1266
{
1267
matchAddress = searchAddress;
1268
searching = false;
1269
gotoAddr(searchAddress);
1270
return;
1271
}
1272
1273
// cancel search
1274
if ((searchAddress % 256) == 0 && KeyDownAsync(VK_ESCAPE))
1275
{
1276
searching = false;
1277
return;
1278
}
1279
1280
searchAddress = g_disassemblyManager.getNthNextAddress(searchAddress,1);
1281
if (searchAddress >= 0x04200000 && searchAddress < 0x08000000) searchAddress = 0x08000000;
1282
}
1283
1284
MessageBox(wnd,L"Not found",L"Search",MB_OK);
1285
searching = false;
1286
}
1287
1288
void CtrlDisAsmView::disassembleToFile() {
1289
// get size
1290
u32 size;
1291
if (executeExpressionWindow(wnd,debugger,size) == false)
1292
return;
1293
if (size == 0 || size > 10*1024*1024) {
1294
MessageBox(wnd,L"Invalid size!",L"Error",MB_OK);
1295
return;
1296
}
1297
1298
std::string filename;
1299
if (W32Util::BrowseForFileName(false, nullptr, L"Save Disassembly As...", nullptr, L"All Files\0*.*\0\0", nullptr, filename)) {
1300
std::wstring fileName = ConvertUTF8ToWString(filename);
1301
FILE *output = _wfopen(fileName.c_str(), L"wb");
1302
if (output == nullptr) {
1303
MessageBox(wnd, L"Could not open file!", L"Error", MB_OK);
1304
return;
1305
}
1306
1307
std::string disassembly = DisassembleRange(curAddress, size, displaySymbols, debugger);
1308
fprintf(output, "%s", disassembly.c_str());
1309
1310
fclose(output);
1311
MessageBox(wnd, L"Finished!", L"Done", MB_OK);
1312
}
1313
}
1314
1315
void CtrlDisAsmView::getOpcodeText(u32 address, char* dest, int bufsize)
1316
{
1317
DisassemblyLineInfo line;
1318
address = g_disassemblyManager.getStartAddress(address);
1319
g_disassemblyManager.getLine(address,displaySymbols,line, debugger);
1320
snprintf(dest, bufsize, "%s %s",line.name.c_str(),line.params.c_str());
1321
}
1322
1323
void CtrlDisAsmView::scrollStepping(u32 newPc)
1324
{
1325
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart,visibleRows);
1326
1327
newPc = g_disassemblyManager.getStartAddress(newPc);
1328
if (newPc >= windowEnd || newPc >= g_disassemblyManager.getNthPreviousAddress(windowEnd,1))
1329
{
1330
windowStart = g_disassemblyManager.getNthPreviousAddress(newPc,visibleRows-2);
1331
}
1332
}
1333
1334
u32 CtrlDisAsmView::getInstructionSizeAt(u32 address)
1335
{
1336
u32 start = g_disassemblyManager.getStartAddress(address);
1337
u32 next = g_disassemblyManager.getNthNextAddress(start,1);
1338
return next - address;
1339
}
1340
1341