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