diff --git a/UI/ImDebugger/ImCommand.h b/UI/ImDebugger/ImCommand.h index 978a4eb881..d488de9760 100644 --- a/UI/ImDebugger/ImCommand.h +++ b/UI/ImDebugger/ImCommand.h @@ -10,6 +10,7 @@ enum class ImCmd { 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 + SHOW_IN_BREAKPOINTS, // no params, just opens and focuses the breakpoint list }; struct ImCommand { diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 33304a6f69..df86bb6b5c 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -2934,6 +2934,12 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: ImGui::SetWindowFocus(ImMemWindow::Title(index)); break; } + case ImCmd::SHOW_IN_BREAKPOINTS: + { + cfg_.breakpointsOpen = true; + ImGui::SetWindowFocus("Breakpoints"); + break; + } case ImCmd::SHOW_IN_MEMORY_DUMPER: { cfg_.memDumpOpen = true; diff --git a/UI/ImDebugger/ImMemView.cpp b/UI/ImDebugger/ImMemView.cpp index ce182b664d..85da5f27ab 100644 --- a/UI/ImDebugger/ImMemView.cpp +++ b/UI/ImDebugger/ImMemView.cpp @@ -16,6 +16,8 @@ #include "Core/Reporting.h" #include "Core/RetroAchievements.h" #include "Common/System/Display.h" +#include "Common/System/System.h" +#include "Core/Debugger/Breakpoints.h" #include "Core/System.h" #include "UI/ImDebugger/ImDebugger.h" @@ -587,6 +589,33 @@ void ImMemView::onMouseMove(float x, float y, int button) { } } +// Everything the block list knows about a block, in a form worth pasting into a bug report. +// Deliberately more than the status bar shows - the whole reason to copy it is to keep it. +static std::string DescribeMemBlockInfo(const MemBlockInfo &info) { + std::string flags; + auto addFlag = [&flags, &info](MemBlockFlags flag, const char *name) { + if ((uint32_t)(info.flags & flag) == 0) + return; + if (!flags.empty()) + flags += "|"; + flags += name; + }; + addFlag(MemBlockFlags::ALLOC, "ALLOC"); + addFlag(MemBlockFlags::FREE, "FREE"); + addFlag(MemBlockFlags::SUB_ALLOC, "SUB_ALLOC"); + addFlag(MemBlockFlags::SUB_FREE, "SUB_FREE"); + addFlag(MemBlockFlags::WRITE, "WRITE"); + addFlag(MemBlockFlags::READ, "READ"); + addFlag(MemBlockFlags::TEXTURE, "TEXTURE"); + if (flags.empty()) + flags = "none"; + + return StringFromFormat( + "%s\n%08x-%08x (%d bytes)\nPC: %08x\nTicks: %lld\nFlags: %s\nAllocated: %s\n", + info.tag.c_str(), info.start, info.start + info.size, (int)info.size, info.pc, + (long long)info.ticks, flags.c_str(), info.allocated ? "yes" : "no"); +} + void ImMemView::updateStatusBarText() { std::vector memRangeInfo = FindMemInfoByFlag(highlightFlags_, curAddress_, 1); char text[512]; @@ -1141,6 +1170,20 @@ void ImMemWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl & cfg.selectedMemoryBlock = iter.start; GotoAddr(iter.start); } + if (ImGui::BeginPopupContextItem("blockinfo")) { + ImGui::TextUnformatted(iter.tag.c_str()); + ImGui::Separator(); + if (ImGui::MenuItem("Copy info to clipboard")) { + System_CopyStringToClipboard(DescribeMemBlockInfo(iter)); + } + if (ImGui::MenuItem("Add memory breakpoint")) { + // Covers the whole block rather than a single address - the point of doing + // this from the block list is to catch anything touching the allocation. + g_breakpoints.AddMemCheck(iter.start, iter.start + iter.size, MEMCHECK_READWRITE, BREAK_ACTION_PAUSE | BREAK_ACTION_LOG); + control.command = { ImCmd::SHOW_IN_BREAKPOINTS }; + } + ImGui::EndPopup(); + } ImGui::PopID(); } const u32 end = start + len;