mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #19720 from hrydgard/imgui-memview
ImDebugger: Add memory viewer window
This commit is contained in:
commit
07e6c35532
25 changed files with 1283 additions and 151 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> ¤tArguments) {
|
||||
void ImDisasmView::drawArguments(ImDrawList *drawList, Bounds rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> ¤tArguments) {
|
||||
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()) {
|
||||
|
|
|
@ -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> ¤tArguments);
|
||||
void drawArguments(ImDrawList *list, Bounds rc, const DisassemblyLineInfo &line, float x, float y, ImColor textColor, const std::set<std::string> ¤tArguments);
|
||||
|
||||
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]{};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
856
UI/ImDebugger/ImMemView.cpp
Normal 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
120
UI/ImDebugger/ImMemView.h
Normal 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_;
|
||||
};
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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?");
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue