From 330a63828148cdf2da7248d30f610471a41ee6b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 9 Feb 2026 19:26:43 +0100 Subject: [PATCH] Add ability to copy function hash from the disassembly view See #4179 --- Core/MIPS/MIPSAnalyst.cpp | 18 +++++++++++------- Core/MIPS/MIPSAnalyst.h | 2 ++ UI/ImDebugger/ImDisasmView.cpp | 11 +++++++++++ Windows/Debugger/CtrlDisAsmView.cpp | 21 ++++++++++++++++++++- Windows/Debugger/CtrlDisAsmView.h | 1 + Windows/Debugger/CtrlMemView.cpp | 10 +++++----- Windows/Debugger/CtrlMemView.h | 6 +++--- Windows/ppsspp.rc | 1 + Windows/resource.h | 1 + ext/aemu_postoffice | 2 +- 10 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 89705675f8..38d4b5759b 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -1261,6 +1261,17 @@ skip: } } + bool GetAnalyzedFunctionAt(u32 addr, AnalyzedFunction *out) { + std::lock_guard guard(functions_lock); + for (auto iter = functions.begin(), end = functions.end(); iter != end; ++iter) { + if (iter->start <= addr && iter->end >= addr) { + *out = *iter; + return true; + } + } + return false; + } + void ReplaceFunctions() { std::lock_guard guard(functions_lock); @@ -1299,13 +1310,6 @@ skip: return 0; } - void SetHashMapFilename(const std::string& filename) { - if (filename.empty()) - hashmapFileName = GetSysDirectory(DIRECTORY_SYSTEM) / "knownfuncs.ini"; - else - hashmapFileName = Path(filename); - } - void StoreHashMap(Path filename) { if (filename.empty()) filename = hashmapFileName; diff --git a/Core/MIPS/MIPSAnalyst.h b/Core/MIPS/MIPSAnalyst.h index 5908f5d882..e287e2bcd6 100644 --- a/Core/MIPS/MIPSAnalyst.h +++ b/Core/MIPS/MIPSAnalyst.h @@ -108,6 +108,8 @@ namespace MIPSAnalyst { void FinalizeScan(bool insertSymbols); void ForgetFunctions(u32 startAddr, u32 endAddr); + bool GetAnalyzedFunctionAt(u32 addr, AnalyzedFunction *out); + void LoadBuiltinHashMap(); void LoadHashMap(const Path &filename); void StoreHashMap(Path filename = Path()); diff --git a/UI/ImDebugger/ImDisasmView.cpp b/UI/ImDebugger/ImDisasmView.cpp index 995eda7d11..1fd8ca1a7f 100644 --- a/UI/ImDebugger/ImDisasmView.cpp +++ b/UI/ImDebugger/ImDisasmView.cpp @@ -12,6 +12,7 @@ #include "Core/Debugger/Breakpoints.h" #include "Core/MIPS/MIPSDebugInterface.h" #include "Core/MIPS/MIPSTables.h" +#include "Core/MIPS/MIPSAnalyst.h" #include "Core/Debugger/SymbolMap.h" #include "Core/MemMap.h" #include "Common/System/Request.h" @@ -751,6 +752,16 @@ void ImDisasmView::PopupMenu(ImControl &control) { if (ImGui::MenuItem("Copy instruction (hex)")) { CopyInstructions(selectRangeStart_, selectRangeEnd_, CopyInstructionsMode::OPCODES); } + if (ImGui::MenuItem("Copy function hash")) { + MIPSAnalyst::AnalyzedFunction func; + if (MIPSAnalyst::GetAnalyzedFunctionAt(curAddress_, &func)) { + if (func.hasHash) { + char temp[256]; + snprintf(temp, sizeof(temp), "%016llx:%d = %s\n", func.hash, func.size, func.name); + System_CopyStringToClipboard(temp); + } + } + } ImGui::Separator(); if (ImGui::MenuItem("Set PC to here")) { diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index f66c00a825..f8ee0e29fe 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -891,10 +891,26 @@ void CtrlDisAsmView::CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructio delete [] temp; } else { std::string disassembly = DisassembleRange(startAddr,endAddr-startAddr, displaySymbols, debugger); - W32Util::CopyTextToClipboard(wnd, disassembly.c_str()); + W32Util::CopyTextToClipboard(wnd, disassembly); } } +void CtrlDisAsmView::CopyFunctionHash(u32 addr) { + MIPSAnalyst::AnalyzedFunction func; + if (MIPSAnalyst::GetAnalyzedFunctionAt(addr, &func)) { + if (func.hasHash) { + char temp[256]; + snprintf(temp, sizeof(temp), "%016llx:%d = %s\n", func.hash, func.size, func.name); + W32Util::CopyTextToClipboard(wnd, temp); + } else { + MessageBox(wnd, L"No hash", L"", 0); + } + } else { + MessageBox(wnd, L"No function", L"", 0); + } +} + + void CtrlDisAsmView::NopInstructions(u32 selectRangeStart, u32 selectRangeEnd) { for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 4) { Memory::Write_U32(0, addr); @@ -945,6 +961,9 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) case ID_DISASM_COPYINSTRUCTIONHEX: CopyInstructions(selectRangeStart, selectRangeEnd, CopyInstructionsMode::OPCODES); break; + case ID_DISASM_COPYFUNCTIONHASH: + CopyFunctionHash(curAddress); + break; case ID_DISASM_NOPINSTRUCTION: NopInstructions(selectRangeStart, selectRangeEnd); redraw(); diff --git a/Windows/Debugger/CtrlDisAsmView.h b/Windows/Debugger/CtrlDisAsmView.h index d0432c0274..2f661ec659 100644 --- a/Windows/Debugger/CtrlDisAsmView.h +++ b/Windows/Debugger/CtrlDisAsmView.h @@ -75,6 +75,7 @@ class CtrlDisAsmView { void updateStatusBarText(); void drawBranchLine(HDC hdc, std::map &addressPositions, const BranchLine &line); void CopyInstructions(u32 startAddr, u32 endAddr, CopyInstructionsMode mode); + void CopyFunctionHash(u32 addr); void NopInstructions(u32 startAddr, u32 endAddr); std::set getSelectedLineArguments(); void drawArguments(HDC hdc, const DisassemblyLineInfo &line, int x, int y, int textColor, const std::set ¤tArguments); diff --git a/Windows/Debugger/CtrlMemView.cpp b/Windows/Debugger/CtrlMemView.cpp index 1a6d022592..4345e536e3 100644 --- a/Windows/Debugger/CtrlMemView.cpp +++ b/Windows/Debugger/CtrlMemView.cpp @@ -596,7 +596,7 @@ void CtrlMemView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) { std::ostringstream stream; stream << (Memory::IsValidAddress(curAddress_) ? Memory::Read_Float(curAddress_) : NAN); auto temp_string = stream.str(); - W32Util::CopyTextToClipboard(wnd, temp_string.c_str()); + W32Util::CopyTextToClipboard(wnd, temp_string); } break; @@ -814,7 +814,7 @@ void CtrlMemView::ScrollCursor(int bytes, GotoMode mode) { redraw(); } -bool CtrlMemView::ParseSearchString(const std::string &query, bool asHex, std::vector &data) { +bool CtrlMemView::ParseSearchString(std::string_view query, bool asHex, std::vector &data) { data.clear(); if (!asHex) { for (size_t i = 0; i < query.length(); i++) { @@ -847,7 +847,7 @@ bool CtrlMemView::ParseSearchString(const std::string &query, bool asHex, std::v return true; } -std::vector CtrlMemView::searchString(const std::string &searchQuery) { +std::vector CtrlMemView::searchString(std::string_view searchQuery) { std::vector searchResAddrs; auto memLock = Memory::Lock(); @@ -993,8 +993,8 @@ void CtrlMemView::setHighlightType(MemBlockFlags flags) { } } -uint32_t CtrlMemView::pickTagColor(const std::string &tag) { +uint32_t CtrlMemView::pickTagColor(std::string_view tag) { int colors[6] = { 0xe0FFFF, 0xFFE0E0, 0xE8E8FF, 0xFFE0FF, 0xE0FFE0, 0xFFFFE0 }; - int which = XXH3_64bits(tag.c_str(), tag.length()) % ARRAY_SIZE(colors); + int which = XXH3_64bits(tag.data(), tag.length()) % ARRAY_SIZE(colors); return colors[which]; } diff --git a/Windows/Debugger/CtrlMemView.h b/Windows/Debugger/CtrlMemView.h index 0c29632fa5..7a0027c16a 100644 --- a/Windows/Debugger/CtrlMemView.h +++ b/Windows/Debugger/CtrlMemView.h @@ -41,7 +41,7 @@ public: MIPSDebugInterface *getDebugger() { return debugger_; } - std::vector searchString(const std::string &searchQuery); + std::vector searchString(std::string_view query); void onPaint(WPARAM wParam, LPARAM lParam); void onVScroll(WPARAM wParam, LPARAM lParam); void onKeyDown(WPARAM wParam, LPARAM lParam); @@ -57,10 +57,10 @@ public: void setHighlightType(MemBlockFlags flags); private: - bool ParseSearchString(const std::string &query, bool asHex, std::vector &data); + bool ParseSearchString(std::string_view query, bool asHex, std::vector &data); void updateStatusBarText(); void search(bool continueSearch); - uint32_t pickTagColor(const std::string &tag); + uint32_t pickTagColor(std::string_view tag); enum class GotoMode { RESET, diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index b69fd69fd2..55a59591cb 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -745,6 +745,7 @@ BEGIN MENUITEM "Copy Address", ID_DISASM_COPYADDRESS MENUITEM "Copy Instruction (Hex)", ID_DISASM_COPYINSTRUCTIONHEX MENUITEM "Copy Instruction (Disasm)", ID_DISASM_COPYINSTRUCTIONDISASM + MENUITEM "Copy Function Hash", ID_DISASM_COPYFUNCTIONHASH MENUITEM "Disassemble to File", ID_DISASM_DISASSEMBLETOFILE MENUITEM SEPARATOR MENUITEM "Assemble Opcode", ID_DISASM_ASSEMBLE diff --git a/Windows/resource.h b/Windows/resource.h index 1366a9ef7b..0dee92b055 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -136,6 +136,7 @@ #define ID_MEMVIEW_COPYVALUE_8 40005 #define ID_DISASM_COPYINSTRUCTIONDISASM 40006 #define ID_DISASM_COPYINSTRUCTIONHEX 40007 +#define ID_DISASM_COPYFUNCTIONHASH 40031 #define ID_EMULATION_SPEEDLIMIT 40008 #define ID_TOGGLE_BREAK 40009 #define ID_EMULATION_STOP 40010 diff --git a/ext/aemu_postoffice b/ext/aemu_postoffice index b0625ecb65..eec2e71424 160000 --- a/ext/aemu_postoffice +++ b/ext/aemu_postoffice @@ -1 +1 @@ -Subproject commit b0625ecb6502038b770eab638143f89699c96bfc +Subproject commit eec2e71424b455998e6add598411678bda25be5a