Merge pull request #19720 from hrydgard/imgui-memview

ImDebugger: Add memory viewer window
This commit is contained in:
Henrik Rydgård 2024-12-12 18:38:48 +01:00 committed by GitHub
commit 07e6c35532
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1283 additions and 151 deletions

View file

@ -1528,6 +1528,8 @@ list(APPEND NativeAppSource
UI/ImDebugger/ImGe.h
UI/ImDebugger/ImDisasmView.cpp
UI/ImDebugger/ImDisasmView.h
UI/ImDebugger/ImMemView.cpp
UI/ImDebugger/ImMemView.h
UI/ImDebugger/ImStructViewer.cpp
UI/ImDebugger/ImStructViewer.h
UI/DiscordIntegration.cpp

View file

@ -57,7 +57,7 @@ public:
virtual u32 GetPC() = 0;
virtual void SetPC(u32 _pc) = 0;
virtual u32 GetLR() = 0;
virtual u32 GetRA() = 0;
virtual void DisAsm(u32 pc, char *out, size_t outSize) = 0;

View file

@ -200,7 +200,7 @@ public:
void clear();
void setCpu(DebugInterface* _cpu) { cpu = _cpu; };
static void setCpu(DebugInterface* _cpu) { cpu = _cpu; };
void setMaxParamChars(int num) { maxParamChars = num; clear(); };
void getLine(u32 address, bool insertSymbols, DisassemblyLineInfo &dest, DebugInterface *cpuDebug = nullptr);
void analyze(u32 address, u32 size);

View file

@ -28,7 +28,7 @@ public:
u32 GetGPR32Value(int reg) override { return ctx.r[reg]; }
u32 GetPC() override { return ctx.pc; }
u32 GetLR() override { return ctx.r[MIPS_REG_RA]; }
u32 GetRA() override { return ctx.r[MIPS_REG_RA]; }
void SetPC(u32 _pc) override { ctx.pc = _pc; }
void PrintRegValue(int cat, int index, char *out, size_t outSize) override {

View file

@ -1327,7 +1327,7 @@ void timeoutFriendsRecursive(SceNetAdhocctlPeerInfo * node, int32_t* count) {
}
void sendChat(const std::string &chatString) {
SceNetAdhocctlChatPacketC2S chat;
SceNetAdhocctlChatPacketC2S chat{};
chat.base.opcode = OPCODE_CHAT;
//TODO check network inited, check send success or not, chatlog.pushback error on failed send, pushback error on not connected
if (friendFinderRunning) {

View file

@ -50,7 +50,7 @@ public:
void SetGPR32Value(int reg, u32 value) override { cpu->r[reg] = value; }
u32 GetPC() override { return cpu->pc; }
u32 GetLR() override { return cpu->r[MIPS_REG_RA]; }
u32 GetRA() override { return cpu->r[MIPS_REG_RA]; }
u32 GetFPCond() override { return cpu->fpcond; }
void DisAsm(u32 pc, char *out, size_t outSize) override;
void SetPC(u32 _pc) override { cpu->pc = _pc; }

View file

@ -35,12 +35,35 @@
// GPU things
#include "GPU/Common/GPUDebugInterface.h"
#include "GPU/Debugger/Stepping.h"
#include "UI/ImDebugger/ImDebugger.h"
#include "UI/ImDebugger/ImGe.h"
extern bool g_TakeScreenshot;
void ShowInMemoryViewerMenuItem(uint32_t addr, ImControl &control) {
if (ImGui::BeginMenu("Show in memory viewer")) {
for (int i = 0; i < 4; i++) {
if (ImGui::MenuItem(ImMemWindow::Title(i))) {
control.command = { ImCmd::SHOW_IN_MEMORY_VIEWER, addr, (u32)i };
}
}
ImGui::EndMenu();
}
}
void ShowInWindowMenuItems(uint32_t addr, ImControl &control) {
// Enable when we implement the memory viewer
ShowInMemoryViewerMenuItem(addr, control);
if (ImGui::MenuItem("Show in CPU debugger")) {
control.command = { ImCmd::SHOW_IN_CPU_DISASM, addr };
}
if (ImGui::MenuItem("Show in GE debugger")) {
control.command = { ImCmd::SHOW_IN_GE_DISASM, addr };
}
}
// TODO: Style it.
// Left click performs the preferred action, if any. Right click opens a menu for more.
void ImClickableAddress(uint32_t addr, ImControl &control, ImCmd cmd) {
@ -56,18 +79,7 @@ void ImClickableAddress(uint32_t addr, ImControl &control, ImCmd cmd) {
System_CopyStringToClipboard(temp);
}
ImGui::Separator();
// Enable when we implement the memory viewer
if (cmd != ImCmd::SHOW_IN_MEMORY_VIEWER) {
if (ImGui::MenuItem("Show in memory viewer 1")) {
control.command = { ImCmd::SHOW_IN_MEMORY_VIEWER, addr };
}
}
if (ImGui::MenuItem("Show in CPU debugger")) {
control.command = { ImCmd::SHOW_IN_CPU_DISASM, addr };
}
if (ImGui::MenuItem("Show in GE debugger")) {
control.command = { ImCmd::SHOW_IN_GE_DISASM, addr };
}
ShowInWindowMenuItems(addr, control);
ImGui::EndPopup();
}
}
@ -879,6 +891,27 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
return;
}
// TODO: Pass mipsDebug in where needed instead.
DisassemblyManager::setCpu(mipsDebug);
disasm_.View().setDebugger(mipsDebug);
for (int i = 0; i < 4; i++) {
mem_[i].View().setDebugger(mipsDebug);
}
// Watch the step counters to figure out when to update things.
if (lastCpuStepCount_ != Core_GetSteppingCounter()) {
lastCpuStepCount_ = Core_GetSteppingCounter();
disasm_.View().NotifyStep();
}
if (lastGpuStepCount_ != GPUStepping::GetSteppingCounter()) {
// A GPU step has happened since last time. This means that we should re-center the cursor.
// Snapshot();
lastGpuStepCount_ = GPUStepping::GetSteppingCounter();
geDebugger_.View().NotifyStep();
}
ImControl control{};
if (ImGui::BeginMainMenuBar()) {
@ -951,6 +984,12 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::MenuItem("Callstacks", nullptr, &cfg_.callstackOpen);
ImGui::MenuItem("Breakpoints", nullptr, &cfg_.breakpointsOpen);
ImGui::MenuItem("Scheduler", nullptr, &cfg_.schedulerOpen);
ImGui::Separator();
for (int i = 0; i < 4; i++) {
char title[64];
snprintf(title, sizeof(title), "Memory %d", i + 1);
ImGui::MenuItem(title, nullptr, &cfg_.memViewOpen[i]);
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("HLE")) {
@ -999,7 +1038,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
}
if (cfg_.disasmOpen) {
disasm_.Draw(mipsDebug, cfg_, coreState);
disasm_.Draw(mipsDebug, cfg_, control, coreState);
}
if (cfg_.regsOpen) {
@ -1074,13 +1113,37 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
DrawSchedulerView(cfg_);
}
for (int i = 0; i < 4; i++) {
if (cfg_.memViewOpen[i]) {
mem_[i].Draw(mipsDebug, cfg_, control, i);
}
}
// Process UI commands
switch (control.command.cmd) {
case ImCmd::SHOW_IN_CPU_DISASM:
disasm_.View().gotoAddr(control.command.param);
cfg_.disasmOpen = true;
ImGui::SetWindowFocus(disasm_.Title());
break;
case ImCmd::SHOW_IN_GE_DISASM:
geDebugger_.View().GotoAddr(control.command.param);
cfg_.geDebuggerOpen = true;
ImGui::SetWindowFocus(geDebugger_.Title());
break;
case ImCmd::SHOW_IN_MEMORY_VIEWER:
{
u32 index = control.command.param2;
_dbg_assert_(index < 4);
mem_[index].GotoAddr(control.command.param);
cfg_.memViewOpen[index] = true;
ImGui::SetWindowFocus(ImMemWindow::Title(index));
break;
}
case ImCmd::TRIGGER_FIND_POPUP:
// TODO
break;
case ImCmd::NONE:
break;
}
}
@ -1089,14 +1152,56 @@ void ImDebugger::Snapshot() {
}
void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, CoreState coreState) {
char title[256];
snprintf(title, sizeof(title), "%s - Disassembly", "Allegrex MIPS");
void ImMemWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl &control, int index) {
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(Title(index), &cfg.memViewOpen[index])) {
ImGui::End();
return;
}
// Toolbars
if (ImGui::InputScalar("Go to addr: ", ImGuiDataType_U32, &gotoAddr_, NULL, NULL, "%08X", ImGuiInputTextFlags_EnterReturnsTrue)) {
memView_.gotoAddr(gotoAddr_);
}
// Main views - list of interesting addresses to the left, memory view to the right.
if (ImGui::BeginChild("addr_list", ImVec2(200.0f, 0.0))) {
if (ImGui::Selectable("Scratch")) {
GotoAddr(0x00010000);
}
if (ImGui::Selectable("Kernel RAM")) {
GotoAddr(0x08000000);
}
if (ImGui::Selectable("User RAM")) {
GotoAddr(0x08800000);
}
if (ImGui::Selectable("VRAM")) {
GotoAddr(0x08800000);
}
ImGui::EndChild();
}
ImGui::SameLine();
ImGui::BeginGroup();
if (ImGui::BeginChild("memview", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()))) {
memView_.Draw(ImGui::GetWindowDrawList());
ImGui::EndChild();
}
ImGui::TextUnformatted(memView_.StatusMessage().c_str());
ImGui::EndGroup();
ImGui::End();
}
const char *ImMemWindow::Title(int index) {
static const char *const titles[4] = { "Memory 1", "Memory 2", "Memory 3", "Memory 4" };
return titles[index];
}
void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl &control, CoreState coreState) {
disasmView_.setDebugger(mipsDebug);
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(title, &cfg.disasmOpen, ImGuiWindowFlags_NoNavInputs)) {
if (!ImGui::Begin(Title(), &cfg.disasmOpen, ImGuiWindowFlags_NoNavInputs)) {
ImGui::End();
return;
}
@ -1185,11 +1290,11 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, CoreStat
ImGui::SameLine();
if (ImGui::SmallButton("Goto PC")) {
disasmView_.gotoPC();
disasmView_.GotoPC();
}
ImGui::SameLine();
if (ImGui::SmallButton("Goto LR")) {
disasmView_.gotoLR();
if (ImGui::SmallButton("Goto RA")) {
disasmView_.GotoRA();
}
if (ImGui::BeginPopup("disSearch")) {
@ -1278,7 +1383,7 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, CoreStat
}
ImGui::TableSetColumnIndex(1);
disasmView_.Draw(ImGui::GetWindowDrawList());
disasmView_.Draw(ImGui::GetWindowDrawList(), control);
ImGui::EndTable();
ImGui::TextUnformatted(disasmView_.StatusBarText().c_str());
@ -1347,6 +1452,11 @@ void ImConfig::SyncConfig(IniFile *ini, bool save) {
sync.Sync("geDebuggerOpen", &geDebuggerOpen, false);
sync.Sync("geStateOpen", &geStateOpen, false);
sync.Sync("schedulerOpen", &schedulerOpen, false);
for (int i = 0; i < 4; i++) {
char name[64];
snprintf(name, sizeof(name), "memory%dOpen", i + 1);
sync.Sync(name, &memViewOpen[i], false);
}
sync.SetSection(ini->GetOrCreateSection("Settings"));
sync.Sync("displayLatched", &displayLatched, false);

View file

@ -16,6 +16,7 @@
#include "Core/Debugger/DebugInterface.h"
#include "UI/ImDebugger/ImDisasmView.h"
#include "UI/ImDebugger/ImMemView.h"
#include "UI/ImDebugger/ImStructViewer.h"
#include "UI/ImDebugger/ImGe.h"
@ -31,13 +32,16 @@ struct ImConfig;
// Corresponds to the CDisasm dialog
class ImDisasmWindow {
public:
void Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, CoreState coreState);
void Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl &control, CoreState coreState);
ImDisasmView &View() {
return disasmView_;
}
void DirtySymbolMap() {
symsDirty_ = true;
}
const char *Title() const {
return "CPU Debugger";
}
private:
// We just keep the state directly in the window. Can refactor later.
@ -46,7 +50,7 @@ private:
INVALID_ADDR = 0xFFFFFFFF,
};
u32 gotoAddr_ = 0x1000;
u32 gotoAddr_ = 0x08800000;
// Symbol cache
std::vector<SymbolEntry> symCache_;
@ -58,6 +62,39 @@ private:
char searchTerm_[64]{};
};
// Corresponds to the CMemView dialog
class ImMemWindow {
public:
void Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl &control, int index);
ImMemView &View() {
return memView_;
}
void DirtySymbolMap() {
symsDirty_ = true;
}
void GotoAddr(u32 addr) {
memView_.gotoAddr(addr);
}
static const char *Title(int index);
private:
// We just keep the state directly in the window. Can refactor later.
enum {
INVALID_ADDR = 0xFFFFFFFF,
};
// Symbol cache
std::vector<SymbolEntry> symCache_;
bool symsDirty_ = true;
int selectedSymbol_ = -1;
char selectedSymbolName_[128];
ImMemView memView_;
char searchTerm_[64]{};
u32 gotoAddr_ = 0x08800000;
};
struct ImConfig {
// Defaults for saved settings are set in SyncConfig.
@ -82,6 +119,7 @@ struct ImConfig {
bool geDebuggerOpen;
bool geStateOpen;
bool schedulerOpen;
bool memViewOpen[4];
// HLE explorer settings
// bool filterByUsed = true;
@ -108,12 +146,13 @@ enum class ImCmd {
TRIGGER_FIND_POPUP,
SHOW_IN_CPU_DISASM,
SHOW_IN_GE_DISASM,
SHOW_IN_MEMORY_VIEWER,
SHOW_IN_MEMORY_VIEWER, // param is address, param2 is viewer index
};
struct ImCommand {
ImCmd cmd;
uint32_t param;
uint32_t param2;
};
struct ImControl {
@ -139,11 +178,17 @@ private:
ImDisasmWindow disasm_;
ImGeDebuggerWindow geDebugger_;
ImGeStateWindow geStateWindow_;
ImMemWindow mem_[4]; // We support 4 separate instances of the memory viewer.
ImStructViewer structViewer_;
int lastCpuStepCount_ = -1;
int lastGpuStepCount_ = -1;
// Open variables.
ImConfig cfg_{};
};
// Simple custom controls
// Simple custom controls and utilities.
void ImClickableAddress(uint32_t addr, ImControl &control, ImCmd cmd);
void ShowInWindowMenuItems(uint32_t addr, ImControl &control);
void ShowInMemoryViewerMenuItem(uint32_t addr, ImControl &control);

View file

@ -1,9 +1,9 @@
#include "ext/imgui/imgui_internal.h"
#include "ext/imgui/imgui_impl_thin3d.h"
#include "Common/StringUtils.h"
#include "Common/Log.h"
#include "Common/Math/geom2d.h"
#include "Core/Core.h"
#include "Core/Debugger/DebugInterface.h"
#include "Core/Debugger/DisassemblyManager.h"
@ -17,6 +17,7 @@
#include "Core/Core.h"
#include "Core/CoreParameter.h"
#include "UI/ImDebugger/ImDisasmView.h"
#include "UI/ImDebugger/ImDebugger.h"
ImDisasmView::ImDisasmView() {
curAddress_ = 0;
@ -82,24 +83,6 @@ bool ImDisasmView::getDisasmAddressText(u32 address, char* dest, bool abbreviate
}
}
// TODO: Replace with another impl.
/*
static std::string trimString(std::string input) {
size_t pos = input.find_first_not_of(" \t");
if (pos != 0 && pos != std::string::npos) {
input = input.erase(0, pos);
}
pos = input.find_last_not_of(" \t");
if (pos != std::string::npos) {
size_t size = input.length() - pos - 1;
input = input.erase(pos + 1, size);
}
return input;
}
*/
void ImDisasmView::assembleOpcode(u32 address, const std::string &defaultText) {
/*
if (!Core_IsStepping()) {
@ -157,7 +140,7 @@ void ImDisasmView::assembleOpcode(u32 address, const std::string &defaultText) {
*/
}
void ImDisasmView::drawBranchLine(ImDrawList *drawList, Rect rect, std::map<u32, float> &addressPositions, const BranchLine &line) {
void ImDisasmView::drawBranchLine(ImDrawList *drawList, Bounds rect, std::map<u32, float> &addressPositions, const BranchLine &line) {
u32 windowEnd = manager.getNthNextAddress(windowStart_, visibleRows_);
float topY;
@ -165,7 +148,7 @@ void ImDisasmView::drawBranchLine(ImDrawList *drawList, Rect rect, std::map<u32,
if (line.first < windowStart_) {
topY = -1;
} else if (line.first >= windowEnd) {
topY = rect.bottom + 1.0f;
topY = rect.y2() + 1.0f;
} else {
topY = (float)addressPositions[line.first] + rowHeight_ / 2;
}
@ -173,12 +156,12 @@ void ImDisasmView::drawBranchLine(ImDrawList *drawList, Rect rect, std::map<u32,
if (line.second < windowStart_) {
bottomY = -1;
} else if (line.second >= windowEnd) {
bottomY = rect.bottom + 1.0f;
bottomY = rect.y2() + 1.0f;
} else {
bottomY = (float)addressPositions[line.second] + rowHeight_ / 2;
}
if ((topY < 0 && bottomY < 0) || (topY > rect.bottom && bottomY > rect.bottom)) {
if ((topY < 0 && bottomY < 0) || (topY > rect.y2() && bottomY > rect.y2())) {
return;
}
@ -200,7 +183,7 @@ void ImDisasmView::drawBranchLine(ImDrawList *drawList, Rect rect, std::map<u32,
curY = y;
};
auto lineTo = [&](float x, float y) {
drawList->AddLine(ImVec2(rect.left + curX, rect.top + curY), ImVec2(rect.left + (float)x, rect.top + (float)y), pen, 1.0f);
drawList->AddLine(ImVec2(rect.x + curX, rect.y + curY), ImVec2(rect.x + (float)x, rect.y + (float)y), pen, 1.0f);
curX = x;
curY = y;
};
@ -215,10 +198,10 @@ void ImDisasmView::drawBranchLine(ImDrawList *drawList, Rect rect, std::map<u32,
lineTo(x - 4.f, bottomY);
lineTo(x + 1.f, bottomY + 5.f);
}
} else if (bottomY > rect.bottom) {// second is not visible, but first is
} else if (bottomY > rect.y2()) {// second is not visible, but first is
moveTo(x - 2.f, topY);
lineTo(x + 2.f, topY);
lineTo(x + 2.f, rect.bottom);
lineTo(x + 2.f, rect.y2());
if (line.type == LINE_UP) {
moveTo(x, topY - 4.f);
@ -266,13 +249,13 @@ std::set<std::string> ImDisasmView::getSelectedLineArguments() {
return args;
}
void ImDisasmView::drawArguments(ImDrawList *drawList, Rect rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> &currentArguments) {
void ImDisasmView::drawArguments(ImDrawList *drawList, Bounds rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> &currentArguments) {
if (line.params.empty()) {
return;
}
// Don't highlight the selected lines.
if (isInInterval(selectRangeStart_, selectRangeEnd_ - selectRangeStart_, line.info.opcodeAddress)) {
drawList->AddText(ImVec2((float)(rc.left + x), (float)(rc.top + y)), textColor, line.params.data(), line.params.data() + line.params.size());
drawList->AddText(ImVec2((float)(rc.x + x), (float)(rc.y + y)), textColor, line.params.data(), line.params.data() + line.params.size());
return;
}
@ -286,7 +269,7 @@ void ImDisasmView::drawArguments(ImDrawList *drawList, Rect rc, const Disassembl
ImColor curColor = textColor;
auto Print = [&](std::string_view text) {
drawList->AddText(ImVec2(rc.left + curX, rc.top + curY), curColor, text.data(), text.data() + text.size());
drawList->AddText(ImVec2(rc.x + curX, rc.y + curY), curColor, text.data(), text.data() + text.size());
ImVec2 sz = ImGui::CalcTextSize(text.data(), text.data() + text.size(), false, -1.0f);
curX += sz.x;
};
@ -313,8 +296,8 @@ void ImDisasmView::drawArguments(ImDrawList *drawList, Rect rc, const Disassembl
}
}
void ImDisasmView::Draw(ImDrawList *drawList) {
if (!debugger->isAlive()) {
void ImDisasmView::Draw(ImDrawList *drawList, ImControl &control) {
if (!debugger_->isAlive()) {
return;
}
@ -340,7 +323,7 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
}
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
const ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
drawList->PushClipRect(canvas_p0, canvas_p1, true);
drawList->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(25, 25, 25, 255));
@ -348,15 +331,15 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
drawList->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
}
Rect rect;
rect.left = canvas_p0.x;
rect.top = canvas_p0.y;
rect.right = canvas_p1.x;
rect.bottom = canvas_p1.y;
Bounds bounds;
bounds.x = canvas_p0.x;
bounds.y = canvas_p0.y;
bounds.w = canvas_p1.x - canvas_p0.x;
bounds.h = canvas_p1.y - canvas_p0.y;
calculatePixelPositions();
visibleRows_ = (int)((rect.bottom - rect.top + rowHeight_ - 1.f) / rowHeight_);
visibleRows_ = (int)((bounds.h + rowHeight_ - 1.f) / rowHeight_);
unsigned int address = windowStart_;
std::map<u32, float> addressPositions;
@ -364,7 +347,7 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
const std::set<std::string> currentArguments = getSelectedLineArguments();
DisassemblyLineInfo line;
const u32 pc = debugger->GetPC();
const u32 pc = debugger_->GetPC();
for (int i = 0; i < visibleRows_; i++) {
manager.getLine(address, displaySymbols_, line);
@ -375,7 +358,7 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
addressPositions[address] = rowY1;
// draw background
ImColor backgroundColor = ImColor(0xFF000000 | debugger->getColor(address, true));
ImColor backgroundColor = ImColor(0xFF000000 | debugger_->getColor(address, true));
ImColor textColor = 0xFFFFFFFF;
if (isInInterval(address, line.totalSize, pc)) {
@ -391,7 +374,7 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
}
}
drawList->AddRectFilled(ImVec2(rect.left, rect.top + rowY1), ImVec2(rect.right, rect.top + rowY1 + rowHeight_), backgroundColor);
drawList->AddRectFilled(ImVec2(bounds.x, bounds.y + rowY1), ImVec2(bounds.x2(), bounds.y + rowY1 + rowHeight_), backgroundColor);
// display breakpoint, if any
bool enabled;
@ -405,7 +388,7 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
char addressText[64];
getDisasmAddressText(address, addressText, true, line.type == DISTYPE_OPCODE);
drawList->AddText(ImVec2(rect.left + pixelPositions_.addressStart, rect.top + rowY1 + 2), textColor, addressText);
drawList->AddText(ImVec2(bounds.x + pixelPositions_.addressStart, bounds.y + rowY1 + 2), textColor, addressText);
if (isInInterval(address, line.totalSize, pc)) {
// Show the current PC with a little triangle.
@ -421,18 +404,18 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
line.params += line.info.conditionMet ? " ; true" : " ; false";
}
drawArguments(drawList, rect, line, pixelPositions_.argumentsStart, rowY1 + 2.f, textColor, currentArguments);
drawArguments(drawList, bounds, line, pixelPositions_.argumentsStart, rowY1 + 2.f, textColor, currentArguments);
// The actual opcode.
// Should be bold!
drawList->AddText(ImVec2(rect.left + pixelPositions_.opcodeStart, rect.top + rowY1 + 2.f), textColor, line.name.c_str());
drawList->AddText(ImVec2(bounds.x + pixelPositions_.opcodeStart, bounds.y + rowY1 + 2.f), textColor, line.name.c_str());
address += line.totalSize;
}
std::vector<BranchLine> branchLines = manager.getBranchLines(windowStart_, address - windowStart_);
for (size_t i = 0; i < branchLines.size(); i++) {
drawBranchLine(drawList, rect, addressPositions, branchLines[i]);
drawBranchLine(drawList, bounds, addressPositions, branchLines[i]);
}
ImGuiIO& io = ImGui::GetIO();
@ -468,20 +451,11 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
ProcessKeyboardShortcuts(ImGui::IsItemFocused());
int coreStep = Core_GetSteppingCounter();
if (coreStep != lastSteppingCount_) {
// A step has happened since last time. This means that we should re-center the cursor.
if (followPC_) {
gotoPC();
}
lastSteppingCount_ = coreStep;
}
if (pressed) {
// INFO_LOG(Log::System, "Clicked %f,%f", mousePos.x, mousePos.y);
if (mousePos.x < rowHeight_) { // Left column
// Toggle breakpoint at dragAddr_.
debugger->toggleBreakpoint(curAddress_);
debugger_->toggleBreakpoint(curAddress_);
bpPopup_ = true;
} else {
// disasmView_.selectedAddr_ = dragAddr_;
@ -492,11 +466,17 @@ void ImDisasmView::Draw(ImDrawList *drawList) {
ImGui_PopFont();
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
PopupMenu();
PopupMenu(control);
drawList->PopClipRect();
}
void ImDisasmView::NotifyStep() {
if (followPC_) {
GotoPC();
}
}
void ImDisasmView::ScrollRelative(int amount) {
if (amount > 0) {
windowStart_ = manager.getNthNextAddress(windowStart_, amount);
@ -528,7 +508,8 @@ void ImDisasmView::FollowBranch() {
}
void ImDisasmView::onChar(int c) {
if (keyTaken) return;
if (keyTaken)
return;
char str[2];
str[0] = c;
@ -638,7 +619,7 @@ void ImDisasmView::ProcessKeyboardShortcuts(bool focused) {
}
if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
if (jumpStack_.empty()) {
gotoPC();
GotoPC();
} else {
u32 addr = jumpStack_[jumpStack_.size() - 1];
jumpStack_.pop_back();
@ -758,14 +739,14 @@ void ImDisasmView::CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructions
_assert_msg_((startAddr & 3) == 0, "readMemory() can't handle unaligned reads");
if (mode != CopyInstructionsMode::DISASM) {
int instructionSize = debugger->getInstructionSize(0);
int instructionSize = debugger_->getInstructionSize(0);
int count = (endAddr - startAddr) / instructionSize;
int space = count * 32;
char *temp = new char[space];
char *p = temp, *end = temp + space;
for (u32 pos = startAddr; pos < endAddr && p < end; pos += instructionSize) {
u32 data = mode == CopyInstructionsMode::OPCODES ? debugger->readMemory(pos) : pos;
u32 data = mode == CopyInstructionsMode::OPCODES ? debugger_->readMemory(pos) : pos;
p += snprintf(p, end - p, "%08X", data);
// Don't leave a trailing newline.
@ -780,39 +761,27 @@ void ImDisasmView::CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructions
}
}
void ImDisasmView::NopInstructions(u32 selectRangeStart, u32 selectRangeEnd) {
for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) {
Memory::Write_U32(0, addr);
}
if (currentMIPS) {
currentMIPS->InvalidateICache(selectRangeStart, selectRangeEnd - selectRangeStart);
}
}
void ImDisasmView::PopupMenu() {
void ImDisasmView::PopupMenu(ImControl &control) {
bool renameFunctionPopup = false;
if (ImGui::BeginPopup("context")) {
ImGui::Text("Address: %08x", curAddress_);
if (ImGui::MenuItem("Toggle breakpoint", "F9")) {
toggleBreakpoint();
}
if (ImGui::MenuItem("Go to in memory view")) {
// SendMessage(GetParent(wnd), WM_DEB_GOTOHEXEDIT, curAddress, 0);
ShowInMemoryViewerMenuItem(curAddress_, control);
if (ImGui::MenuItem("Copy address")) {
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::ADDRESSES);
}
if (ImGui::MenuItem("Copy instruction (disasm)")) {
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::DISASM);
}
if (ImGui::MenuItem("Copy address")) {
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::ADDRESSES);
}
if (ImGui::MenuItem("Copy instruction (hex)")) {
CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::OPCODES);
}
ImGui::Separator();
if (ImGui::MenuItem("Set PC to here")) {
debugger->SetPC(curAddress_);
debugger_->SetPC(curAddress_);
}
if (ImGui::MenuItem("Follow branch")) {
FollowBranch();
@ -829,7 +798,12 @@ void ImDisasmView::PopupMenu() {
assembleOpcode(curAddress_, "");
}
if (ImGui::MenuItem("NOP instructions (destructive)")) {
NopInstructions(selectRangeStart_, selectRangeEnd_);
for (u32 addr = selectRangeStart_; addr < selectRangeEnd_; addr += 4) {
Memory::Write_U32(0, addr);
}
if (currentMIPS) {
currentMIPS->InvalidateICache(selectRangeStart_, selectRangeEnd_ - selectRangeStart_);
}
}
ImGui::Separator();
if (ImGui::MenuItem("Rename function")) {
@ -1112,8 +1086,8 @@ std::string ImDisasmView::disassembleRange(u32 start, u32 size) {
// gather all branch targets without labels
std::set<u32> branchAddresses;
for (u32 i = 0; i < size; i += debugger->getInstructionSize(0)) {
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debugger, start + i);
for (u32 i = 0; i < size; i += debugger_->getInstructionSize(0)) {
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debugger_, start + i);
if (info.isBranch && g_symbolMap->GetLabelString(info.branchTarget).empty()) {
if (branchAddresses.find(info.branchTarget) == branchAddresses.end()) {

View file

@ -8,11 +8,13 @@
#include "ext/imgui/imgui.h"
#include "Common/CommonTypes.h"
#include "Common/Math/geom2d.h"
#include "Core/Debugger/DisassemblyManager.h"
#include "Core/Debugger/DebugInterface.h"
struct ImConfig;
struct ImControl;
// Corresponds to CtrlDisAsmView
// TODO: Fold out common code.
@ -24,9 +26,10 @@ public:
// Public variables bounds to imgui checkboxes
bool followPC_ = true;
void Draw(ImDrawList *drawList);
void Draw(ImDrawList *drawList, ImControl &control);
void PopupMenu();
void PopupMenu(ImControl &control);
void NotifyStep();
void ScrollRelative(int amount);
@ -43,14 +46,14 @@ public:
u32 yToAddress(float y);
void setDebugger(DebugInterface *deb) {
if (debugger != deb) {
debugger = deb;
curAddress_ = debugger->GetPC();
if (debugger_ != deb) {
debugger_ = deb;
curAddress_ = debugger_->GetPC();
manager.setCpu(deb);
}
}
DebugInterface *getDebugger() {
return debugger;
return debugger_;
}
void scrollStepping(u32 newPc);
@ -69,11 +72,11 @@ public:
setCurAddress(newAddress);
ScanVisibleFunctions();
}
void gotoPC() {
gotoAddr(debugger->GetPC());
void GotoPC() {
gotoAddr(debugger_->GetPC());
}
void gotoLR() {
gotoAddr(debugger->GetLR());
void GotoRA() {
gotoAddr(debugger_->GetRA());
}
u32 getSelection() {
return curAddress_;
@ -120,13 +123,6 @@ private:
ADDRESSES,
};
struct Rect {
float left;
float top;
float right;
float bottom;
};
void ProcessKeyboardShortcuts(bool focused);
void assembleOpcode(u32 address, const std::string &defaultText);
std::string disassembleRange(u32 start, u32 size);
@ -135,11 +131,10 @@ private:
void calculatePixelPositions();
bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData);
void updateStatusBarText();
void drawBranchLine(ImDrawList *list, ImDisasmView::Rect rc, std::map<u32, float> &addressPositions, const BranchLine &line);
void drawBranchLine(ImDrawList *list, Bounds rc, std::map<u32, float> &addressPositions, const BranchLine &line);
void CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode);
void NopInstructions(u32 startAddr, u32 endAddr);
std::set<std::string> getSelectedLineArguments();
void drawArguments(ImDrawList *list, ImDisasmView::Rect rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> &currentArguments);
void drawArguments(ImDrawList *list, Bounds rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> &currentArguments);
DisassemblyManager manager;
u32 curAddress_ = 0;
@ -152,7 +147,7 @@ private:
bool hasFocus_ = true;
bool showHex_ = false;
DebugInterface *debugger = nullptr;
DebugInterface *debugger_ = nullptr;
u32 windowStart_ = 0;
int visibleRows_ = 1;
@ -163,7 +158,7 @@ private:
int opcodeStart;
int argumentsStart;
int arrowsStart;
} pixelPositions_;
} pixelPositions_{};
std::vector<u32> jumpStack_;
@ -174,9 +169,8 @@ private:
bool mapReloaded_ = false;
int positionLocked_ = 0;
int lastSteppingCount_ = 0;
std::string statusBarText_;
u32 funcBegin_;
char funcNameTemp_[128];
u32 funcBegin_ = 0;
char funcNameTemp_[128]{};
};

View file

@ -14,6 +14,7 @@
#include "GPU/Debugger/State.h"
#include "GPU/Debugger/GECommandTable.h"
#include "GPU/Debugger/Breakpoints.h"
#include "GPU/Debugger/Stepping.h"
#include "GPU/Debugger/Debugger.h"
#include "GPU/GPUState.h"
@ -82,6 +83,12 @@ void DrawDebugStatsWindow(ImConfig &cfg) {
ImGui::End();
}
void ImGeDisasmView::NotifyStep() {
if (followPC_) {
gotoPC_ = true;
}
}
void ImGeDisasmView::Draw(GPUDebugInterface *gpuDebug) {
const u32 branchColor = 0xFFA0FFFF;
const u32 gteColor = 0xFFFFEFA0;
@ -123,7 +130,7 @@ void ImGeDisasmView::Draw(GPUDebugInterface *gpuDebug) {
}
if (pc != 0xFFFFFFFF) {
if (gotoPC_ || followPC_) {
if (gotoPC_) {
selectedAddr_ = pc;
gotoPC_ = false;
}
@ -238,7 +245,7 @@ void ImGeDisasmView::Draw(GPUDebugInterface *gpuDebug) {
void ImGeDebuggerWindow::Draw(ImConfig &cfg, ImControl &control, GPUDebugInterface *gpuDebug) {
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("GE Debugger", &cfg.geDebuggerOpen)) {
if (!ImGui::Begin(Title(), &cfg.geDebuggerOpen)) {
ImGui::End();
return;
}

View file

@ -28,6 +28,8 @@ public:
selectedAddr_ = addr;
}
void NotifyStep();
private:
u32 selectedAddr_ = INVALID_ADDR;
u32 dragAddr_ = INVALID_ADDR;
@ -52,6 +54,9 @@ public:
ImGeDisasmView &View() {
return disasmView_;
}
const char *Title() const {
return "GE Debugger";
}
private:
ImGeDisasmView disasmView_;

856
UI/ImDebugger/ImMemView.cpp Normal file
View file

@ -0,0 +1,856 @@
#include <cctype>
#include <cmath>
#include <iomanip>
#include <sstream>
#include "ext/imgui/imgui.h"
#include "ext/imgui/imgui_internal.h"
#include "ext/imgui/imgui_impl_thin3d.h"
#include "ext/xxhash.h"
#include "Common/StringUtils.h"
#include "Core/Config.h"
#include "Core/MemMap.h"
#include "Core/Reporting.h"
#include "Core/RetroAchievements.h"
#include "Common/System/Display.h"
#include "UI/ImDebugger/ImDebugger.h"
#include "UI/ImDebugger/ImMemView.h"
ImMemView::ImMemView() {
windowStart_ = curAddress_;
selectRangeStart_ = curAddress_;
selectRangeEnd_ = curAddress_ + 1;
lastSelectReset_ = curAddress_;
}
ImMemView::~ImMemView() {}
/*
LRESULT CALLBACK ImMemView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) {
ccp->ScrollWindow(-3, GotoModeFromModifiers(false));
} else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) {
ccp->ScrollWindow(3, GotoModeFromModifiers(false));
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
*/
static uint32_t pickTagColor(std::string_view tag) {
uint32_t colors[6] = { 0xFF301010, 0xFF103030, 0xFF403010, 0xFF103000, 0xFF301030, 0xFF101030 };
int which = XXH3_64bits(tag.data(), tag.length()) % ARRAY_SIZE(colors);
return colors[which];
}
void ImMemView::Draw(ImDrawList *drawList) {
if (!debugger_->isAlive()) {
return;
}
ImGui_PushFixedFont();
rowHeight_ = ImGui::GetTextLineHeightWithSpacing();
charWidth_ = ImGui::CalcTextSize("W", nullptr, false, -1.0f).x;
charHeight_ = ImGui::GetTextLineHeight();
offsetPositionY_ = offsetLine * rowHeight_;
addressStartX_ = charWidth_;
hexStartX_ = addressStartX_ + 9 * charWidth_;
asciiStartX_ = hexStartX_ + (rowSize_ * 3 + 1) * charWidth_;
const ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
const ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
const ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
// This will catch our interactions
bool pressed = ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
const bool is_hovered = ImGui::IsItemHovered(); // Hovered
const bool is_active = ImGui::IsItemActive(); // Held
if (pressed) {
// INFO_LOG(Log::System, "Pressed");
}
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
visibleRows_ = canvas_sz.y / rowHeight_;
if (displayOffsetScale_) {
// visibleRows_ is calculated based on the size of the control, but X rows have already been used for the offsets and are no longer usable
visibleRows_ -= offsetSpace;
}
Bounds bounds;
bounds.x = canvas_p0.x;
bounds.y = canvas_p0.y;
bounds.w = canvas_p1.x - canvas_p0.x;
bounds.h = canvas_p1.y - canvas_p0.y;
drawList->PushClipRect(canvas_p0, canvas_p1, true);
drawList->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(25, 25, 25, 255));
if (displayOffsetScale_)
drawOffsetScale(drawList);
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, windowStart_, (visibleRows_ + 1) * rowSize_);
_assert_msg_(((windowStart_ | rowSize_) & 3) == 0, "readMemory() can't handle unaligned reads");
// draw one extra row that may be partially visible
for (int i = 0; i < visibleRows_ + 1; i++) {
int rowY = rowHeight_ * i;
// Skip the first X rows to make space for the offsets.
if (displayOffsetScale_)
rowY += rowHeight_ * offsetSpace;
char temp[32];
uint32_t address = windowStart_ + i * rowSize_;
snprintf(temp, sizeof(temp), "%08X", address);
drawList->AddText(ImVec2(canvas_p0.x + addressStartX_, canvas_p0.y + rowY), IM_COL32(0xE0, 0xE0, 0xE0, 0xFF), temp);
union {
uint32_t words[4];
uint8_t bytes[16];
} memory;
int valid = debugger_ != nullptr && debugger_->isAlive() ? Memory::ValidSize(address, 16) / 4 : 0;
for (int i = 0; i < valid; ++i) {
memory.words[i] = debugger_->readMemory(address + i * 4);
}
for (int j = 0; j < rowSize_; j++) {
const uint32_t byteAddress = (address + j) & ~0xC0000000;
std::string_view tag;
bool tagContinues = false;
for (const auto &info : memRangeInfo) {
if (info.start <= byteAddress && info.start + info.size > byteAddress) {
tag = info.tag; // doesn't take ownership!
tagContinues = byteAddress + 1 < info.start + info.size;
}
}
int hexX = hexStartX_ + j * 3 * charWidth_;
int hexLen = 2;
int asciiX = asciiStartX_ + j * (charWidth_ + 2);
char c;
if (valid) {
snprintf(temp, sizeof(temp), "%02X ", memory.bytes[j]);
c = (char)memory.bytes[j];
if (memory.bytes[j] < 32 || memory.bytes[j] >= 128)
c = '.';
} else {
truncate_cpy(temp, "??");
c = '.';
}
ImColor standardBG = 0xFF000000;
bool continueRect = false;
ImColor hexBGCol = 0;
ImColor hexTextCol = 0xFFFFFFFF;
ImColor asciiBGCol = 0;
ImColor asciiTextCol = 0xFFFFFFFF;
int underline = -1;
const ImColor primarySelFg = 0xFFFFFFFF;
const ImColor primarySelBg = 0xFFFF9933;
const ImColor secondarySelFg = 0xFFFFFFFF;
const ImColor secondarySelBg = 0xFF808080;
if (address + j >= selectRangeStart_ && address + j < selectRangeEnd_ && !searching_) {
if (asciiSelected_) {
hexBGCol = secondarySelBg;
hexTextCol = secondarySelFg;
asciiBGCol = primarySelBg;
asciiTextCol = primarySelFg;
} else {
hexBGCol = primarySelBg;
hexTextCol = primarySelFg;
asciiBGCol = secondarySelBg;
asciiTextCol = secondarySelFg;
if (address + j == curAddress_)
underline = selectedNibble_;
}
if (!tag.empty() && tagContinues) {
continueRect = true;
}
} else if (!tag.empty()) {
hexBGCol = pickTagColor(tag);
continueRect = tagContinues;
asciiBGCol = hexBGCol;
}
ImColor fg = hexTextCol;
ImColor bg = hexBGCol;
// SelectObject(hdc, underline == 0 ? (HGDIOBJ)underlineFont : (HGDIOBJ)font);
if (bg != 0) {
int bgWidth = 2; // continueRect ? 3 : 2;
drawList->AddRectFilled(ImVec2(canvas_p0.x + hexX - 1, canvas_p0.y + rowY), ImVec2(canvas_p0.x + hexX + charWidth_ * bgWidth, canvas_p0.y + rowY + charHeight_), bg);
drawList->AddText(ImVec2(canvas_p0.x + hexX, canvas_p0.y + rowY), fg, &temp[0], &temp[2]);
}
if (underline >= 0) {
float x = canvas_p0.x + hexX + underline * charWidth_;
drawList->AddRectFilled(ImVec2(x, canvas_p0.y + rowY + charHeight_ - 2), ImVec2(x + charWidth_, canvas_p0.y + rowY + charHeight_), IM_COL32(0xFF, 0xFF, 0xFF, 0xFF));
}
fg = asciiTextCol;
bg = asciiBGCol;
drawList->AddRectFilled(ImVec2(canvas_p0.x + asciiX, canvas_p0.y + rowY), ImVec2(canvas_p0.x + asciiX + charWidth_, canvas_p0.y + rowY + charHeight_), bg);
drawList->AddText(ImVec2(canvas_p0.x + asciiX, canvas_p0.y + rowY), fg, &c, &c + 1);
}
}
ImGuiIO& io = ImGui::GetIO();
ImVec2 mousePos = ImVec2(io.MousePos.x - canvas_p0.x, io.MousePos.y - canvas_p0.y);
if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
// INFO_LOG(Log::System, "Mousedown %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
onMouseDown(mousePos.x, mousePos.y, 1);
}
if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
// INFO_LOG(Log::CPU, "Mousedown %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
onMouseDown(mousePos.x, mousePos.y, 2);
}
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
// INFO_LOG(Log::System, "Mouseup %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
if (is_hovered) {
onMouseUp(mousePos.x, mousePos.y, 1);
}
}
if (ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
// INFO_LOG(Log::System, "Mousedrag %f,%f active:%d hover:%d", mousePos.x, mousePos.y, is_active, is_hovered);
if (is_hovered) {
onMouseMove(mousePos.x, mousePos.y, 1);
}
}
if (is_hovered) {
if (io.MouseWheel > 0.0f) { // TODO: Scale steps by the value.
windowStart_ -= rowSize_ * 4;
} else if (io.MouseWheel < 0.0f) {
windowStart_ += rowSize_ * 4;
}
}
ProcessKeyboardShortcuts(ImGui::IsItemFocused());
ImGui_PopFont();
ImGui::OpenPopupOnItemClick("memcontext", ImGuiPopupFlags_MouseButtonRight);
PopupMenu();
drawList->PopClipRect();
}
// We don't have a scroll bar - though maybe we should build one.
/*
void ImMemView::onVScroll(WPARAM wParam, LPARAM lParam) {
switch (wParam & 0xFFFF) {
case SB_LINEDOWN:
ScrollWindow(1, GotoModeFromModifiers(false));
break;
case SB_LINEUP:
ScrollWindow(-1, GotoModeFromModifiers(false));
break;
case SB_PAGEDOWN:
ScrollWindow(visibleRows_, GotoModeFromModifiers(false));
break;
case SB_PAGEUP:
ScrollWindow(-visibleRows_, GotoModeFromModifiers(false));
break;
default:
return;
}
}
*/
void ImMemView::ProcessKeyboardShortcuts(bool focused) {
if (!focused) {
return;
}
ImGuiIO& io = ImGui::GetIO();
if (io.KeyMods & ImGuiMod_Ctrl) {
if (ImGui::IsKeyPressed(ImGuiKey_G)) {
/*
u32 addr;
if (executeExpressionWindow(wnd, debugger_, addr) == false)
return;
gotoAddr(addr);
return;
*/
}
if (ImGui::IsKeyPressed(ImGuiKey_F)) {
search(false);
}
if (ImGui::IsKeyPressed(ImGuiKey_C)) {
search(true);
}
} else {
if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
ScrollCursor(rowSize_, GotoModeFromModifiers(false));
}
if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
ScrollCursor(-rowSize_, GotoModeFromModifiers(false));
}
if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
ScrollCursor(-1, GotoModeFromModifiers(false));
}
if (ImGui::IsKeyPressed(ImGuiKey_RightArrow)) {
ScrollCursor(1, GotoModeFromModifiers(false));
}
if (ImGui::IsKeyPressed(ImGuiKey_PageDown)) {
ScrollWindow(visibleRows_, GotoModeFromModifiers(false));
}
if (ImGui::IsKeyPressed(ImGuiKey_PageUp)) {
ScrollWindow(-visibleRows_, GotoModeFromModifiers(false));
}
}
}
void ImMemView::onChar(int c) {
if (!PSP_IsInited())
return;
ImGuiIO& io = ImGui::GetIO();
if (io.KeyMods & ImGuiMod_Ctrl) {
return;
}
if (!Memory::IsValidAddress(curAddress_)) {
ScrollCursor(1, GotoMode::RESET);
return;
}
bool active = Core_IsActive();
if (active)
Core_Break("memory.access", curAddress_);
if (asciiSelected_) {
Memory::WriteUnchecked_U8((u8)c, curAddress_);
ScrollCursor(1, GotoMode::RESET);
} else {
c = tolower(c);
int inputValue = -1;
if (c >= '0' && c <= '9') inputValue = c - '0';
if (c >= 'a' && c <= 'f') inputValue = c - 'a' + 10;
if (inputValue >= 0) {
int shiftAmount = (1 - selectedNibble_) * 4;
u8 oldValue = Memory::ReadUnchecked_U8(curAddress_);
oldValue &= ~(0xF << shiftAmount);
u8 newValue = oldValue | (inputValue << shiftAmount);
Memory::WriteUnchecked_U8(newValue, curAddress_);
ScrollCursor(1, GotoMode::RESET);
}
}
Reporting::NotifyDebugger();
if (active)
Core_Resume();
}
ImMemView::GotoMode ImMemView::GotoModeFromModifiers(bool isRightClick) {
GotoMode mode = GotoMode::RESET;
auto &io = ImGui::GetIO();
if (isRightClick) {
mode = GotoMode::RESET_IF_OUTSIDE;
} else if (io.KeyMods & ImGuiMod_Shift) {
if (io.KeyMods & ImGuiMod_Ctrl)
mode = GotoMode::EXTEND;
else
mode = GotoMode::FROM_CUR;
}
return mode;
}
void ImMemView::onMouseDown(float x, float y, int button) {
if (Achievements::HardcoreModeActive())
return;
GotoPoint(x, y, GotoModeFromModifiers(button == 2));
}
void ImMemView::PopupMenu() {
if (ImGui::BeginPopup("memcontext")) {
int32_t selectedSize = selectRangeEnd_ - selectRangeStart_;
bool enable16 = !asciiSelected_ && (selectedSize == 1 || (selectedSize & 1) == 0);
bool enable32 = !asciiSelected_ && (selectedSize == 1 || (selectedSize & 3) == 0);
/*
if (ImGui::MenuItem("Dump memory")) {
DumpMemoryWindow dump(wnd, debugger_);
dump.exec();
break;
}
*/
if (ImGui::MenuItem("Copy value (8-bit)")) {
size_t tempSize = 3 * selectedSize + 1;
char *temp = new char[tempSize];
memset(temp, 0, tempSize);
// it's admittedly not really useful like this
if (asciiSelected_) {
for (uint32_t p = selectRangeStart_; p != selectRangeEnd_; ++p) {
uint8_t c = Memory::IsValidAddress(p) ? Memory::ReadUnchecked_U8(p) : '.';
if (c < 32 || c >= 128)
c = '.';
temp[p - selectRangeStart_] = c;
}
} else {
char *pos = temp;
for (uint32_t p = selectRangeStart_; p != selectRangeEnd_; ++p) {
uint8_t c = Memory::IsValidAddress(p) ? Memory::ReadUnchecked_U8(p) : 0xFF;
pos += snprintf(pos, tempSize - (pos - temp + 1), "%02X ", c);
}
// Clear the last space.
if (pos > temp)
*(pos - 1) = '\0';
}
System_CopyStringToClipboard(temp);
delete[] temp;
}
if (ImGui::MenuItem("Copy value (16-bit)")) {
size_t tempSize = 5 * ((selectedSize + 1) / 2) + 1;
char *temp = new char[tempSize];
memset(temp, 0, tempSize);
char *pos = temp;
for (uint32_t p = selectRangeStart_; p < selectRangeEnd_; p += 2) {
uint16_t c = Memory::IsValidRange(p, 2) ? Memory::ReadUnchecked_U16(p) : 0xFFFF;
pos += snprintf(pos, tempSize - (pos - temp + 1), "%04X ", c);
}
// Clear the last space.
if (pos > temp)
*(pos - 1) = '\0';
System_CopyStringToClipboard(temp);
delete[] temp;
}
if (ImGui::MenuItem("Copy value (32-bit)")) {
size_t tempSize = 9 * ((selectedSize + 3) / 4) + 1;
char *temp = new char[tempSize];
memset(temp, 0, tempSize);
char *pos = temp;
for (uint32_t p = selectRangeStart_; p < selectRangeEnd_; p += 4) {
uint32_t c = Memory::IsValidRange(p, 4) ? Memory::ReadUnchecked_U32(p) : 0xFFFFFFFF;
pos += snprintf(pos, tempSize - (pos - temp + 1), "%08X ", c);
}
// Clear the last space.
if (pos > temp)
*(pos - 1) = '\0';
System_CopyStringToClipboard(temp);
delete[] temp;
}
if (ImGui::MenuItem("Copy value (float32)")) {
char temp[64];
snprintf(temp, sizeof(temp), "%f", Memory::IsValidAddress(curAddress_) ? Memory::Read_Float(curAddress_) : NAN);
System_CopyStringToClipboard(temp);
}
/*
case ID_MEMVIEW_EXTENTBEGIN:
{
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress_, 1);
uint32_t addr = curAddress_;
for (MemBlockInfo info : memRangeInfo) {
addr = info.start;
}
gotoAddr(addr);
break;
}
case ID_MEMVIEW_EXTENTEND:
{
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress_, 1);
uint32_t addr = curAddress_;
for (MemBlockInfo info : memRangeInfo) {
addr = info.start + info.size - 1;
}
gotoAddr(addr);
break;
}
*/
if (ImGui::MenuItem("Copy address")) {
char temp[24];
snprintf(temp, sizeof(temp), "0x%08X", curAddress_);
System_CopyStringToClipboard(temp);
}
if (ImGui::MenuItem("Goto in disasm")) {
/*
if (disasmWindow) {
disasmWindow->Goto(curAddress_);
disasmWindow->Show(true);
}
*/
}
ImGui::EndPopup();
}
}
void ImMemView::onMouseUp(float x, float y, int button) {
if (button == 2) {
// HMENU menu = GetContextMenu(ContextMenuID::MEMVIEW);
// EnableMenuItem(menu, ID_MEMVIEW_COPYVALUE_16, enable16 ? MF_ENABLED : MF_GRAYED);
// EnableMenuItem(menu, ID_MEMVIEW_COPYVALUE_32, enable32 ? MF_ENABLED : MF_GRAYED);
// EnableMenuItem(menu, ID_MEMVIEW_COPYFLOAT_32, enable32 ? MF_ENABLED : MF_GRAYED);
}
/*
int x = LOWORD(lParam);
int y = HIWORD(lParam);
ReleaseCapture();
*/
GotoPoint(x, y, GotoModeFromModifiers(button == 2));
}
void ImMemView::onMouseMove(float x, float y, int button) {
if (Achievements::HardcoreModeActive())
return;
if (button & 1) {
GotoPoint(x, y, GotoModeFromModifiers(button == 2));
}
}
void ImMemView::updateStatusBarText() {
std::vector<MemBlockInfo> memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress_, 1);
char text[512];
snprintf(text, sizeof(text), "%08X", curAddress_);
// There should only be one.
for (MemBlockInfo info : memRangeInfo) {
snprintf(text, sizeof(text), "%08X - %s %08X-%08X (at PC %08X / %lld ticks)", curAddress_, info.tag.c_str(), info.start, info.start + info.size, info.pc, info.ticks);
}
statusMessage_ = text;
}
void ImMemView::UpdateSelectRange(uint32_t target, GotoMode mode) {
if (mode == GotoMode::FROM_CUR && lastSelectReset_ == 0) {
lastSelectReset_ = curAddress_;
}
switch (mode) {
case GotoMode::RESET:
selectRangeStart_ = target;
selectRangeEnd_ = target + 1;
lastSelectReset_ = target;
break;
case GotoMode::RESET_IF_OUTSIDE:
if (target < selectRangeStart_ || target >= selectRangeEnd_) {
selectRangeStart_ = target;
selectRangeEnd_ = target + 1;
lastSelectReset_ = target;
}
break;
case GotoMode::FROM_CUR:
selectRangeStart_ = lastSelectReset_ > target ? target : lastSelectReset_;
selectRangeEnd_ = selectRangeStart_ == lastSelectReset_ ? target + 1 : lastSelectReset_ + 1;
break;
case GotoMode::EXTEND:
if (target < selectRangeStart_)
selectRangeStart_ = target;
if (target > selectRangeEnd_)
selectRangeEnd_ = target;
break;
}
curAddress_ = target;
}
void ImMemView::GotoPoint(int x, int y, GotoMode mode) {
int line = y / rowHeight_;
int lineAddress = windowStart_ + line * rowSize_;
if (displayOffsetScale_) {
// ignore clicks on the offset space
if (line < offsetSpace) {
updateStatusBarText();
return;
}
// since each row has been written X rows down from where the window expected it to be written the target of the clicks must be adjusted
lineAddress -= rowSize_ * offsetSpace;
}
uint32_t target = curAddress_;
uint32_t targetNibble = selectedNibble_;
bool targetAscii = asciiSelected_;
if (x >= asciiStartX_) {
int col = (x - asciiStartX_) / (charWidth_ + 2);
if (col >= rowSize_)
return;
targetAscii = true;
target = lineAddress + col;
targetNibble = 0;
} else if (x >= hexStartX_) {
int col = (x - hexStartX_) / charWidth_;
if ((col / 3) >= rowSize_)
return;
switch (col % 3) {
case 0: targetNibble = 0; break;
case 1: targetNibble = 1; break;
// case 2: return; // don't change position when clicking on the space
case 2: targetNibble = 0; break; // TODO: split the difference? Anyway, this feels better.
}
targetAscii = false;
target = lineAddress + col / 3;
}
if (target != curAddress_ || targetNibble != selectedNibble_ || targetAscii != asciiSelected_) {
selectedNibble_ = targetNibble;
asciiSelected_ = targetAscii;
UpdateSelectRange(target, mode);
updateStatusBarText();
}
}
void ImMemView::gotoAddr(unsigned int addr) {
int lines = visibleRows_;
u32 windowEnd = windowStart_ + lines * rowSize_;
curAddress_ = addr;
lastSelectReset_ = curAddress_;
selectRangeStart_ = curAddress_;
selectRangeEnd_ = curAddress_ + 1;
selectedNibble_ = 0;
if (curAddress_ < windowStart_ || curAddress_ >= windowEnd) {
windowStart_ = curAddress_ & ~15;
}
updateStatusBarText();
}
void ImMemView::ScrollWindow(int lines, GotoMode mode) {
windowStart_ += lines * rowSize_;
UpdateSelectRange(curAddress_ + lines * rowSize_, mode);
updateStatusBarText();
}
void ImMemView::ScrollCursor(int bytes, GotoMode mode) {
if (!asciiSelected_ && bytes == 1) {
if (selectedNibble_ == 0) {
selectedNibble_ = 1;
bytes = 0;
} else {
selectedNibble_ = 0;
}
} else if (!asciiSelected_ && bytes == -1) {
if (selectedNibble_ == 0) {
selectedNibble_ = 1;
} else {
selectedNibble_ = 0;
bytes = 0;
}
}
UpdateSelectRange(curAddress_ + bytes, mode);
u32 windowEnd = windowStart_ + visibleRows_ * rowSize_;
if (curAddress_ < windowStart_) {
windowStart_ = curAddress_ & ~15;
} else if (curAddress_ >= windowEnd) {
windowStart_ = (curAddress_ - (visibleRows_ - 1) * rowSize_) & ~15;
}
updateStatusBarText();
}
bool ImMemView::ParseSearchString(const std::string &query, bool asHex, std::vector<uint8_t> &data) {
data.clear();
if (!asHex) {
for (size_t i = 0; i < query.length(); i++) {
data.push_back(query[i]);
}
return true;
}
for (size_t index = 0; index < query.size(); ) {
if (isspace(query[index])) {
index++;
continue;
}
u8 value = 0;
for (int i = 0; i < 2 && index < query.size(); i++) {
char c = tolower(query[index++]);
if (c >= 'a' && c <= 'f') {
value |= (c - 'a' + 10) << (1 - i) * 4;
} else if (c >= '0' && c <= '9') {
value |= (c - '0') << (1 - i) * 4;
} else {
return false;
}
}
data.push_back(value);
}
return true;
}
std::vector<u32> ImMemView::searchString(const std::string &searchQuery) {
std::vector<u32> searchResAddrs;
if (!PSP_IsInited())
return searchResAddrs;
std::vector<u8> searchData;
if (!ParseSearchString(searchQuery, false, searchData))
return searchResAddrs;
if (searchData.empty())
return searchResAddrs;
std::vector<std::pair<u32, u32>> memoryAreas;
memoryAreas.emplace_back(PSP_GetScratchpadMemoryBase(), PSP_GetScratchpadMemoryEnd());
// Ignore the video memory mirrors.
memoryAreas.emplace_back(PSP_GetVidMemBase(), 0x04200000);
memoryAreas.emplace_back(PSP_GetKernelMemoryBase(), PSP_GetUserMemoryEnd());
for (const auto &area : memoryAreas) {
const u32 segmentStart = area.first;
const u32 segmentEnd = area.second - (u32)searchData.size();
for (u32 pos = segmentStart; pos < segmentEnd; pos++) {
if ((pos % 256) == 0 && ImGui::IsKeyDown(ImGuiKey_Escape)) {
return searchResAddrs;
}
const u8 *ptr = Memory::GetPointerUnchecked(pos);
if (memcmp(ptr, searchData.data(), searchData.size()) == 0) {
searchResAddrs.push_back(pos);
}
}
}
return searchResAddrs;
};
void ImMemView::search(bool continueSearch) {
/*
if (!PSP_IsInited())
return;
u32 searchAddress = 0;
u32 segmentStart = 0;
u32 segmentEnd = 0;
if (continueSearch == false || searchQuery_.empty()) {
if (InputBox_GetString(GetModuleHandle(NULL), wnd, L"Search for", searchQuery_, searchQuery_) == false) {
SetFocus(wnd);
return;
}
SetFocus(wnd);
searchAddress = curAddress_ + 1;
} else {
searchAddress = matchAddress_ + 1;
}
std::vector<u8> searchData;
if (!ParseSearchString(searchQuery_, !asciiSelected_, searchData)) {
statusMessage_ = "Invalid search text.";
return;
}
std::vector<std::pair<u32, u32>> memoryAreas;
// Ignore the video memory mirrors.
memoryAreas.emplace_back(PSP_GetVidMemBase(), 0x04200000);
memoryAreas.emplace_back(PSP_GetKernelMemoryBase(), PSP_GetUserMemoryEnd());
memoryAreas.emplace_back(PSP_GetScratchpadMemoryBase(), PSP_GetScratchpadMemoryEnd());
searching_ = true;
redraw(); // so the cursor is disabled
for (size_t i = 0; i < memoryAreas.size(); i++) {
segmentStart = memoryAreas[i].first;
segmentEnd = memoryAreas[i].second;
// better safe than sorry, I guess
if (!Memory::IsValidAddress(segmentStart))
continue;
const u8 *dataPointer = Memory::GetPointerUnchecked(segmentStart);
if (searchAddress < segmentStart)
searchAddress = segmentStart;
if (searchAddress >= segmentEnd)
continue;
int index = searchAddress - segmentStart;
int endIndex = segmentEnd - segmentStart - (int)searchData.size();
while (index < endIndex) {
// cancel search
if ((index % 256) == 0 && ImGui::IsKeyDown(ImGuiKey_Escape)) {
searching_ = false;
return;
}
if (memcmp(&dataPointer[index], searchData.data(), searchData.size()) == 0) {
matchAddress_ = index + segmentStart;
searching_ = false;
gotoAddr(matchAddress_);
return;
}
index++;
}
}
statusMessage_ = "Not found";
searching_ = false;
redraw();
*/
}
void ImMemView::drawOffsetScale(ImDrawList *drawList) {
int currentX = addressStartX_;
drawList->AddText(ImVec2(currentX, offsetPositionY_), 0xFF600000, "Offset");
// SetTextColor(hdc, 0x600000);
// TextOutA(hdc, currentX, offsetPositionY_, "Offset", 6);
// the start offset, the size of the hex addresses and one space
currentX = addressStartX_ + ((8 + 1) * charWidth_);
char temp[64];
for (int i = 0; i < 16; i++) {
snprintf(temp, sizeof(temp), "%02X", i);
drawList->AddText(ImVec2(currentX, offsetPositionY_), 0xFF600000, temp);
currentX += 3 * charWidth_; // hex and space
}
}
void ImMemView::toggleOffsetScale(CommonToggles toggle) {
if (toggle == On)
displayOffsetScale_ = true;
else if (toggle == Off)
displayOffsetScale_ = false;
updateStatusBarText();
}
void ImMemView::setHighlightType(MemBlockFlags flags) {
if (highlightFlags_ != flags) {
highlightFlags_ = flags;
updateStatusBarText();
}
}

120
UI/ImDebugger/ImMemView.h Normal file
View file

@ -0,0 +1,120 @@
#pragma once
#include <cstdint>
#include <vector>
#include "ext/imgui/imgui.h"
#include "Core/Debugger/DebugInterface.h"
#include "Core/Debugger/MemBlockInfo.h"
enum OffsetSpacing {
offsetSpace = 3, // the number of blank lines that should be left to make space for the offsets
offsetLine = 1, // the line on which the offsets should be written
};
enum CommonToggles {
On,
Off,
};
class ImMemView {
public:
ImMemView();
~ImMemView();
void setDebugger(DebugInterface *deb) {
debugger_ = deb;
}
DebugInterface *getDebugger() {
return debugger_;
}
std::vector<u32> searchString(const std::string &searchQuery);
void Draw(ImDrawList *drawList);
// void onVScroll(WPARAM wParam, LPARAM lParam);
// void onKeyDown(WPARAM wParam, LPARAM lParam);
void onChar(int c);
void onMouseDown(float x, float y, int button);
void onMouseUp(float x, float y, int button);
void onMouseMove(float x, float y, int button);
void gotoAddr(unsigned int addr);
void drawOffsetScale(ImDrawList *drawList);
void toggleOffsetScale(CommonToggles toggle);
void setHighlightType(MemBlockFlags flags);
const std::string &StatusMessage() const {
return statusMessage_;
}
private:
void ProcessKeyboardShortcuts(bool focused);
bool ParseSearchString(const std::string &query, bool asHex, std::vector<uint8_t> &data);
void updateStatusBarText();
void search(bool continueSearch);
enum class GotoMode {
RESET,
RESET_IF_OUTSIDE,
FROM_CUR,
EXTEND,
};
static GotoMode GotoModeFromModifiers(bool isRightClick);
void UpdateSelectRange(uint32_t target, GotoMode mode);
void GotoPoint(int x, int y, GotoMode mode);
void ScrollWindow(int lines, GotoMode mdoe);
void ScrollCursor(int bytes, GotoMode mdoe);
void PopupMenu();
static wchar_t szClassName[];
DebugInterface *debugger_ = nullptr;
MemBlockFlags highlightFlags_ = MemBlockFlags::ALLOC;
// Current cursor position.
uint32_t curAddress_ = 0x08800000;
// Selected range, which should always be around the cursor.
uint32_t selectRangeStart_ = 0;
uint32_t selectRangeEnd_ = 0;
// Last select reset position, for selecting ranges.
uint32_t lastSelectReset_ = 0;
// Address of the first displayed byte.
uint32_t windowStart_ = 0x08800000;
// Number of bytes displayed per row.
int rowSize_ = 16;
// Width of one monospace character (to maintain grid.)
int charWidth_ = 0;
// Height of one monospace character (to maintain grid.)
int charHeight_ = 0;
// Height of one row of bytes.
int rowHeight_ = 0;
// Y position of offset header (at top.)
int offsetPositionY_ = 0;
// X position of addresses (at left.)
int addressStartX_ = 0;
// X position of hex display.
int hexStartX_ = 0;
// X position of text display.
int asciiStartX_ = 0;
// Whether cursor is within text display or hex display.
bool asciiSelected_ = false;
// Which nibble is selected, if in hex display. 0 means leftmost, i.e. most significant.
int selectedNibble_ = 0;
bool displayOffsetScale_ = false;
// Number of rows visible as of last redraw.
int visibleRows_ = 0;
// Last used search query, used when continuing a search.
std::string searchQuery_;
// Address of last match when continuing search.
uint32_t matchAddress_ = 0xFFFFFFFF;
// Whether a search is in progress.
bool searching_ = false;
std::string statusMessage_;
};

View file

@ -54,6 +54,7 @@
<ClCompile Include="ImDebugger\ImDebugger.cpp" />
<ClCompile Include="ImDebugger\ImDisasmView.cpp" />
<ClCompile Include="ImDebugger\ImGe.cpp" />
<ClCompile Include="ImDebugger\ImMemView.cpp" />
<ClCompile Include="ImDebugger\ImStructViewer.cpp" />
<ClCompile Include="JitCompareScreen.cpp" />
<ClCompile Include="JoystickHistoryView.cpp" />
@ -98,6 +99,7 @@
<ClInclude Include="ImDebugger\ImDebugger.h" />
<ClInclude Include="ImDebugger\ImDisasmView.h" />
<ClInclude Include="ImDebugger\ImGe.h" />
<ClInclude Include="ImDebugger\ImMemView.h" />
<ClInclude Include="ImDebugger\ImStructViewer.h" />
<ClInclude Include="JitCompareScreen.h" />
<ClInclude Include="JoystickHistoryView.h" />

View file

@ -110,6 +110,9 @@
<ClCompile Include="ImDebugger\ImGe.cpp">
<Filter>ImDebugger</Filter>
</ClCompile>
<ClCompile Include="ImDebugger\ImMemView.cpp">
<Filter>ImDebugger</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="GameInfoCache.h" />
@ -220,6 +223,9 @@
<ClInclude Include="ImDebugger\ImGe.h">
<Filter>ImDebugger</Filter>
</ClInclude>
<ClInclude Include="ImDebugger\ImMemView.h">
<Filter>ImDebugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Screens">

View file

@ -129,6 +129,7 @@
<ClInclude Include="..\..\UI\ImDebugger\ImDebugger.h" />
<ClInclude Include="..\..\UI\ImDebugger\ImDisasmView.h" />
<ClInclude Include="..\..\UI\ImDebugger\ImGe.h" />
<ClInclude Include="..\..\UI\ImDebugger\ImMemView.h" />
<ClInclude Include="..\..\UI\ImDebugger\ImStructViewer.h" />
<ClInclude Include="..\..\UI\InstallZipScreen.h" />
<ClInclude Include="..\..\UI\JitCompareScreen.h" />
@ -173,6 +174,7 @@
<ClCompile Include="..\..\UI\ImDebugger\ImDebugger.cpp" />
<ClCompile Include="..\..\UI\ImDebugger\ImDisasmView.cpp" />
<ClCompile Include="..\..\UI\ImDebugger\ImGe.cpp" />
<ClCompile Include="..\..\UI\ImDebugger\ImMemView.cpp" />
<ClCompile Include="..\..\UI\ImDebugger\ImStructViewer.cpp" />
<ClCompile Include="..\..\UI\InstallZipScreen.cpp" />
<ClCompile Include="..\..\UI\JitCompareScreen.cpp" />

View file

@ -51,6 +51,9 @@
<ClCompile Include="..\..\UI\ImDebugger\ImGe.cpp">
<Filter>ImDebugger</Filter>
</ClCompile>
<ClCompile Include="..\..\UI\ImDebugger\ImMemView.cpp">
<Filter>ImDebugger</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@ -103,6 +106,9 @@
<ClInclude Include="..\..\UI\ImDebugger\ImGe.h">
<Filter>ImDebugger</Filter>
</ClInclude>
<ClInclude Include="..\..\UI\ImDebugger\ImMemView.h">
<Filter>ImDebugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="ImDebugger">

View file

@ -1,16 +1,10 @@
#pragma once
//////////////////////////////////////////////////////////////////////////
//CtrlDisAsmView
// CtrlDisAsmView.cpp
// CtrlMemView
//////////////////////////////////////////////////////////////////////////
//This Win32 control is made to be flexible and usable with
//every kind of CPU architecture that has fixed width instruction words.
//Just supply it an instance of a class derived from Debugger, with all methods
//overridden for full functionality.
//
//To add to a dialog box, just draw a User Control in the dialog editor,
//and set classname to "CtrlDisAsmView". you also need to call CtrlDisAsmView::init()
//and set classname to "CtrlMemView". you also need to call CtrlMemView::init()
//before opening this dialog, to register the window class.
//
//To get a class instance to be able to access it, just use getFrom(HWND wnd).

View file

@ -444,9 +444,9 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {
UpdateDialog();
}
break;
case IDC_GOTOLR:
case IDC_GOTORA:
{
ptr->gotoAddr(cpu->GetLR());
ptr->gotoAddr(cpu->GetRA());
SetFocus(GetDlgItem(m_hDlg, IDC_DISASMVIEW));
}
break;
@ -696,7 +696,7 @@ void CDisasm::SetDebugMode(bool _bDebug, bool switchPC)
EnableWindow(GetDlgItem(hDlg, IDC_STEPHLE), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_STEPOUT), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_GOTOPC), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_GOTOLR), TRUE);
EnableWindow(GetDlgItem(hDlg, IDC_GOTORA), TRUE);
CtrlDisAsmView *ptr = DisAsmView();
ptr->setDontRedraw(false);
if (switchPC)
@ -715,7 +715,7 @@ void CDisasm::SetDebugMode(bool _bDebug, bool switchPC)
EnableWindow(GetDlgItem(hDlg, IDC_STEPHLE), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_STEPOUT), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_GOTOPC), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_GOTOLR), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_GOTORA), FALSE);
CtrlRegisterList *reglist = CtrlRegisterList::getFrom(GetDlgItem(m_hDlg,IDC_REGLIST));
reglist->redraw();
}

View file

@ -180,7 +180,7 @@ BEGIN
EDITTEXT IDC_THREADNAME,370,3,150,10,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_ADDRESS,11,24,91,13,ES_AUTOHSCROLL | ES_WANTRETURN
PUSHBUTTON "PC",IDC_GOTOPC,11,40,15,13
PUSHBUTTON "RA",IDC_GOTOLR,28,40,14,13
PUSHBUTTON "RA",IDC_GOTORA,28,40,14,13
COMBOBOX IDC_GOTOINT,43,40,60,76,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Custom1",IDC_DISASMVIEW,"CtrlDisAsmView",WS_BORDER | WS_TABSTOP,111,16,397,304
GROUPBOX "Go to",IDC_STATIC,5,12,102,47

View file

@ -70,7 +70,7 @@
#define IDC_STEP 1009
#define IDC_VERSION 1010
#define IDC_MEMVIEW 1069
#define IDC_GOTOLR 1070
#define IDC_GOTORA 1070
#define IDC_GOTOINT 1071
#define IDC_MEMSORT 1073
#define IDC_SYMBOLS 1097

View file

@ -879,6 +879,7 @@ LOCAL_SRC_FILES := \
$(SRC)/UI/ImDebugger/ImDebugger.cpp \
$(SRC)/UI/ImDebugger/ImGe.cpp \
$(SRC)/UI/ImDebugger/ImDisasmView.cpp \
$(SRC)/UI/ImDebugger/ImMemView.cpp \
$(SRC)/UI/ImDebugger/ImStructViewer.cpp \
$(SRC)/UI/AudioCommon.cpp \
$(SRC)/UI/BackgroundAudio.cpp \

View file

@ -313,6 +313,10 @@ void ImGui_PopFont() {
ImGui::PopFont();
}
ImFont *ImGui_GetFixedFont() {
return g_fixedFont;
}
void ImGui_ImplThin3d_Shutdown() {
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");

View file

@ -55,6 +55,10 @@ IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddFBAsTextureTemp(Draw::Framebuffer
void ImGui_PushFixedFont();
void ImGui_PopFont();
// To get metrics etc.
ImFont *ImGui_GetFixedFont();
// Helper structure to hold the data needed by one rendering context into one OS window
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
struct ImGui_ImplThin3dH_Window {