From 08d251b5bc5156561835130bd297115a3c193686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 9 Jan 2025 13:14:13 +0100 Subject: [PATCH] Add a memory dump window --- UI/ImDebugger/ImDebugger.cpp | 18 +++++++++++++ UI/ImDebugger/ImDebugger.h | 4 +++ UI/ImDebugger/ImDisasmView.cpp | 7 ++--- UI/ImDebugger/ImMemView.cpp | 49 ++++++++++++++++++++++++++++++++++ UI/ImDebugger/ImMemView.h | 28 +++++++++++++++++++ 5 files changed, 103 insertions(+), 3 deletions(-) diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index e80be8586c..4b3418472b 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -56,6 +56,12 @@ void ShowInMemoryViewerMenuItem(uint32_t addr, ImControl &control) { } } +void ShowInMemoryDumperMenuItem(uint32_t addr, uint32_t size, MemDumpMode mode, ImControl &control) { + if (ImGui::MenuItem(mode == MemDumpMode::Raw ? "Dump bytes to file..." : "Disassemble to file...")) { + control.command = { ImCmd::SHOW_IN_MEMORY_DUMPER, addr, size }; + } +} + void ShowInWindowMenuItems(uint32_t addr, ImControl &control) { // Enable when we implement the memory viewer ShowInMemoryViewerMenuItem(addr, control); @@ -1112,6 +1118,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu snprintf(title, sizeof(title), "Memory %d", i + 1); ImGui::MenuItem(title, nullptr, &cfg_.memViewOpen[i]); } + ImGui::MenuItem("Memory Dumper", nullptr, &cfg_.memDumpOpen); ImGui::EndMenu(); } if (ImGui::BeginMenu("HLE")) { @@ -1253,6 +1260,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu pixelViewer_.Draw(cfg_, control, gpuDebug, draw); } + if (cfg_.memDumpOpen) { + memDumpWindow_.Draw(cfg_); + } + for (int i = 0; i < 4; i++) { if (cfg_.memViewOpen[i]) { mem_[i].Draw(mipsDebug, cfg_, control, i); @@ -1288,6 +1299,13 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu ImGui::SetWindowFocus(ImMemWindow::Title(index)); break; } + case ImCmd::SHOW_IN_MEMORY_DUMPER: + { + cfg_.memDumpOpen = true; + memDumpWindow_.SetRange(control.command.param, control.command.param2); + ImGui::SetWindowFocus(memDumpWindow_.Title()); + break; + } case ImCmd::TRIGGER_FIND_POPUP: // TODO break; diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index b9d621e6d3..d85d27e6c2 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -143,6 +143,7 @@ struct ImConfig { bool pixelViewerOpen; bool npOpen; bool socketsOpen; + bool memDumpOpen; bool memViewOpen[4]; // HLE explorer settings @@ -175,6 +176,7 @@ enum class ImCmd { SHOW_IN_GE_DISASM, SHOW_IN_MEMORY_VIEWER, // param is address, param2 is viewer index SHOW_IN_PIXEL_VIEWER, // param is address, param2 is stride, |0x80000000 if depth, param3 is w/h + SHOW_IN_MEMORY_DUMPER, // param is address, param2 is size, param3 is mode }; struct ImCommand { @@ -211,6 +213,7 @@ private: ImMemWindow mem_[4]; // We support 4 separate instances of the memory viewer. ImStructViewer structViewer_; ImGePixelViewerWindow pixelViewer_; + ImMemDumpWindow memDumpWindow_; ImSnapshotState newSnapshot_; ImSnapshotState snapshot_; @@ -226,4 +229,5 @@ private: void ImClickableAddress(uint32_t addr, ImControl &control, ImCmd cmd); void ShowInWindowMenuItems(uint32_t addr, ImControl &control); void ShowInMemoryViewerMenuItem(uint32_t addr, ImControl &control); +void ShowInMemoryDumperMenuItem(uint32_t addr, uint32_t size, MemDumpMode mode, ImControl &control); void StatusBar(std::string_view str); diff --git a/UI/ImDebugger/ImDisasmView.cpp b/UI/ImDebugger/ImDisasmView.cpp index 49b5901682..3fd883e480 100644 --- a/UI/ImDebugger/ImDisasmView.cpp +++ b/UI/ImDebugger/ImDisasmView.cpp @@ -830,9 +830,9 @@ void ImDisasmView::PopupMenu(ImControl &control) { statusBarText_ = "WARNING: unable to find function symbol here"; } } + u32 prevBegin = g_symbolMap->GetFunctionStart(curAddress_); if (ImGui::MenuItem("Add function")) { char statusBarTextBuff[256]; - u32 prevBegin = g_symbolMap->GetFunctionStart(curAddress_); if (prevBegin != -1) { if (prevBegin == curAddress_) { snprintf(statusBarTextBuff, 256, "WARNING: There's already a function entry point at this adress"); @@ -861,8 +861,9 @@ void ImDisasmView::PopupMenu(ImControl &control) { mapReloaded_ = true; } } - if (ImGui::MenuItem("Disassemble to file")) { - disassembleToFile(); + if (prevBegin != -1) { + u32 prevSize = g_symbolMap->GetFunctionSize(prevBegin); + ShowInMemoryDumperMenuItem(prevBegin, prevSize, MemDumpMode::Disassembly, control); } ImGui::EndPopup(); } diff --git a/UI/ImDebugger/ImMemView.cpp b/UI/ImDebugger/ImMemView.cpp index 6a42948306..436690c038 100644 --- a/UI/ImDebugger/ImMemView.cpp +++ b/UI/ImDebugger/ImMemView.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "ext/imgui/imgui.h" @@ -9,6 +10,7 @@ #include "ext/xxhash.h" #include "Common/StringUtils.h" +#include "Common/File/FileUtil.h" #include "Core/Config.h" #include "Core/MemMap.h" #include "Core/Reporting.h" @@ -838,3 +840,50 @@ void ImMemView::setHighlightType(MemBlockFlags flags) { updateStatusBarText(); } } + +void ImMemDumpWindow::Draw(ImConfig &cfg) { + ImGui::SetNextWindowSize(ImVec2(200, 300), ImGuiCond_FirstUseEver); + + if (!ImGui::Begin(Title(), &cfg.memDumpOpen)) { + ImGui::End(); + return; + } + + if (ImGui::Button("User RAM (0x08800000)")) { + address_ = 0x08800000; + size_ = 0x01800000; // 24MB + } + + ImGui::InputScalar("Starting address: ", ImGuiDataType_U32, &address_, NULL, NULL, "%08X"); + ImGui::InputScalar("Size: ", ImGuiDataType_U32, &size_, NULL, NULL, "%08X"); + + ImGui::InputText("Filename: ", filename_, ARRAY_SIZE(filename_)); + + if (ImGui::Button("Dump!")) { + uint32_t validSize = Memory::ValidSize(address_, size_); + if (validSize != size_) { + errorMsg_ = "Address range out of bounds"; + if (Memory::IsValidAddress(address_)) { + size_ = validSize; + } + } else if (strlen(filename_) == 0) { + errorMsg_ = "Please specify a valid filename"; + } else { + FILE *file = File::OpenCFile(Path(filename_), "wb"); + if (!file) { + errorMsg_ = "Couldn't open file for writing"; + } else { + const uint8_t *ptr = Memory::GetPointer(address_); + fwrite(ptr, 1, size_, file); + fclose(file); + errorMsg_.clear(); + } + } + } + + if (!errorMsg_.empty()) { + ImGui::TextUnformatted(errorMsg_.data(), errorMsg_.data() + errorMsg_.size()); + } + + ImGui::End(); +} diff --git a/UI/ImDebugger/ImMemView.h b/UI/ImDebugger/ImMemView.h index e0235f2517..5e2c7de520 100644 --- a/UI/ImDebugger/ImMemView.h +++ b/UI/ImDebugger/ImMemView.h @@ -118,3 +118,31 @@ private: std::string statusMessage_; }; + +enum class MemDumpMode { + Raw = 0, + Disassembly = 1, +}; + +class ImMemDumpWindow { +public: + ImMemDumpWindow() { + filename_[0] = 0; + address_ = 0x08800000; + size_ = 0x01800000; + } + static const char *Title() { + return "Memory Dumper"; + } + void Draw(ImConfig &cfg); + void SetRange(uint32_t addr, uint32_t size) { + address_ = addr; + size_ = size; + } + +private: + uint32_t address_; + uint32_t size_; + char filename_[1024]; + std::string errorMsg_; +};