Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UI/ImDebugger/ImDisasmView.cpp
4779 views
1
#include "ext/imgui/imgui_internal.h"
2
#include "ext/imgui/imgui_extras.h"
3
#include "ext/imgui/imgui_impl_thin3d.h"
4
5
#include "Common/StringUtils.h"
6
#include "Common/Log.h"
7
#include "Common/Math/geom2d.h"
8
#include "Core/Core.h"
9
#include "Core/HLE/HLE.h"
10
#include "Core/Debugger/DebugInterface.h"
11
#include "Core/Debugger/DisassemblyManager.h"
12
#include "Core/Debugger/Breakpoints.h"
13
#include "Core/MIPS/MIPSDebugInterface.h"
14
#include "Core/MIPS/MIPSTables.h"
15
#include "Core/Debugger/SymbolMap.h"
16
#include "Core/MemMap.h"
17
#include "Common/System/Request.h"
18
19
#include "Core/System.h"
20
#include "UI/ImDebugger/ImDisasmView.h"
21
#include "UI/ImDebugger/ImDebugger.h"
22
23
ImDisasmView::ImDisasmView() {
24
curAddress_ = 0;
25
showHex_ = false;
26
hasFocus_ = false;
27
keyTaken = false;
28
29
matchAddress_ = -1;
30
searching_ = false;
31
searchQuery_.clear();
32
windowStart_ = curAddress_;
33
displaySymbols_ = true;
34
}
35
36
ImDisasmView::~ImDisasmView() {
37
g_disassemblyManager.clear();
38
}
39
40
void ImDisasmView::ScanVisibleFunctions() {
41
g_disassemblyManager.analyze(windowStart_, g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_) - windowStart_);
42
}
43
44
static ImColor scaleColor(ImColor color, float factor) {
45
if (factor <= 0.0f) {
46
return color;
47
}
48
color.Value.x = std::min(color.Value.x * factor, 1.0f);
49
color.Value.y = std::min(color.Value.y * factor, 1.0f);
50
color.Value.z = std::min(color.Value.z * factor, 1.0f);
51
return color;
52
}
53
54
bool ImDisasmView::getDisasmAddressText(u32 address, char *dest, size_t bufSize, bool abbreviateLabels, bool showData) {
55
if (PSP_GetBootState() != BootState::Complete) {
56
dest[0] = '\0';
57
return false;
58
}
59
60
return GetDisasmAddressText(address, dest, bufSize, abbreviateLabels, showData, displaySymbols_);
61
}
62
63
void ImDisasmView::assembleOpcode(u32 address, const std::string &defaultText) {
64
/*
65
if (!Core_IsStepping()) {
66
MessageBox(wnd, L"Cannot change code while the core is running!", L"Error", MB_OK);
67
return;
68
}
69
std::string op;
70
bool result = InputBox_GetString(MainWindow::GetHInstance(), wnd, L"Assemble opcode", defaultText, op, InputBoxFlags::Default);
71
if (!result) {
72
return;
73
}
74
75
// check if it changes registers first
76
auto separator = op.find('=');
77
if (separator != std::string::npos)
78
{
79
std::string registerName = trimString(op.substr(0, separator));
80
std::string expression = trimString(op.substr(separator + 1));
81
82
u32 value;
83
if (parseExpression(expression.c_str(), debugger, value) == true)
84
{
85
for (int cat = 0; cat < debugger->GetNumCategories(); cat++)
86
{
87
for (int reg = 0; reg < debugger->GetNumRegsInCategory(cat); reg++)
88
{
89
if (strcasecmp(debugger->GetRegName(cat, reg).c_str(), registerName.c_str()) == 0)
90
{
91
debugger->SetRegValue(cat, reg, value);
92
Reporting::NotifyDebugger();
93
SendMessage(GetParent(wnd), WM_DEB_UPDATE, 0, 0);
94
return;
95
}
96
}
97
}
98
}
99
100
// try to assemble the input if it failed
101
}
102
103
result = MIPSAsm::MipsAssembleOpcode(op, debugger, address);
104
Reporting::NotifyDebugger();
105
if (result == true)
106
{
107
ScanVisibleFunctions();
108
109
if (address == curAddress)
110
gotoAddr(g_disassemblyManager.getNthNextAddress(curAddress, 1));
111
112
redraw();
113
} else {
114
std::wstring error = ConvertUTF8ToWString(MIPSAsm::GetAssembleError());
115
MessageBox(wnd, error.c_str(), L"Error", MB_OK);
116
}
117
*/
118
}
119
120
void ImDisasmView::drawBranchLine(ImDrawList *drawList, Bounds rect, std::map<u32, float> &addressPositions, const BranchLine &line) {
121
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_);
122
123
float topY;
124
float bottomY;
125
if (line.first < windowStart_) {
126
topY = -1;
127
} else if (line.first >= windowEnd) {
128
topY = rect.y2() + 1.0f;
129
} else {
130
topY = (float)addressPositions[line.first] + rowHeight_ / 2;
131
}
132
133
if (line.second < windowStart_) {
134
bottomY = -1;
135
} else if (line.second >= windowEnd) {
136
bottomY = rect.y2() + 1.0f;
137
} else {
138
bottomY = (float)addressPositions[line.second] + rowHeight_ / 2;
139
}
140
141
if ((topY < 0 && bottomY < 0) || (topY > rect.y2() && bottomY > rect.y2())) {
142
return;
143
}
144
145
ImColor pen;
146
147
// highlight line in a different color if it affects the currently selected opcode
148
// TODO: Color line differently if forward or backward too!
149
if (line.first == curAddress_ || line.second == curAddress_) {
150
pen = ImColor(0xFF257AFA);
151
} else {
152
pen = ImColor(0xFFFF3020);
153
}
154
155
float x = (float)pixelPositions_.arrowsStart + (float)line.laneIndex * 8.0f;
156
157
float curX, curY;
158
auto moveTo = [&](float x, float y) {
159
curX = x;
160
curY = y;
161
};
162
auto lineTo = [&](float x, float y) {
163
drawList->AddLine(ImVec2(rect.x + curX, rect.y + curY), ImVec2(rect.x + (float)x, rect.y + (float)y), pen, 1.0f);
164
curX = x;
165
curY = y;
166
};
167
168
if (topY < 0) { // first is not visible, but second is
169
moveTo(x - 2.f, bottomY);
170
lineTo(x + 2.f, bottomY);
171
lineTo(x + 2.f, 0.0f);
172
173
if (line.type == LINE_DOWN) {
174
moveTo(x, bottomY - 4.f);
175
lineTo(x - 4.f, bottomY);
176
lineTo(x + 1.f, bottomY + 5.f);
177
}
178
} else if (bottomY > rect.y2()) {// second is not visible, but first is
179
moveTo(x - 2.f, topY);
180
lineTo(x + 2.f, topY);
181
lineTo(x + 2.f, rect.y2());
182
183
if (line.type == LINE_UP) {
184
moveTo(x, topY - 4.f);
185
lineTo(x - 4.f, topY);
186
lineTo(x + 1.f, topY + 5.f);
187
}
188
} else { // both are visible
189
if (line.type == LINE_UP) {
190
moveTo(x - 2.f, bottomY);
191
lineTo(x + 2.f, bottomY);
192
lineTo(x + 2.f, topY);
193
lineTo(x - 4.f, topY);
194
195
moveTo(x, topY - 4.f);
196
lineTo(x - 4.f, topY);
197
lineTo(x + 1.f, topY + 5.f);
198
} else {
199
moveTo(x - 2.f, topY);
200
lineTo(x + 2.f, topY);
201
lineTo(x + 2.f, bottomY);
202
lineTo(x - 4.f, bottomY);
203
204
moveTo(x, bottomY - 4.f);
205
lineTo(x - 4.f, bottomY);
206
lineTo(x + 1.f, bottomY + 5.f);
207
}
208
}
209
}
210
211
std::set<std::string> ImDisasmView::getSelectedLineArguments() {
212
std::set<std::string> args;
213
DisassemblyLineInfo line;
214
for (u32 addr = selectRangeStart_; addr < selectRangeEnd_; addr += 4) {
215
g_disassemblyManager.getLine(addr, displaySymbols_, line, debugger_);
216
size_t p = 0, nextp = line.params.find(',');
217
while (nextp != line.params.npos) {
218
args.emplace(line.params.substr(p, nextp - p));
219
p = nextp + 1;
220
nextp = line.params.find(',', p);
221
}
222
if (p < line.params.size()) {
223
args.emplace(line.params.substr(p));
224
}
225
}
226
return args;
227
}
228
229
void ImDisasmView::drawArguments(ImDrawList *drawList, Bounds rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> &currentArguments) {
230
if (line.params.empty()) {
231
return;
232
}
233
// Don't highlight the selected lines.
234
if (isInInterval(selectRangeStart_, selectRangeEnd_ - selectRangeStart_, line.info.opcodeAddress)) {
235
drawList->AddText(ImVec2((float)(rc.x + x), (float)(rc.y + y)), textColor, line.params.data(), line.params.data() + line.params.size());
236
return;
237
}
238
239
ImColor highlightedColor(0xFFaabb00);
240
if (textColor == 0xFF0000ff) {
241
highlightedColor = ImColor(0xFFaabb77);
242
}
243
244
float curX = (float)x, curY = (float)y;
245
246
ImColor curColor = textColor;
247
248
auto Print = [&](std::string_view text) {
249
drawList->AddText(ImVec2(rc.x + curX, rc.y + curY), curColor, text.data(), text.data() + text.size());
250
ImVec2 sz = ImGui::CalcTextSize(text.data(), text.data() + text.size(), false, -1.0f);
251
curX += sz.x;
252
};
253
254
size_t p = 0, nextp = line.params.find(',');
255
while (nextp != line.params.npos) {
256
const std::string arg = line.params.substr(p, nextp - p);
257
if (currentArguments.find(arg) != currentArguments.end() && textColor != 0xffffff) {
258
curColor = highlightedColor;
259
}
260
Print(arg);
261
curColor = textColor;
262
p = nextp + 1;
263
nextp = line.params.find(',', p);
264
Print(",");
265
}
266
if (p < line.params.size()) {
267
const std::string arg = line.params.substr(p);
268
if (currentArguments.find(arg) != currentArguments.end() && textColor != 0xffffff) {
269
curColor = highlightedColor;
270
}
271
Print(arg);
272
curColor = textColor;
273
}
274
}
275
276
void ImDisasmView::Draw(ImDrawList *drawList, ImControl &control) {
277
if (!debugger_->isAlive()) {
278
return;
279
}
280
281
// TODO: Don't need to do these every frame.
282
ImGui_PushFixedFont();
283
284
rowHeight_ = ImGui::GetTextLineHeightWithSpacing();
285
charWidth_ = ImGui::CalcTextSize("W", nullptr, false, -1.0f).x;
286
287
ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
288
ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
289
const ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
290
291
// This will catch our interactions
292
bool pressed = ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
293
const bool is_hovered = ImGui::IsItemHovered(); // Hovered
294
const bool is_active = ImGui::IsItemActive(); // Held
295
296
if (pressed) {
297
// INFO_LOG(Log::System, "Pressed");
298
}
299
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
300
301
drawList->PushClipRect(canvas_p0, canvas_p1, true);
302
drawList->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(25, 25, 25, 255));
303
if (is_active) {
304
drawList->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
305
}
306
307
Bounds bounds;
308
bounds.x = canvas_p0.x;
309
bounds.y = canvas_p0.y;
310
bounds.w = canvas_p1.x - canvas_p0.x;
311
bounds.h = canvas_p1.y - canvas_p0.y;
312
313
calculatePixelPositions();
314
315
visibleRows_ = (int)((bounds.h + rowHeight_ - 1.f) / rowHeight_);
316
317
unsigned int address = windowStart_;
318
std::map<u32, float> addressPositions;
319
320
const std::set<std::string> currentArguments = getSelectedLineArguments();
321
DisassemblyLineInfo line;
322
323
const u32 pc = debugger_->GetPC();
324
325
for (int i = 0; i < visibleRows_; i++) {
326
g_disassemblyManager.getLine(address, displaySymbols_, line, debugger_);
327
328
float rowY1 = rowHeight_ * i;
329
float rowY2 = rowHeight_ * (i + 1);
330
331
addressPositions[address] = rowY1;
332
333
// draw background
334
ImColor backgroundColor = ImColor(0xFF000000 | debugger_->getColor(address, true));
335
ImColor textColor = 0xFFFFFFFF;
336
337
if (isInInterval(address, line.totalSize, pc)) {
338
backgroundColor = scaleColor(backgroundColor, 1.3f);
339
}
340
341
if (address >= selectRangeStart_ && address < selectRangeEnd_ && searching_ == false) {
342
if (hasFocus_) {
343
backgroundColor = ImColor(address == curAddress_ ? 0xFFFF8822 : 0xFFFF9933);
344
textColor = ImColor(0xFF000000);
345
} else {
346
backgroundColor = ImColor(0xFF606060);
347
}
348
}
349
350
drawList->AddRectFilled(ImVec2(bounds.x, bounds.y + rowY1), ImVec2(bounds.x2(), bounds.y + rowY1 + rowHeight_), backgroundColor);
351
352
// display breakpoint, if any
353
bool enabled;
354
if (g_breakpoints.IsAddressBreakPoint(address, &enabled)) {
355
ImColor breakColor = 0xFF0000FF;
356
if (!enabled)
357
breakColor = 0xFF909090;
358
float yOffset = std::max(-1.0f, (rowHeight_ - 14.f + 1.f) / 2.0f);
359
drawList->AddCircleFilled(ImVec2(canvas_p0.x + rowHeight_ * 0.5f, canvas_p0.y + rowY1 + rowHeight_ * 0.5f), rowHeight_ * 0.4f, breakColor, 12);
360
}
361
362
char addressText[64];
363
getDisasmAddressText(address, addressText, sizeof(addressText), true, line.type == DISTYPE_OPCODE);
364
drawList->AddText(ImVec2(bounds.x + pixelPositions_.addressStart, bounds.y + rowY1 + 2), textColor, addressText);
365
366
if (isInInterval(address, line.totalSize, pc)) {
367
// Show the current PC with a little triangle.
368
drawList->AddTriangleFilled(
369
ImVec2(canvas_p0.x + pixelPositions_.opcodeStart - rowHeight_ * 0.7f, canvas_p0.y + rowY1 + 2),
370
ImVec2(canvas_p0.x + pixelPositions_.opcodeStart - rowHeight_ * 0.7f, canvas_p0.y + rowY1 + rowHeight_ - 2),
371
ImVec2(canvas_p0.x + pixelPositions_.opcodeStart - 4, canvas_p0.y + rowY1 + rowHeight_ * 0.5f),
372
0xFFFFFFFF);
373
}
374
375
// display whether the condition of a branch is met
376
if (line.info.isConditional && address == pc) {
377
line.params += line.info.conditionMet ? " ; true" : " ; false";
378
}
379
380
drawArguments(drawList, bounds, line, pixelPositions_.argumentsStart, rowY1 + 2.f, textColor, currentArguments);
381
382
// The actual opcode.
383
// Should be bold!
384
drawList->AddText(ImVec2(bounds.x + pixelPositions_.opcodeStart, bounds.y + rowY1 + 2.f), textColor, line.name.c_str());
385
386
address += line.totalSize;
387
}
388
389
std::vector<BranchLine> branchLines = g_disassemblyManager.getBranchLines(windowStart_, address - windowStart_);
390
for (size_t i = 0; i < branchLines.size(); i++) {
391
drawBranchLine(drawList, bounds, addressPositions, branchLines[i]);
392
}
393
394
ImGuiIO& io = ImGui::GetIO();
395
ImVec2 mousePos = ImVec2(io.MousePos.x - canvas_p0.x, io.MousePos.y - canvas_p0.y);
396
if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
397
// INFO_LOG(Log::System, "Mousedown %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
398
onMouseDown(mousePos.x, mousePos.y, 1);
399
}
400
if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
401
// INFO_LOG(Log::CPU, "Mousedown %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
402
onMouseDown(mousePos.x, mousePos.y, 2);
403
}
404
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
405
// INFO_LOG(Log::System, "Mouseup %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
406
if (is_hovered) {
407
onMouseUp(mousePos.x, mousePos.y, 1);
408
}
409
}
410
if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
411
// INFO_LOG(Log::System, "Mousedrag %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
412
if (is_hovered) {
413
onMouseMove(mousePos.x, mousePos.y, 1);
414
}
415
}
416
417
if (is_hovered) {
418
if (io.MouseWheel > 0.0f) { // TODO: Scale steps by the value.
419
windowStart_ = g_disassemblyManager.getNthPreviousAddress(windowStart_, 4);
420
} else if (io.MouseWheel < 0.0f) {
421
windowStart_ = g_disassemblyManager.getNthNextAddress(windowStart_, 4);
422
}
423
}
424
425
ProcessKeyboardShortcuts(ImGui::IsItemFocused());
426
427
if (pressed) {
428
// INFO_LOG(Log::System, "Clicked %f,%f", mousePos.x, mousePos.y);
429
if (mousePos.x < rowHeight_) { // Left column
430
// Toggle breakpoint at dragAddr_.
431
debugger_->toggleBreakpoint(curAddress_);
432
bpPopup_ = true;
433
} else {
434
// disasmView_.selectedAddr_ = dragAddr_;
435
bpPopup_ = false;
436
}
437
}
438
439
ImGui_PopFont();
440
441
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
442
PopupMenu(control);
443
444
drawList->PopClipRect();
445
}
446
447
void ImDisasmView::NotifyStep() {
448
if (followPC_) {
449
GotoPC();
450
}
451
}
452
453
void ImDisasmView::ScrollRelative(int amount) {
454
if (amount > 0) {
455
windowStart_ = g_disassemblyManager.getNthNextAddress(windowStart_, amount);
456
} else if (amount < 0) {
457
windowStart_ = g_disassemblyManager.getNthPreviousAddress(windowStart_, amount);
458
}
459
ScanVisibleFunctions();
460
}
461
462
// Follows branches and jumps.
463
void ImDisasmView::FollowBranch() {
464
DisassemblyLineInfo line;
465
g_disassemblyManager.getLine(curAddress_, true, line, debugger_);
466
467
if (line.type == DISTYPE_OPCODE || line.type == DISTYPE_MACRO) {
468
if (line.info.isBranch) {
469
jumpStack_.push_back(curAddress_);
470
gotoAddr(line.info.branchTarget);
471
} else if (line.info.hasRelevantAddress) {
472
// well, not exactly a branch, but we can do something anyway
473
// SendMessage(GetParent(wnd), WM_DEB_GOTOHEXEDIT, line.info.relevantAddress, 0);
474
// SetFocus(wnd);
475
}
476
} else if (line.type == DISTYPE_DATA) {
477
// jump to the start of the current line
478
// SendMessage(GetParent(wnd), WM_DEB_GOTOHEXEDIT, curAddress, 0);
479
// SetFocus(wnd);
480
}
481
}
482
483
void ImDisasmView::onChar(int c) {
484
if (keyTaken)
485
return;
486
487
char str[2];
488
str[0] = c;
489
str[1] = 0;
490
assembleOpcode(curAddress_, str);
491
}
492
493
494
void ImDisasmView::editBreakpoint(ImConfig &cfg) {
495
/*
496
BreakpointWindow win(wnd, debugger);
497
498
bool exists = false;
499
if (g_breakpoints.IsAddressBreakPoint(curAddress)) {
500
auto breakpoints = g_breakpoints.GetBreakpoints();
501
for (size_t i = 0; i < breakpoints.size(); i++) {
502
if (breakpoints[i].addr == curAddress) {
503
win.loadFromBreakpoint(breakpoints[i]);
504
exists = true;
505
break;
506
}
507
}
508
}
509
510
if (!exists) {
511
win.initBreakpoint(curAddress);
512
}
513
514
if (win.exec()) {
515
if (exists)
516
g_breakpoints.RemoveBreakPoint(curAddress);
517
win.addBreakpoint();
518
}
519
*/
520
}
521
522
void ImDisasmView::ProcessKeyboardShortcuts(bool focused) {
523
if (!focused) {
524
return;
525
}
526
527
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_);
528
keyTaken = true;
529
530
ImGuiIO& io = ImGui::GetIO();
531
532
if (io.KeyMods & ImGuiMod_Ctrl) {
533
if (ImGui::IsKeyPressed(ImGuiKey_F)) {
534
// Toggle the find popup
535
// ImGui::OpenPopup("disSearch");
536
}
537
if (ImGui::IsKeyPressed(ImGuiKey_C) || ImGui::IsKeyPressed(ImGuiKey_Insert)) {
538
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::DISASM);
539
}
540
if (ImGui::IsKeyPressed(ImGuiKey_X)) {
541
// disassembleToFile();
542
}
543
if (ImGui::IsKeyPressed(ImGuiKey_A)) {
544
// assembleOpcode(curAddress, "");
545
}
546
if (ImGui::IsKeyPressed(ImGuiKey_G)) {
547
// Goto. should just focus on the goto input?
548
// u32 addr;
549
// if (executeExpressionWindow(wnd, debugger, addr) == false) return;
550
// gotoAddr(addr);
551
}
552
if (ImGui::IsKeyPressed(ImGuiKey_E)) {
553
// editBreakpoint();
554
}
555
if (ImGui::IsKeyPressed(ImGuiKey_D)) {
556
toggleBreakpoint(true);
557
}
558
if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
559
ScrollRelative(-1);
560
ScanVisibleFunctions();
561
}
562
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
563
ScrollRelative(1);
564
ScanVisibleFunctions();
565
}
566
if (ImGui::IsKeyPressed(ImGuiKey_PageDown)) {
567
setCurAddress(g_disassemblyManager.getNthPreviousAddress(windowEnd, 1), (io.KeyMods & ImGuiMod_Shift) != 0);
568
}
569
if (ImGui::IsKeyPressed(ImGuiKey_PageUp)) {
570
setCurAddress(windowStart_, ImGui::IsKeyDown(ImGuiKey_LeftShift));
571
}
572
} else {
573
if (ImGui::IsKeyPressed(ImGuiKey_PageDown)) {
574
windowStart_ = g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_);
575
}
576
if (ImGui::IsKeyPressed(ImGuiKey_PageUp)) {
577
windowStart_ = g_disassemblyManager.getNthPreviousAddress(windowStart_, visibleRows_);
578
}
579
if (ImGui::IsKeyPressed(ImGuiKey_F3)) {
580
SearchNext(!ImGui::IsKeyPressed(ImGuiKey_LeftShift));
581
}
582
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
583
setCurAddress(g_disassemblyManager.getNthNextAddress(curAddress_, 1), (io.KeyMods & ImGuiMod_Shift) != 0);
584
scrollAddressIntoView();
585
}
586
if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
587
setCurAddress(g_disassemblyManager.getNthPreviousAddress(curAddress_, 1), (io.KeyMods & ImGuiMod_Shift) != 0);
588
scrollAddressIntoView();
589
}
590
if (ImGui::IsKeyPressed(ImGuiKey_RightArrow)) {
591
FollowBranch();
592
}
593
if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
594
if (jumpStack_.empty()) {
595
GotoPC();
596
} else {
597
u32 addr = jumpStack_[jumpStack_.size() - 1];
598
jumpStack_.pop_back();
599
gotoAddr(addr);
600
}
601
return;
602
}
603
if (ImGui::IsKeyPressed(ImGuiKey_F9)) {
604
toggleBreakpoint();
605
}
606
}
607
608
/*
609
if (KeyDownAsync(VK_CONTROL)) {
610
} else {
611
switch (wParam & 0xFFFF) {
612
case VK_NEXT:
613
if (g_disassemblyManager.getNthNextAddress(curAddress, 1) != windowEnd && curAddressIsVisible()) {
614
setCurAddress(g_disassemblyManager.getNthPreviousAddress(windowEnd, 1), KeyDownAsync(VK_SHIFT));
615
scrollAddressIntoView();
616
} else {
617
setCurAddress(g_disassemblyManager.getNthNextAddress(windowEnd, visibleRows_ - 1), KeyDownAsync(VK_SHIFT));
618
scrollAddressIntoView();
619
}
620
break;
621
case VK_PRIOR:
622
if (curAddress_ != windowStart_ && curAddressIsVisible()) {
623
setCurAddress(windowStart_, KeyDownAsync(VK_SHIFT));
624
scrollAddressIntoView();
625
} else {
626
setCurAddress(g_disassemblyManager.getNthPreviousAddress(windowStart_, visibleRows_), KeyDownAsync(VK_SHIFT));
627
scrollAddressIntoView();
628
}
629
break;
630
case VK_TAB:
631
displaySymbols_ = !displaySymbols_;
632
break;
633
default:
634
keyTaken = false;
635
return;
636
}
637
}
638
*/
639
}
640
641
void ImDisasmView::scrollAddressIntoView() {
642
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_);
643
644
if (curAddress_ < windowStart_)
645
windowStart_ = curAddress_;
646
else if (curAddress_ >= windowEnd)
647
windowStart_ = g_disassemblyManager.getNthPreviousAddress(curAddress_, visibleRows_ - 1);
648
649
ScanVisibleFunctions();
650
}
651
652
bool ImDisasmView::curAddressIsVisible() {
653
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_);
654
return curAddress_ >= windowStart_ && curAddress_ < windowEnd;
655
}
656
657
void ImDisasmView::toggleBreakpoint(bool toggleEnabled) {
658
bool enabled;
659
if (g_breakpoints.IsAddressBreakPoint(curAddress_, &enabled)) {
660
if (!enabled) {
661
// enable disabled breakpoints
662
g_breakpoints.ChangeBreakPoint(curAddress_, true);
663
} else if (!toggleEnabled && g_breakpoints.GetBreakPointCondition(curAddress_) != nullptr) {
664
// don't just delete a breakpoint with a custom condition
665
/*
666
int ret = MessageBox(wnd, L"This breakpoint has a custom condition.\nDo you want to remove it?", L"Confirmation", MB_YESNO);
667
if (ret == IDYES)
668
g_breakpoints.RemoveBreakPoint(curAddress);
669
*/
670
} else if (toggleEnabled) {
671
// disable breakpoint
672
g_breakpoints.ChangeBreakPoint(curAddress_, false);
673
} else {
674
// otherwise just remove breakpoint
675
g_breakpoints.RemoveBreakPoint(curAddress_);
676
}
677
} else {
678
g_breakpoints.AddBreakPoint(curAddress_);
679
}
680
}
681
682
void ImDisasmView::onMouseDown(float x, float y, int button) {
683
u32 newAddress = yToAddress(y);
684
bool extend = ImGui::IsKeyDown(ImGuiKey_LeftShift);
685
if (button == 1) {
686
if (newAddress == curAddress_ && hasFocus_) {
687
toggleBreakpoint();
688
}
689
} else if (button == 2) {
690
// Maintain the current selection if right clicking into it.
691
if (newAddress >= selectRangeStart_ && newAddress < selectRangeEnd_)
692
extend = true;
693
}
694
setCurAddress(newAddress, extend);
695
}
696
697
void ImDisasmView::onMouseMove(float x, float y, int button) {
698
if ((button & 1) != 0) {
699
setCurAddress(yToAddress(y), ImGui::IsKeyDown(ImGuiKey_LeftShift));
700
}
701
}
702
703
void ImDisasmView::onMouseUp(float x, float y, int button) {
704
if (button == 1) {
705
if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) {
706
setCurAddress(yToAddress(y), true);
707
}
708
}
709
}
710
711
void ImDisasmView::CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode) {
712
_assert_msg_((startAddr & 3) == 0, "readMemory() can't handle unaligned reads");
713
714
if (mode != CopyInstructionsMode::DISASM) {
715
int instructionSize = debugger_->getInstructionSize(0);
716
int count = (endAddr - startAddr) / instructionSize;
717
int space = count * 32;
718
char *temp = new char[space];
719
720
char *p = temp, *end = temp + space;
721
for (u32 pos = startAddr; pos < endAddr && p < end; pos += instructionSize) {
722
u32 data = mode == CopyInstructionsMode::OPCODES ? debugger_->readMemory(pos) : pos;
723
p += snprintf(p, end - p, "%08X", data);
724
725
// Don't leave a trailing newline.
726
if (pos + instructionSize < endAddr && p < end)
727
p += snprintf(p, end - p, "\r\n");
728
}
729
System_CopyStringToClipboard(temp);
730
delete[] temp;
731
} else {
732
std::string disassembly = disassembleRange(startAddr, endAddr - startAddr);
733
System_CopyStringToClipboard(disassembly);
734
}
735
}
736
737
void ImDisasmView::PopupMenu(ImControl &control) {
738
bool renameFunctionPopup = false;
739
if (ImGui::BeginPopup("context")) {
740
ImGui::Text("Address: %08x", curAddress_);
741
if (ImGui::MenuItem("Toggle breakpoint", "F9")) {
742
toggleBreakpoint();
743
}
744
ShowInMemoryViewerMenuItem(curAddress_, control);
745
if (ImGui::MenuItem("Copy address")) {
746
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::ADDRESSES);
747
}
748
if (ImGui::MenuItem("Copy instruction (disasm)")) {
749
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::DISASM);
750
}
751
if (ImGui::MenuItem("Copy instruction (hex)")) {
752
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::OPCODES);
753
}
754
ImGui::Separator();
755
756
if (ImGui::MenuItem("Set PC to here")) {
757
debugger_->SetPC(curAddress_);
758
}
759
if (ImGui::MenuItem("Follow branch")) {
760
FollowBranch();
761
}
762
if (ImGui::MenuItem("Run to here")) {
763
g_breakpoints.AddBreakPoint(curAddress_, true);
764
g_breakpoints.SetSkipFirst(curAddress_);
765
if (Core_IsStepping()) {
766
Core_Resume();
767
}
768
}
769
ImGui::Separator();
770
if (ImGui::MenuItem("Assemble")) {
771
assembleOpcode(curAddress_, "");
772
}
773
if (ImGui::MenuItem("NOP instructions (destructive)")) {
774
for (u32 addr = selectRangeStart_; addr < selectRangeEnd_; addr += 4) {
775
Memory::Write_U32(0, addr);
776
}
777
if (currentMIPS) {
778
currentMIPS->InvalidateICache(selectRangeStart_, selectRangeEnd_ - selectRangeStart_);
779
}
780
}
781
ImGui::Separator();
782
if (ImGui::MenuItem("Rename function")) {
783
funcBegin_ = g_symbolMap->GetFunctionStart(curAddress_);
784
if (funcBegin_ != -1) {
785
truncate_cpy(funcNameTemp_, g_symbolMap->GetLabelString(funcBegin_));
786
renameFunctionPopup = true;
787
statusBarText_ = funcNameTemp_;
788
} else {
789
statusBarText_ = "No function here";
790
}
791
}
792
if (ImGui::MenuItem("Remove function")) {
793
u32 funcBegin = g_symbolMap->GetFunctionStart(curAddress_);
794
if (funcBegin != -1) {
795
u32 prevBegin = g_symbolMap->GetFunctionStart(funcBegin - 1);
796
if (prevBegin != -1)
797
{
798
u32 expandedSize = g_symbolMap->GetFunctionSize(prevBegin) + g_symbolMap->GetFunctionSize(funcBegin);
799
g_symbolMap->SetFunctionSize(prevBegin, expandedSize);
800
}
801
802
g_symbolMap->RemoveFunction(funcBegin, true);
803
g_symbolMap->SortSymbols();
804
g_disassemblyManager.clear();
805
806
mapReloaded_ = true;
807
} else {
808
statusBarText_ = "WARNING: unable to find function symbol here";
809
}
810
}
811
u32 prevBegin = g_symbolMap->GetFunctionStart(curAddress_);
812
if (ImGui::MenuItem("Add function")) {
813
char statusBarTextBuff[256];
814
if (prevBegin != -1) {
815
if (prevBegin == curAddress_) {
816
snprintf(statusBarTextBuff, 256, "WARNING: There's already a function entry point at this adress");
817
statusBarText_ = statusBarTextBuff;
818
} else {
819
char symname[128];
820
u32 prevSize = g_symbolMap->GetFunctionSize(prevBegin);
821
u32 newSize = curAddress_ - prevBegin;
822
g_symbolMap->SetFunctionSize(prevBegin, newSize);
823
824
newSize = prevSize - newSize;
825
snprintf(symname, 128, "u_un_%08X", curAddress_);
826
g_symbolMap->AddFunction(symname, curAddress_, newSize);
827
g_symbolMap->SortSymbols();
828
g_disassemblyManager.clear();
829
830
mapReloaded_ = true;
831
}
832
} else {
833
char symname[128];
834
int newSize = selectRangeEnd_ - selectRangeStart_;
835
snprintf(symname, 128, "u_un_%08X", selectRangeStart_);
836
g_symbolMap->AddFunction(symname, selectRangeStart_, newSize);
837
g_symbolMap->SortSymbols();
838
839
mapReloaded_ = true;
840
}
841
}
842
if (prevBegin != -1) {
843
u32 prevSize = g_symbolMap->GetFunctionSize(prevBegin);
844
ShowInMemoryDumperMenuItem(prevBegin, prevSize, MemDumpMode::Disassembly, control);
845
}
846
ImGui::EndPopup();
847
}
848
849
// Sub popups here
850
if (renameFunctionPopup) {
851
ImGui::OpenPopup("renameFunction");
852
}
853
// ImGui::SetNextWindowPos(pos, ImGuiCond_Appearing())
854
if (ImGui::BeginPopup("renameFunction")) {
855
std::string symName = g_symbolMap->GetDescription(funcBegin_);
856
ImGui::Text("Rename function %s", symName.c_str());
857
if (ImGui::IsWindowAppearing()) {
858
ImGui::SetKeyboardFocusHere();
859
}
860
if (ImGui::InputText("Name", funcNameTemp_, sizeof(funcNameTemp_), ImGuiInputTextFlags_EnterReturnsTrue) && strlen(funcNameTemp_)) {
861
g_symbolMap->SetLabelName(funcNameTemp_, funcBegin_);
862
u32 funcSize = g_symbolMap->GetFunctionSize(funcBegin_);
863
MIPSAnalyst::RegisterFunction(funcBegin_, funcSize, funcNameTemp_);
864
MIPSAnalyst::UpdateHashMap();
865
MIPSAnalyst::ApplyHashMap();
866
mapReloaded_ = true;
867
ImGui::CloseCurrentPopup();
868
}
869
ImGui::EndPopup();
870
}
871
}
872
873
void ImDisasmView::updateStatusBarText() {
874
if (!PSP_IsInited())
875
return;
876
877
char text[512];
878
DisassemblyLineInfo line;
879
g_disassemblyManager.getLine(curAddress_, true, line, debugger_);
880
881
text[0] = 0;
882
if (line.type == DISTYPE_OPCODE || line.type == DISTYPE_MACRO) {
883
if (line.info.hasRelevantAddress && IsLikelyStringAt(line.info.relevantAddress)) {
884
snprintf(text, sizeof(text), "[%08X] = \"%s\"", line.info.relevantAddress, Memory::GetCharPointer(line.info.relevantAddress));
885
}
886
887
if (line.info.isDataAccess) {
888
if (!Memory::IsValidAddress(line.info.dataAddress)) {
889
snprintf(text, sizeof(text), "Invalid address %08X", line.info.dataAddress);
890
} else {
891
bool isFloat = MIPSGetInfo(line.info.encodedOpcode) & (IS_FPU | IS_VFPU);
892
switch (line.info.dataSize) {
893
case 1:
894
snprintf(text, sizeof(text), "[%08X] = %02X", line.info.dataAddress, Memory::Read_U8(line.info.dataAddress));
895
break;
896
case 2:
897
snprintf(text, sizeof(text), "[%08X] = %04X", line.info.dataAddress, Memory::Read_U16(line.info.dataAddress));
898
break;
899
case 4:
900
{
901
u32 dataInt = Memory::Read_U32(line.info.dataAddress);
902
u32 dataFloat = Memory::Read_Float(line.info.dataAddress);
903
std::string dataString;
904
if (isFloat)
905
dataString = StringFromFormat("%08X / %f", dataInt, dataFloat);
906
else
907
dataString = StringFromFormat("%08X", dataInt);
908
909
const std::string addressSymbol = g_symbolMap->GetLabelString(dataInt);
910
if (!addressSymbol.empty()) {
911
snprintf(text, sizeof(text), "[%08X] = %s (%s)", line.info.dataAddress, addressSymbol.c_str(), dataString.c_str());
912
} else {
913
snprintf(text, sizeof(text), "[%08X] = %s", line.info.dataAddress, dataString.c_str());
914
}
915
break;
916
}
917
case 16:
918
{
919
uint32_t dataInt[4];
920
float dataFloat[4];
921
for (int i = 0; i < 4; ++i) {
922
dataInt[i] = Memory::Read_U32(line.info.dataAddress + i * 4);
923
dataFloat[i] = Memory::Read_Float(line.info.dataAddress + i * 4);
924
}
925
std::string dataIntString = StringFromFormat("%08X,%08X,%08X,%08X", dataInt[0], dataInt[1], dataInt[2], dataInt[3]);
926
std::string dataFloatString = StringFromFormat("%f,%f,%f,%f", dataFloat[0], dataFloat[1], dataFloat[2], dataFloat[3]);
927
928
snprintf(text, sizeof(text), "[%08X] = %s / %s", line.info.dataAddress, dataIntString.c_str(), dataFloatString.c_str());
929
break;
930
}
931
}
932
}
933
}
934
935
if (line.info.isBranch) {
936
const std::string addressSymbol = g_symbolMap->GetLabelString(line.info.branchTarget);
937
if (addressSymbol.empty()) {
938
snprintf(text, sizeof(text), "%08X", line.info.branchTarget);
939
} else {
940
snprintf(text, sizeof(text), "%08X = %s", line.info.branchTarget, addressSymbol.c_str());
941
}
942
}
943
} else if (line.type == DISTYPE_DATA) {
944
u32 start = g_symbolMap->GetDataStart(curAddress_);
945
if (start == -1)
946
start = curAddress_;
947
948
u32 diff = curAddress_ - start;
949
const std::string label = g_symbolMap->GetLabelString(start);
950
951
if (!label.empty()) {
952
if (diff != 0)
953
snprintf(text, sizeof(text), "%08X (%s) + %08X", start, label.c_str(), diff);
954
else
955
snprintf(text, sizeof(text), "%08X (%s)", start, label.c_str());
956
} else {
957
if (diff != 0)
958
snprintf(text, sizeof(text), "%08X + %08X", start, diff);
959
else
960
snprintf(text, sizeof(text), "%08X", start);
961
}
962
}
963
964
statusBarText_ = text;
965
966
const std::string label = g_symbolMap->GetLabelString(line.info.opcodeAddress);
967
if (!label.empty()) {
968
statusBarText_ = label;
969
}
970
}
971
972
u32 ImDisasmView::yToAddress(float y) {
973
int line = (int)(y / rowHeight_);
974
return g_disassemblyManager.getNthNextAddress(windowStart_, line);
975
}
976
977
void ImDisasmView::calculatePixelPositions() {
978
pixelPositions_.addressStart = 16;
979
pixelPositions_.opcodeStart = pixelPositions_.addressStart + 18 * charWidth_;
980
pixelPositions_.argumentsStart = pixelPositions_.opcodeStart + 9 * charWidth_;
981
pixelPositions_.arrowsStart = pixelPositions_.argumentsStart + 30 * charWidth_;
982
}
983
984
void ImDisasmView::Search(std::string_view needle) {
985
searchQuery_ = needle;
986
for (size_t i = 0; i < searchQuery_.size(); i++) {
987
searchQuery_[i] = tolower(searchQuery_[i]);
988
}
989
matchAddress_ = curAddress_;
990
SearchNext(true);
991
}
992
993
void ImDisasmView::SearchNext(bool forward) {
994
if (searchQuery_.empty()) {
995
return;
996
}
997
998
// Note: Search will replace matchAddress_ with the current address.
999
u32 searchAddress = g_disassemblyManager.getNthNextAddress(matchAddress_, 1);
1000
1001
// limit address to sensible ranges
1002
if (searchAddress < 0x04000000)
1003
searchAddress = 0x04000000;
1004
if (searchAddress >= 0x04200000 && searchAddress < 0x08000000)
1005
searchAddress = 0x08000000;
1006
if (searchAddress >= 0x0A000000) {
1007
// MessageBox(wnd, L"Not found", L"Search", MB_OK);
1008
return;
1009
}
1010
1011
searching_ = true;
1012
1013
DisassemblyLineInfo lineInfo;
1014
while (searchAddress < 0x0A000000) {
1015
g_disassemblyManager.getLine(searchAddress, displaySymbols_, lineInfo, debugger_);
1016
1017
char addressText[64];
1018
getDisasmAddressText(searchAddress, addressText, sizeof(addressText), true, lineInfo.type == DISTYPE_OPCODE);
1019
1020
const char* opcode = lineInfo.name.c_str();
1021
const char* arguments = lineInfo.params.c_str();
1022
1023
char merged[512];
1024
int mergePos = 0;
1025
1026
// I'm doing it manually to convert everything to lowercase at the same time
1027
for (int i = 0; addressText[i] != 0; i++) merged[mergePos++] = tolower(addressText[i]);
1028
merged[mergePos++] = ' ';
1029
for (int i = 0; opcode[i] != 0; i++) merged[mergePos++] = tolower(opcode[i]);
1030
merged[mergePos++] = ' ';
1031
for (int i = 0; arguments[i] != 0; i++) merged[mergePos++] = tolower(arguments[i]);
1032
merged[mergePos] = 0;
1033
1034
// match!
1035
if (strstr(merged, searchQuery_.c_str()) != NULL) {
1036
matchAddress_ = searchAddress;
1037
searching_ = false;
1038
gotoAddr(searchAddress);
1039
return;
1040
}
1041
1042
// cancel search
1043
if ((searchAddress % 256) == 0 && ImGui::GetKeyPressedAmount(ImGuiKey_Escape, 0.0f, 0.0f)) {
1044
searching_ = false;
1045
return;
1046
}
1047
1048
searchAddress = g_disassemblyManager.getNthNextAddress(searchAddress, 1);
1049
if (searchAddress >= 0x04200000 && searchAddress < 0x08000000) searchAddress = 0x08000000;
1050
}
1051
1052
statusBarText_ = "Not found: ";
1053
statusBarText_.append(searchQuery_);
1054
1055
searching_ = false;
1056
}
1057
1058
std::string ImDisasmView::disassembleRange(u32 start, u32 size) {
1059
std::string result;
1060
1061
// gather all branch targets without labels
1062
std::set<u32> branchAddresses;
1063
for (u32 i = 0; i < size; i += debugger_->getInstructionSize(0)) {
1064
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debugger_, start + i);
1065
1066
if (info.isBranch && g_symbolMap->GetLabelString(info.branchTarget).empty()) {
1067
if (branchAddresses.find(info.branchTarget) == branchAddresses.end()) {
1068
branchAddresses.insert(info.branchTarget);
1069
}
1070
}
1071
}
1072
1073
u32 disAddress = start;
1074
bool previousLabel = true;
1075
DisassemblyLineInfo line;
1076
while (disAddress < start + size) {
1077
char addressText[64], buffer[512];
1078
1079
g_disassemblyManager.getLine(disAddress, displaySymbols_, line, debugger_);
1080
bool isLabel = getDisasmAddressText(disAddress, addressText, sizeof(addressText), false, line.type == DISTYPE_OPCODE);
1081
1082
if (isLabel) {
1083
if (!previousLabel) result += "\r\n";
1084
sprintf(buffer, "%s\r\n\r\n", addressText);
1085
result += buffer;
1086
} else if (branchAddresses.find(disAddress) != branchAddresses.end()) {
1087
if (!previousLabel) result += "\r\n";
1088
sprintf(buffer, "pos_%08X:\r\n\r\n", disAddress);
1089
result += buffer;
1090
}
1091
1092
if (line.info.isBranch && !line.info.isBranchToRegister
1093
&& g_symbolMap->GetLabelString(line.info.branchTarget).empty()
1094
&& branchAddresses.find(line.info.branchTarget) != branchAddresses.end())
1095
{
1096
sprintf(buffer, "pos_%08X", line.info.branchTarget);
1097
line.params = line.params.substr(0, line.params.find("0x")) + buffer;
1098
}
1099
1100
sprintf(buffer, "\t%s\t%s\r\n", line.name.c_str(), line.params.c_str());
1101
result += buffer;
1102
previousLabel = isLabel;
1103
disAddress += line.totalSize;
1104
}
1105
1106
return result;
1107
}
1108
1109
void ImDisasmView::disassembleToFile() { // get size
1110
/*
1111
u32 size;
1112
if (executeExpressionWindow(wnd, debugger, size) == false)
1113
return;
1114
if (size == 0 || size > 10 * 1024 * 1024) {
1115
MessageBox(wnd, L"Invalid size!", L"Error", MB_OK);
1116
return;
1117
}
1118
1119
std::string filename;
1120
if (W32Util::BrowseForFileName(false, nullptr, L"Save Disassembly As...", nullptr, L"All Files\0*.*\0\0", nullptr, filename)) {
1121
std::wstring fileName = ConvertUTF8ToWString(filename);
1122
FILE *output = _wfopen(fileName.c_str(), L"wb");
1123
if (output == nullptr) {
1124
MessageBox(wnd, L"Could not open file!", L"Error", MB_OK);
1125
return;
1126
}
1127
1128
std::string disassembly = disassembleRange(curAddress, size);
1129
fprintf(output, "%s", disassembly.c_str());
1130
1131
fclose(output);
1132
MessageBox(wnd, L"Finished!", L"Done", MB_OK);
1133
}
1134
*/
1135
}
1136
1137
void ImDisasmView::getOpcodeText(u32 address, char* dest, int bufsize) {
1138
DisassemblyLineInfo line;
1139
address = g_disassemblyManager.getStartAddress(address);
1140
g_disassemblyManager.getLine(address, displaySymbols_, line, debugger_);
1141
snprintf(dest, bufsize, "%s %s", line.name.c_str(), line.params.c_str());
1142
}
1143
1144
void ImDisasmView::scrollStepping(u32 newPc) {
1145
u32 windowEnd = g_disassemblyManager.getNthNextAddress(windowStart_, visibleRows_);
1146
1147
newPc = g_disassemblyManager.getStartAddress(newPc);
1148
if (newPc >= windowEnd || newPc >= g_disassemblyManager.getNthPreviousAddress(windowEnd, 1))
1149
{
1150
windowStart_ = g_disassemblyManager.getNthPreviousAddress(newPc, visibleRows_ - 2);
1151
}
1152
}
1153
1154
u32 ImDisasmView::getInstructionSizeAt(u32 address) {
1155
u32 start = g_disassemblyManager.getStartAddress(address);
1156
u32 next = g_disassemblyManager.getNthNextAddress(start, 1);
1157
return next - address;
1158
}
1159
1160
1161
void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl &control, CoreState coreState) {
1162
disasmView_.setDebugger(mipsDebug);
1163
1164
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
1165
if (!ImGui::Begin(Title(), &cfg.disasmOpen)) {
1166
ImGui::End();
1167
return;
1168
}
1169
1170
if (ImGui::IsWindowFocused()) {
1171
// Process stepping keyboard shortcuts.
1172
if (ImGui::IsKeyPressed(ImGuiKey_F10)) {
1173
u32 stepSize = disasmView_.getInstructionSizeAt(mipsDebug->GetPC());
1174
Core_RequestCPUStep(CPUStepType::Over, stepSize);
1175
}
1176
if (ImGui::IsKeyPressed(ImGuiKey_F11)) {
1177
u32 stepSize = disasmView_.getInstructionSizeAt(mipsDebug->GetPC());
1178
Core_RequestCPUStep(CPUStepType::Into, stepSize);
1179
}
1180
}
1181
1182
if (coreState == CORE_STEPPING_GE || coreState == CORE_RUNNING_GE) {
1183
ImGui::Text("!!! Currently stepping the GE");
1184
ImGui::SameLine();
1185
if (ImGui::SmallButton("Open Ge Debugger")) {
1186
cfg.geDebuggerOpen = true;
1187
ImGui::SetWindowFocus("GE Debugger");
1188
}
1189
}
1190
1191
ImGui::BeginDisabled(coreState != CORE_STEPPING_CPU);
1192
if (ImGui::SmallButton("Run")) {
1193
Core_Resume();
1194
}
1195
ImGui::EndDisabled();
1196
1197
ImGui::SameLine();
1198
ImGui::BeginDisabled(coreState != CORE_RUNNING_CPU);
1199
if (ImGui::SmallButton("Pause")) {
1200
Core_Break(BreakReason::DebugBreak);
1201
}
1202
ImGui::EndDisabled();
1203
1204
ImGui::BeginDisabled(coreState != CORE_STEPPING_CPU);
1205
1206
ImGui::SameLine();
1207
ImGui::Text("Step: ");
1208
ImGui::SameLine();
1209
1210
if (ImGui::RepeatButtonShift("Into")) {
1211
u32 stepSize = disasmView_.getInstructionSizeAt(mipsDebug->GetPC());
1212
Core_RequestCPUStep(CPUStepType::Into, stepSize);
1213
}
1214
if (ImGui::IsItemHovered()) {
1215
ImGui::SetTooltip("F11");
1216
}
1217
1218
ImGui::SameLine();
1219
if (ImGui::SmallButton("Over")) {
1220
u32 stepSize = disasmView_.getInstructionSizeAt(mipsDebug->GetPC());
1221
Core_RequestCPUStep(CPUStepType::Over, stepSize);
1222
}
1223
if (ImGui::IsItemHovered()) {
1224
ImGui::SetTooltip("F10");
1225
}
1226
1227
ImGui::SameLine();
1228
if (ImGui::SmallButton("Out")) {
1229
Core_RequestCPUStep(CPUStepType::Out, 0);
1230
}
1231
1232
/*
1233
ImGui::SameLine();
1234
if (ImGui::SmallButton("Frame")) {
1235
Core_RequestCPUStep(CPUStepType::Frame, 0);
1236
}*/
1237
1238
ImGui::SameLine();
1239
if (ImGui::SmallButton("Syscall")) {
1240
hleDebugBreak();
1241
Core_Resume();
1242
}
1243
1244
ImGui::EndDisabled();
1245
1246
ImGui::SameLine();
1247
if (ImGui::SmallButton("Goto PC")) {
1248
disasmView_.GotoPC();
1249
}
1250
ImGui::SameLine();
1251
if (ImGui::SmallButton("Goto RA")) {
1252
disasmView_.GotoRA();
1253
}
1254
1255
if (ImGui::BeginPopup("disSearch")) {
1256
if (ImGui::IsWindowAppearing()) {
1257
ImGui::SetKeyboardFocusHere();
1258
}
1259
if (ImGui::InputText("Search", searchTerm_, sizeof(searchTerm_), ImGuiInputTextFlags_EnterReturnsTrue)) {
1260
disasmView_.Search(searchTerm_);
1261
ImGui::CloseCurrentPopup();
1262
}
1263
ImGui::EndPopup();
1264
}
1265
1266
ImGui::SameLine();
1267
if (ImGui::SmallButton("Search")) {
1268
// Open a small popup
1269
ImGui::OpenPopup("disSearch");
1270
ImGui::Shortcut(ImGuiKey_F | ImGuiMod_Ctrl);
1271
}
1272
1273
ImGui::SameLine();
1274
if (ImGui::SmallButton("Next")) {
1275
disasmView_.SearchNext(true);
1276
}
1277
1278
ImGui::SameLine();
1279
if (ImGui::SmallButton("Settings")) {
1280
ImGui::OpenPopup("disSettings");
1281
}
1282
1283
if (ImGui::BeginPopup("disSettings")) {
1284
ImGui::Checkbox("Follow PC", &disasmView_.followPC_);
1285
ImGui::EndPopup();
1286
}
1287
1288
ImGui::SetNextItemWidth(100);
1289
if (ImGui::InputScalar("Go to addr: ", ImGuiDataType_U32, &gotoAddr_, NULL, NULL, "%08X")) {
1290
disasmView_.setCurAddress(gotoAddr_);
1291
disasmView_.scrollAddressIntoView();
1292
}
1293
ImGui::SameLine();
1294
if (ImGui::Button("Go")) {
1295
disasmView_.setCurAddress(gotoAddr_);
1296
disasmView_.scrollAddressIntoView();
1297
}
1298
1299
BreakReason breakReason = Core_BreakReason();
1300
ImGui::SameLine();
1301
ImGui::TextUnformatted(BreakReasonToString(breakReason));
1302
1303
ImVec2 avail = ImGui::GetContentRegionAvail();
1304
avail.y -= ImGui::GetTextLineHeightWithSpacing();
1305
1306
if (ImGui::BeginChild("left", ImVec2(150.0f, avail.y), ImGuiChildFlags_ResizeX)) {
1307
if (symCache_.empty() || symsDirty_) {
1308
symCache_ = g_symbolMap->GetAllActiveSymbols(SymbolType::ST_FUNCTION);
1309
symsDirty_ = false;
1310
}
1311
1312
if (selectedSymbol_ >= 0 && selectedSymbol_ < symCache_.size()) {
1313
auto &sym = symCache_[selectedSymbol_];
1314
if (ImGui::TreeNode("Edit Symbol", "Edit %s", sym.name.c_str())) {
1315
if (ImGui::InputText("Name", selectedSymbolName_, sizeof(selectedSymbolName_), ImGuiInputTextFlags_EnterReturnsTrue)) {
1316
g_symbolMap->SetLabelName(selectedSymbolName_, sym.address);
1317
symsDirty_ = true;
1318
}
1319
ImGui::Text("%08x (size: %0d)", sym.address, sym.size);
1320
ImGui::TreePop();
1321
}
1322
}
1323
1324
if (ImGui::BeginListBox("##symbols", ImGui::GetContentRegionAvail())) {
1325
ImGuiListClipper clipper;
1326
clipper.Begin((int)symCache_.size(), -1);
1327
while (clipper.Step()) {
1328
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
1329
if (ImGui::Selectable(symCache_[i].name.c_str(), selectedSymbol_ == i)) {
1330
disasmView_.gotoAddr(symCache_[i].address);
1331
disasmView_.scrollAddressIntoView();
1332
truncate_cpy(selectedSymbolName_, symCache_[i].name);
1333
selectedSymbol_ = i;
1334
}
1335
}
1336
}
1337
clipper.End();
1338
ImGui::EndListBox();
1339
}
1340
}
1341
ImGui::EndChild();
1342
1343
ImGui::SameLine();
1344
if (ImGui::BeginChild("right", ImVec2(0.0f, avail.y))) {
1345
disasmView_.Draw(ImGui::GetWindowDrawList(), control);
1346
}
1347
ImGui::EndChild();
1348
1349
StatusBar(disasmView_.StatusBarText());
1350
ImGui::End();
1351
}
1352
1353