mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Add module filter to symbol list in ImDebugger
This commit is contained in:
1 parent
a0c10a0ea6
commit
8cf77a49f3
13 files changed
+109
-16
No files matched your search
@@ -107,6 +107,7 @@ add_library(Common STATIC
|
||||
Data/Text/Parsers.cpp
|
||||
Data/Text/Parsers.h
|
||||
Data/Text/StringWriter.h
|
||||
Data/Text/StringWriter.cpp
|
||||
Data/Text/WrapText.cpp
|
||||
Data/Text/WrapText.h
|
||||
Data/Random/Rng.h
|
||||
|
||||
@@ -900,6 +900,7 @@
|
||||
<ClCompile Include="Data\Hash\Hash.cpp" />
|
||||
<ClCompile Include="Data\Text\I18n.cpp" />
|
||||
<ClCompile Include="Data\Text\Parsers.cpp" />
|
||||
<ClCompile Include="Data\Text\StringWriter.cpp" />
|
||||
<ClCompile Include="Data\Text\WrapText.cpp" />
|
||||
<ClCompile Include="File\AndroidContentURI.cpp" />
|
||||
<ClCompile Include="File\AndroidStorage.cpp" />
|
||||
@@ -1081,4 +1082,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1472,6 +1472,9 @@
|
||||
<ClCompile Include="UI\ScreenManager.cpp">
|
||||
<Filter>UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Data\Text\StringWriter.cpp">
|
||||
<Filter>Data\Text</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Crypto">
|
||||
|
||||
@@ -160,16 +160,3 @@ bool TryParse(const std::string &str, bool *const output) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
StringWriter &StringWriter::F(const char *format, ...) {
|
||||
const size_t remainder = bufSize_ - (p_ - start_);
|
||||
if (remainder < 3) {
|
||||
return *this;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int wouldHaveBeenWritten = vsnprintf(p_, remainder, format, args);
|
||||
p_ += std::min((int)remainder, wouldHaveBeenWritten);
|
||||
va_end(args);
|
||||
return *this;
|
||||
}
|
||||
@@ -1,2 +1,16 @@
|
||||
#include <cstdarg>
|
||||
#include "Common/Data/Text/StringWriter.h"
|
||||
|
||||
|
||||
StringWriter &StringWriter::F(const char *format, ...) {
|
||||
const size_t remainder = bufSize_ - (p_ - start_);
|
||||
if (remainder < 3) {
|
||||
return *this;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int wouldHaveBeenWritten = vsnprintf(p_, remainder, format, args);
|
||||
p_ += std::min((int)remainder, wouldHaveBeenWritten);
|
||||
va_end(args);
|
||||
return *this;
|
||||
}
|
||||
@@ -477,11 +477,14 @@ u32 SymbolMap::GetModuleCrc(int moduleIndex) const {
|
||||
// per-game rather than per-module, hence GetGameSymbolsPath instead of GetModuleSymbolsPath.
|
||||
bool SymbolMap::SaveModuleSymbols(int moduleIndex, const Path &filename, const std::string &gameID, const std::string &gameTitle) const {
|
||||
u32 crc = 0;
|
||||
// Only for logging - module 0 isn't a module, it's the symbols that aren't in one.
|
||||
const char *moduleName = "(no module)";
|
||||
if (moduleIndex != 0) {
|
||||
bool found = false;
|
||||
for (const auto &module : modules) {
|
||||
if (module.index == moduleIndex) {
|
||||
crc = module.crc;
|
||||
moduleName = module.name;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -529,8 +532,10 @@ bool SymbolMap::SaveModuleSymbols(int moduleIndex, const Path &filename, const s
|
||||
if (count == 0) {
|
||||
// Nothing worth keeping. Remove any previous file rather than leaving one behind that
|
||||
// would restore symbols the user has since deleted.
|
||||
if (File::Exists(filename))
|
||||
if (File::Exists(filename)) {
|
||||
INFO_LOG(Log::Loader, "SaveModuleSymbols: '%s' has no named symbols left, deleting %s", moduleName, filename.c_str());
|
||||
File::Delete(filename);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -552,6 +557,7 @@ bool SymbolMap::SaveModuleSymbols(int moduleIndex, const Path &filename, const s
|
||||
fwrite(text.data(), 1, text.size(), f);
|
||||
|
||||
fclose(f);
|
||||
INFO_LOG(Log::Loader, "SaveModuleSymbols: wrote %d symbol(s) for '%s' to %s", count, moduleName, filename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1323,6 +1323,38 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImContro
|
||||
avail.y -= ImGui::GetTextLineHeightWithSpacing();
|
||||
|
||||
if (ImGui::BeginChild("left", ImVec2(150.0f, avail.y), ImGuiChildFlags_ResizeX)) {
|
||||
// Modules load and unload as the game runs and nothing tells us about it, so poll. The
|
||||
// list is a couple of dozen entries at most, and this only runs while the panel is open.
|
||||
std::vector<LoadedModuleInfo> modules = g_symbolMap->getAllModules();
|
||||
modules.erase(std::remove_if(modules.begin(), modules.end(), [](const LoadedModuleInfo &m) {
|
||||
return !m.active;
|
||||
}), modules.end());
|
||||
if (modules.size() != symModules_.size() || !std::equal(modules.begin(), modules.end(), symModules_.begin(),
|
||||
[](const LoadedModuleInfo &a, const LoadedModuleInfo &b) {
|
||||
return a.address == b.address && a.size == b.size && a.name == b.name;
|
||||
})) {
|
||||
symModules_ = std::move(modules);
|
||||
// symCache_ holds active symbols only, so it's stale now too.
|
||||
symsDirty_ = true;
|
||||
|
||||
// Re-resolve the module filter against the new list. A module that reloaded lands at
|
||||
// a different address, and one that's gone should drop back to All rather than leave
|
||||
// the list mysteriously empty.
|
||||
if (!symModuleFilter_.empty()) {
|
||||
auto found = std::find_if(symModules_.begin(), symModules_.end(), [this](const LoadedModuleInfo &m) {
|
||||
return m.name == symModuleFilter_;
|
||||
});
|
||||
if (found == symModules_.end()) {
|
||||
symModuleFilter_.clear();
|
||||
symModuleFilterStart_ = 0;
|
||||
symModuleFilterSize_ = 0;
|
||||
} else {
|
||||
symModuleFilterStart_ = found->address;
|
||||
symModuleFilterSize_ = found->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (symCache_.empty() || symsDirty_) {
|
||||
symCache_ = g_symbolMap->GetAllActiveSymbols(SymbolType::ST_FUNCTION);
|
||||
symsDirty_ = false;
|
||||
@@ -1346,6 +1378,30 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImContro
|
||||
symMatchesDirty_ = true;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(-1.0f);
|
||||
if (ImGui::BeginCombo("##symmodule", symModuleFilter_.empty() ? "All modules" : symModuleFilter_.c_str())) {
|
||||
if (ImGui::Selectable("All modules", symModuleFilter_.empty())) {
|
||||
symModuleFilter_.clear();
|
||||
symModuleFilterStart_ = 0;
|
||||
symModuleFilterSize_ = 0;
|
||||
symMatchesDirty_ = true;
|
||||
}
|
||||
for (int i = 0; i < (int)symModules_.size(); i++) {
|
||||
const LoadedModuleInfo &module = symModules_[i];
|
||||
// Module names are not unique - the same one can be loaded more than once.
|
||||
ImGui::PushID(i);
|
||||
const bool selected = symModuleFilter_ == module.name && symModuleFilterStart_ == module.address;
|
||||
if (ImGui::Selectable(module.name.c_str(), selected)) {
|
||||
symModuleFilter_ = module.name;
|
||||
symModuleFilterStart_ = module.address;
|
||||
symModuleFilterSize_ = module.size;
|
||||
symMatchesDirty_ = true;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (symMatchesDirty_) {
|
||||
symMatchesDirty_ = false;
|
||||
symMatches_.clear();
|
||||
@@ -1353,6 +1409,11 @@ void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImContro
|
||||
// path to get wrong. These lists run to a few thousand entries, and this only reruns
|
||||
// when the filter or the symbol map changes, not per frame.
|
||||
for (int i = 0; i < (int)symCache_.size(); i++) {
|
||||
if (!symModuleFilter_.empty()) {
|
||||
const u32 addr = symCache_[i].address;
|
||||
if (addr < symModuleFilterStart_ || addr >= symModuleFilterStart_ + symModuleFilterSize_)
|
||||
continue;
|
||||
}
|
||||
if (symFilter_[0] == '\0' || containsNoCase(symCache_[i].name, symFilter_))
|
||||
symMatches_.push_back(i);
|
||||
}
|
||||
|
||||
@@ -230,6 +230,16 @@ private:
|
||||
std::vector<int> symMatches_;
|
||||
bool symMatchesDirty_ = true;
|
||||
|
||||
// Currently loaded modules, for the module filter dropdown. Refreshed every frame the
|
||||
// symbol list is visible: modules come and go while a game runs, and nothing notifies us.
|
||||
// A change here also invalidates symCache_, since it's built from active symbols only.
|
||||
std::vector<LoadedModuleInfo> symModules_;
|
||||
// The module filter is remembered as a name plus an address range rather than an index into
|
||||
// symModules_, so a selection survives that list being rebuilt. Empty name means "All".
|
||||
std::string symModuleFilter_;
|
||||
u32 symModuleFilterStart_ = 0;
|
||||
u32 symModuleFilterSize_ = 0;
|
||||
|
||||
ImDisasmView disasmView_;
|
||||
char searchTerm_[64]{};
|
||||
};
|
||||
@@ -93,6 +93,7 @@
|
||||
<ClInclude Include="..\..\Common\BitSet.h" />
|
||||
<ClInclude Include="..\..\Common\Buffer.h" />
|
||||
<ClInclude Include="..\..\Common\Data\Format\DDSLoad.h" />
|
||||
<ClInclude Include="..\..\Common\Data\Text\StringWriter.h" />
|
||||
<ClInclude Include="..\..\Common\File\AndroidContentURI.h" />
|
||||
<ClInclude Include="..\..\Common\File\AndroidStorage.h" />
|
||||
<ClInclude Include="..\..\Common\File\VFS\SevenZipFileReader.h" />
|
||||
@@ -305,6 +306,7 @@
|
||||
<ClCompile Include="..\..\Common\ArmEmitter.cpp" />
|
||||
<ClCompile Include="..\..\Common\Buffer.cpp" />
|
||||
<ClCompile Include="..\..\Common\Data\Format\DDSLoad.cpp" />
|
||||
<ClCompile Include="..\..\Common\Data\Text\StringWriter.cpp" />
|
||||
<ClCompile Include="..\..\Common\File\AndroidContentURI.cpp" />
|
||||
<ClCompile Include="..\..\Common\File\AndroidStorage.cpp" />
|
||||
<ClCompile Include="..\..\Common\File\VFS\SevenZipFileReader.cpp" />
|
||||
|
||||
@@ -591,6 +591,9 @@
|
||||
<ClCompile Include="..\..\Common\UI\ScreenManager.cpp">
|
||||
<Filter>UI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\Common\Data\Text\StringWriter.cpp">
|
||||
<Filter>Data\Text</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="targetver.h" />
|
||||
@@ -1145,6 +1148,9 @@
|
||||
<ClInclude Include="..\..\Common\UI\ScreenManager.h">
|
||||
<Filter>UI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\Common\Data\Text\StringWriter.h">
|
||||
<Filter>Data\Text</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\ext\libpng17\CMakeLists.txt" />
|
||||
|
||||
@@ -334,6 +334,7 @@ EXEC_AND_LIB_FILES := \
|
||||
$(SRC)/Common/Data/Hash/Hash.cpp \
|
||||
$(SRC)/Common/Data/Text/I18n.cpp \
|
||||
$(SRC)/Common/Data/Text/Parsers.cpp \
|
||||
$(SRC)/Common/Data/Text/StringWriter.cpp \
|
||||
$(SRC)/Common/Data/Text/WrapText.cpp \
|
||||
$(SRC)/Common/File/AndroidStorage.cpp \
|
||||
$(SRC)/Common/File/AndroidContentURI.cpp \
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
plugins {
|
||||
id("com.android.application") version "9.3.1" apply false
|
||||
id("com.android.application") version "9.3.2" apply false
|
||||
id("com.google.protobuf") version "0.10.0" apply false
|
||||
}
|
||||
@@ -451,6 +451,7 @@ SOURCES_CXX += \
|
||||
$(COMMONDIR)/Data/Hash/Hash.cpp \
|
||||
$(COMMONDIR)/Data/Text/I18n.cpp \
|
||||
$(COMMONDIR)/Data/Text/Parsers.cpp \
|
||||
$(COMMONDIR)/Data/Text/StringWriter.cpp \
|
||||
$(COMMONDIR)/Data/Text/WrapText.cpp \
|
||||
$(COMMONDIR)/File/VFS/VFS.cpp \
|
||||
$(COMMONDIR)/File/VFS/DirectoryReader.cpp \
|
||||
|
||||
Reference in new issue
Block a user