Merge pull request #22950 from hrydgard/imdebugger-func-scan

ImDebugger: Add scan/remove functions in range, reapply replacements
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-11-06 01:04:22 +01:00
commit 75c35f99e2
6 files changed
+123 -53

No files matched your search

+3 -26
View File
@@ -496,31 +496,8 @@ void WebSocketHLEFuncRemove(DebuggerRequest &req) {
// (Note: this makes no checks whether the range is valid)
// Returns the number of removed functions
static u32 RemoveFuncSymbolsInRange(u32 addr, u32 size) {
u32 func_address = g_symbolMap->GetFunctionStart(addr);
if (func_address == SymbolMap::INVALID_ADDRESS) {
func_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION);
}
u32 counter = 0;
while (func_address < addr + size && func_address != SymbolMap::INVALID_ADDRESS) {
g_symbolMap->RemoveFunction(func_address, true);
++counter;
func_address = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION);
}
u32 counter = MIPSAnalyst::RemoveFunctionsInRange(addr, size);
if (counter) {
MIPSAnalyst::ForgetFunctions(addr, addr + size);
// The following was copied from hle.func.remove:
g_symbolMap->SortSymbols();
MIPSAnalyst::UpdateHashMap();
MIPSAnalyst::ApplyHashMap();
if (g_Config.bFuncReplacements) {
MIPSAnalyst::ReplaceFunctions();
}
// Clear cache for branch lines and such.
g_disassemblyManager.clear();
}
@@ -664,8 +641,8 @@ void WebSocketHLEFuncScan(DebuggerRequest &req) {
RemoveFuncSymbolsInRange(addr, size);
}
bool insertSymbols = MIPSAnalyst::ScanForFunctions(addr, addr + size, true);
MIPSAnalyst::FinalizeScan(insertSymbols);
MIPSAnalyst::ScanFunctionsInRange(addr, size);
g_disassemblyManager.clear();
req.Respond();
});
+36
View File
@@ -26,6 +26,7 @@
#include "Common/Log.h"
#include "Common/StringUtils.h"
#include "Common/TimeUtil.h"
#include "Common/Math/math_util.h"
#include "Core/Config.h"
#include "Core/MemMap.h"
#include "Core/System.h"
@@ -1317,6 +1318,41 @@ namespace MIPSAnalyst {
}
}
void ScanFunctionsInRange(u32 addr, u32 size) {
addr = RoundDownToMultipleOf(addr, 4);
size = RoundUpToMultipleOf(size, 4);
bool insertSymbols = ScanForFunctions(addr, addr + size, true);
FinalizeScan(insertSymbols);
}
u32 RemoveFunctionsInRange(u32 addr, u32 size) {
addr = RoundDownToMultipleOf(addr, 4);
size = RoundUpToMultipleOf(size, 4);
u32 funcAddr = g_symbolMap->GetFunctionStart(addr);
if (funcAddr == SymbolMap::INVALID_ADDRESS) {
funcAddr = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION);
}
u32 count = 0;
while (funcAddr < addr + size && funcAddr != SymbolMap::INVALID_ADDRESS) {
g_symbolMap->RemoveFunction(funcAddr, true);
++count;
funcAddr = g_symbolMap->GetNextSymbolAddress(addr, SymbolType::ST_FUNCTION);
}
if (count) {
ForgetFunctions(addr, addr + size);
g_symbolMap->SortSymbols();
UpdateHashMap();
ApplyHashMap();
if (g_Config.bFuncReplacements) {
ReplaceFunctions();
}
}
return count;
}
bool GetAnalyzedFunctionAt(u32 addr, AnalyzedFunction *out) {
std::lock_guard<std::recursive_mutex> guard(functions_lock);
for (auto iter = functions.begin(), end = functions.end(); iter != end; ++iter) {
+7
View File
@@ -109,6 +109,13 @@ namespace MIPSAnalyst {
void FinalizeScan(bool insertSymbols);
void ForgetFunctions(u32 startAddr, u32 endAddr);
// Debugger helpers. The range is widened to whole instructions. Callers should clear
// g_disassemblyManager afterwards.
void ScanFunctionsInRange(u32 addr, u32 size);
// Removes the function symbols starting in (or containing the start of) the range, forgets
// them, and reapplies replacements. Returns the number removed.
u32 RemoveFunctionsInRange(u32 addr, u32 size);
bool GetAnalyzedFunctionAt(u32 addr, AnalyzedFunction *out);
// endAddr is exclusive.
bool HasFunctionsInRange(u32 startAddr, u32 endAddr);
+69
View File
@@ -5,6 +5,7 @@
#include "Common/StringUtils.h"
#include "Common/Log.h"
#include "Common/Math/geom2d.h"
#include "Core/Config.h"
#include "Core/Core.h"
#include "Core/HLE/HLE.h"
#include "Core/Debugger/DebugInterface.h"
@@ -787,6 +788,7 @@ void ImDisasmView::RemoveFunction(u32 funcStart) {
void ImDisasmView::PopupMenu(MIPSState *mips, ImControl &control) {
bool renameFunctionPopup = false;
bool funcRangePopup = false;
if (ImGui::BeginPopup("context")) {
// The source location is the more useful heading when there is one, but keep the address:
// it's what you paste into a bug report or another debugger.
@@ -905,6 +907,24 @@ void ImDisasmView::PopupMenu(MIPSState *mips, ImControl &control) {
mapReloaded_ = true;
}
}
if (ImGui::MenuItem("Scan/remove functions in range...")) {
// Prefill with the selection if there is one, otherwise the function we're in.
if (selectRangeEnd_ - selectRangeStart_ > 4 || funcStart == -1) {
funcRangeAddr_ = selectRangeStart_;
funcRangeSize_ = selectRangeEnd_ - selectRangeStart_;
} else {
funcRangeAddr_ = funcStart;
funcRangeSize_ = g_symbolMap->GetFunctionSize(funcStart);
}
funcRangeError_.clear();
funcRangePopup = true;
}
if (ImGui::MenuItem("Reapply function replacements", nullptr, false, g_Config.bFuncReplacements)) {
MIPSAnalyst::ReplaceFunctions();
}
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_AllowWhenDisabled)) {
ImGui::SetTooltip("Installs the HLE replacements (ReplaceTables) for every known function whose hash matches.");
}
if (prevBegin != -1) {
u32 prevSize = g_symbolMap->GetFunctionSize(prevBegin);
ShowInMemoryDumperMenuItem(prevBegin, prevSize, MemDumpMode::Disassembly, control);
@@ -912,6 +932,55 @@ void ImDisasmView::PopupMenu(MIPSState *mips, ImControl &control) {
ImGui::EndPopup();
}
if (funcRangePopup) {
ImGui::OpenPopup("funcRange");
}
if (ImGui::BeginPopup("funcRange")) {
ImGui::TextUnformatted("Scan or remove functions in range");
if (ImGui::IsWindowAppearing()) {
ImGui::SetKeyboardFocusHere();
}
ImGui::InputScalar("Address", ImGuiDataType_U32, &funcRangeAddr_, nullptr, nullptr, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
ImGui::InputScalar("Size", ImGuiDataType_U32, &funcRangeSize_, nullptr, nullptr, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
enum class RangeAction { NONE, SCAN, REMOVE, RESCAN };
RangeAction action = RangeAction::NONE;
if (ImGui::Button("Scan")) {
action = RangeAction::SCAN;
}
ImGui::SameLine();
if (ImGui::Button("Remove")) {
action = RangeAction::REMOVE;
}
ImGui::SameLine();
if (ImGui::Button("Remove and rescan")) {
action = RangeAction::RESCAN;
}
if (action != RangeAction::NONE) {
if (funcRangeSize_ == 0 || !Memory::IsValidRange(funcRangeAddr_, funcRangeSize_)) {
funcRangeError_ = "Invalid range";
} else {
u32 removed = 0;
if (action != RangeAction::SCAN) {
removed = MIPSAnalyst::RemoveFunctionsInRange(funcRangeAddr_, funcRangeSize_);
}
if (action != RangeAction::REMOVE) {
MIPSAnalyst::ScanFunctionsInRange(funcRangeAddr_, funcRangeSize_);
}
g_disassemblyManager.clear();
mapReloaded_ = true;
if (action == RangeAction::REMOVE) {
statusBarText_ = StringFromFormat("Removed %d functions", removed);
}
ImGui::CloseCurrentPopup();
}
}
if (!funcRangeError_.empty()) {
ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%s", funcRangeError_.c_str());
}
ImGui::EndPopup();
}
// Sub popups here
if (renameFunctionPopup) {
ImGui::OpenPopup("renameFunction");
+5
View File
@@ -197,6 +197,11 @@ private:
u32 funcBegin_ = 0;
char funcNameTemp_[128]{};
// "Scan/remove functions in range" popup.
u32 funcRangeAddr_ = 0;
u32 funcRangeSize_ = 0;
std::string funcRangeError_;
bool assemblePopup_ = false;
u32 assembleAddress_ = 0;
char assembleTemp_[256]{};
+3 -27
View File
@@ -147,36 +147,12 @@ bool EditSymbolsWindow::exec() {
}
void EditSymbolsWindow::Scan() {
bool insertSymbols = MIPSAnalyst::ScanForFunctions(address_, address_ + size_ - 1, true);
MIPSAnalyst::FinalizeScan(insertSymbols);
MIPSAnalyst::ScanFunctionsInRange(address_, size_);
g_disassemblyManager.clear();
}
void EditSymbolsWindow::Remove() {
u32 func_address = g_symbolMap->GetFunctionStart(address_);
if (func_address == SymbolMap::INVALID_ADDRESS) {
func_address = g_symbolMap->GetNextSymbolAddress(address_, SymbolType::ST_FUNCTION);
}
u32 counter = 0;
while (func_address < address_ + size_ && func_address != SymbolMap::INVALID_ADDRESS) {
g_symbolMap->RemoveFunction(func_address, true);
++counter;
func_address = g_symbolMap->GetNextSymbolAddress(address_, SymbolType::ST_FUNCTION);
}
if (counter) {
MIPSAnalyst::ForgetFunctions(address_, address_ + size_);
// The following was copied from hle.func.remove:
g_symbolMap->SortSymbols();
MIPSAnalyst::UpdateHashMap();
MIPSAnalyst::ApplyHashMap();
if (g_Config.bFuncReplacements) {
MIPSAnalyst::ReplaceFunctions();
}
if (MIPSAnalyst::RemoveFunctionsInRange(address_, size_)) {
// Clear cache for branch lines and such.
g_disassemblyManager.clear();
}