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