diff --git a/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp b/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp index 5b3f53dc..fcdb8997 100644 --- a/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp @@ -420,7 +420,7 @@ void PatchEntryInstruction::undoPatch() uint8* patchAddr = (uint8*)memory_base + addr; memcpy(patchAddr, m_dataBackup, m_length); PPCRecompiler_invalidateRange(addr, addr + m_length); - rplSymbolStorage_removeRange(addr, m_length); + rplSymbolStorage_removeRange(addr, m_length, RPL_STORED_SYMBOL_PATCH); DebugSymbolStorage::ClearRange(addr, m_length); } @@ -434,7 +434,7 @@ bool registerU32Variable(PatchContext_t& ctx, std::string& name, uint32 value, P } ctx.map_values[name] = value; // keep track of address symbols for the debugger - rplSymbolStorage_store(ctx.graphicPack->GetName().data(), name.data(), value); + rplSymbolStorage_store(ctx.graphicPack->GetName().data(), name.data(), value, RPL_STORED_SYMBOL_PATCH); return true; } diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index b906b6b1..cf709a2e 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -536,6 +536,10 @@ bool RPLLoader_LoadSections(sint32 aProcId, RPLModule* rplLoaderContext) rplLoaderContext->regionSize_loaderInfo = regionLoaderinfoSize; rplLoaderContext->regionSize_text = regionTextSize; + // set original base addresses + rplLoaderContext->regionOrigAddr_text = regionMappingTable.region[RPL_MAPPING_REGION_TEXT].baseAddress; + rplLoaderContext->regionOrigAddr_data = regionMappingTable.region[RPL_MAPPING_REGION_DATA].baseAddress; + // load data sections for (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++) { diff --git a/src/Cafe/OS/RPL/rpl_structs.h b/src/Cafe/OS/RPL/rpl_structs.h index aa734dae..bd18d244 100644 --- a/src/Cafe/OS/RPL/rpl_structs.h +++ b/src/Cafe/OS/RPL/rpl_structs.h @@ -171,7 +171,9 @@ struct RPLModule uint32 tlsStartAddress; uint32 tlsEndAddress; uint32 regionSize_text; + uint32 regionOrigAddr_text; uint32 regionSize_data; + uint32 regionOrigAddr_data; uint32 regionSize_loaderInfo; uint32 patchCRC; // Cemuhook style module crc for patches.txt diff --git a/src/Cafe/OS/RPL/rpl_symbol_storage.cpp b/src/Cafe/OS/RPL/rpl_symbol_storage.cpp index 5d3046e3..3910640e 100644 --- a/src/Cafe/OS/RPL/rpl_symbol_storage.cpp +++ b/src/Cafe/OS/RPL/rpl_symbol_storage.cpp @@ -63,7 +63,7 @@ char* rplSymbolStorage_storeLibname(const char* libName) return libEntry->libName; } -RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address) +RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address, uint32 type) { std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); char* libNameStorage = rplSymbolStorage_storeLibname(libName); @@ -72,7 +72,11 @@ RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolN storedSymbol->address = address; storedSymbol->libName = libNameStorage; storedSymbol->symbolName = symbolNameStorage; - storedSymbol->flags = 0; + storedSymbol->flags = type; + storedSymbol->previous = nullptr; + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + if (it != rplSymbolStorage.map_symbolByAddress.end()) + storedSymbol->previous = it->second; rplSymbolStorage.map_symbolByAddress[address] = storedSymbol; return storedSymbol; } @@ -80,7 +84,10 @@ RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolN RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address) { std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); - return rplSymbolStorage.map_symbolByAddress[address]; + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + if (it == rplSymbolStorage.map_symbolByAddress.end()) + return nullptr; + return it->second; } RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address) @@ -89,7 +96,8 @@ RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address) std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); for(uint32 i=0; i<4096; i++) { - RPLStoredSymbol* symbol = rplSymbolStorage.map_symbolByAddress[address]; + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + RPLStoredSymbol* symbol = (it == rplSymbolStorage.map_symbolByAddress.end()) ? nullptr : it->second; if(symbol) return symbol; address -= 4; @@ -100,18 +108,63 @@ RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address) void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol) { std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); - if (rplSymbolStorage.map_symbolByAddress[storedSymbol->address] == storedSymbol) - rplSymbolStorage.map_symbolByAddress[storedSymbol->address] = nullptr; + auto it = rplSymbolStorage.map_symbolByAddress.find(storedSymbol->address); + if (it != rplSymbolStorage.map_symbolByAddress.end()) + { + if (it->second == storedSymbol) + { + if (storedSymbol->previous) + it->second = storedSymbol->previous; + else + rplSymbolStorage.map_symbolByAddress.erase(it); + } + else + { + RPLStoredSymbol* parentSymbol = it->second; + while (parentSymbol && parentSymbol->previous != storedSymbol) + parentSymbol = parentSymbol->previous; + if (parentSymbol) + parentSymbol->previous = storedSymbol->previous; + } + } delete storedSymbol; } -void rplSymbolStorage_removeRange(MPTR address, sint32 length) + +void rplSymbolStorage_removeRange(MPTR address, sint32 length, uint32 type) { + std::unique_lock lck(rplSymbolStorage.m_symbolStorageMutex); while (length > 0) { - RPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(address); - if (symbol) - rplSymbolStorage_remove(symbol); + auto it = rplSymbolStorage.map_symbolByAddress.find(address); + if (it != rplSymbolStorage.map_symbolByAddress.end()) + { + RPLStoredSymbol* current = it->second; + RPLStoredSymbol* newHead = current; + RPLStoredSymbol* previousKept = nullptr; + while (current) + { + RPLStoredSymbol* next = current->previous; + if ((current->flags & type) == type) + { + if (previousKept) + previousKept->previous = next; + else + newHead = next; + delete current; + } + else + { + previousKept = current; + } + current = next; + } + + if (newHead) + it->second = newHead; + else + rplSymbolStorage.map_symbolByAddress.erase(it); + } address += 4; length -= 4; } @@ -145,7 +198,15 @@ void rplSymbolStorage_unloadAll() { // free symbols for (auto& it : rplSymbolStorage.map_symbolByAddress) - delete it.second; + { + RPLStoredSymbol* symbol = it.second; + while (symbol) + { + RPLStoredSymbol* previous = symbol->previous; + delete symbol; + symbol = previous; + } + } rplSymbolStorage.map_symbolByAddress.clear(); // free libs rplSymbolLib_t* lib = rplSymbolStorage.libs; diff --git a/src/Cafe/OS/RPL/rpl_symbol_storage.h b/src/Cafe/OS/RPL/rpl_symbol_storage.h index d940186a..59592c6c 100644 --- a/src/Cafe/OS/RPL/rpl_symbol_storage.h +++ b/src/Cafe/OS/RPL/rpl_symbol_storage.h @@ -1,19 +1,27 @@ +enum RPLStoredSymbolType : uint32 +{ + RPL_STORED_SYMBOL_NONE = 0, + RPL_STORED_SYMBOL_MAP = 1 << 0, + RPL_STORED_SYMBOL_PATCH = 1 << 1, +}; + struct RPLStoredSymbol { MPTR address; void* libName; void* symbolName; uint32 flags; + RPLStoredSymbol* previous; }; void rplSymbolStorage_init(); void rplSymbolStorage_unloadAll(); -RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address); +RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address, uint32 type = RPL_STORED_SYMBOL_NONE); void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol); -void rplSymbolStorage_removeRange(MPTR address, sint32 length); +void rplSymbolStorage_removeRange(MPTR address, sint32 length, uint32 type = RPL_STORED_SYMBOL_NONE); RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address); RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address); void rplSymbolStorage_createJumpProxySymbol(MPTR jumpAddress, MPTR destAddress); std::unordered_map& rplSymbolStorage_lockSymbolMap(); -void rplSymbolStorage_unlockSymbolMap(); \ No newline at end of file +void rplSymbolStorage_unlockSymbolMap(); diff --git a/src/gui/wxgui/debugger/DebuggerWindow2.cpp b/src/gui/wxgui/debugger/DebuggerWindow2.cpp index e91bc1e0..d4e8bc2e 100644 --- a/src/gui/wxgui/debugger/DebuggerWindow2.cpp +++ b/src/gui/wxgui/debugger/DebuggerWindow2.cpp @@ -3,11 +3,12 @@ #include "wxHelper.h" -#include - +#include "Common/FileStream.h" #include "config/ActiveSettings.h" +#include "Cafe/HW/MMU/MMU.h" #include "Cafe/OS/RPL/rpl_structs.h" #include "Cafe/OS/RPL/rpl_debug_symbols.h" +#include "Cafe/OS/RPL/rpl_symbol_storage.h" #include "wxgui/debugger/RegisterWindow.h" #include "wxgui/debugger/DumpWindow.h" @@ -20,6 +21,7 @@ #include "wxgui/debugger/BreakpointWindow.h" #include "wxgui/debugger/ModuleWindow.h" #include "util/helpers/helpers.h" +#include "util/helpers/StringHelpers.h" #include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h" #include "Cemu/Logging/CemuLogging.h" @@ -84,10 +86,11 @@ DebuggerModuleInfo::DebuggerModuleInfo(RPLModule* module) moduleName = module->moduleName2; patchCRC = module->patchCRC; textArea.base = module->regionMappingBase_text.GetMPTR(); + textArea.origBase = module->regionOrigAddr_text; textArea.size = module->regionSize_text; dataArea.base = module->regionMappingBase_data; + dataArea.origBase = module->regionOrigAddr_data; dataArea.size = module->regionSize_data; - } struct DebuggerModuleInfoNotify : public wxClientData @@ -99,6 +102,65 @@ struct DebuggerModuleInfoNotify : public wxClientData DebuggerWindow2* s_debuggerWindow; +static bool TryParseMapAddress(std::string_view token, uint32& value) +{ + trim(token, "\t\n\v\f\r ,:;()[]"); + if (const auto colonIndex = token.find_last_of(':'); colonIndex != std::string_view::npos) + token = token.substr(colonIndex + 1); + trim(token, "\t\n\v\f\r ,:;()[]"); + if (!token.empty() && (token.back() == 'h' || token.back() == 'H')) + token.remove_suffix(1); + if (token.size() > 2 && token[0] == '0' && (token[1] == 'x' || token[1] == 'X')) + token.remove_prefix(2); + if (token.empty()) + return false; + + uint64 parsedValue = 0; + const auto result = std::from_chars(token.data(), token.data() + token.size(), parsedValue, 16); + if (result.ec != std::errc() || result.ptr != (token.data() + token.size()) || parsedValue > std::numeric_limits::max()) + return false; + + value = static_cast(parsedValue); + return true; +} + +static bool TryParseMapSymbolLine(std::string_view rawLine, uint32& address, std::string& symbolName) +{ + auto line = rawLine; + trim(line); + if (line.empty()) + return false; + + const auto addressEnd = line.find_first_of(" \t"); + if (addressEnd == std::string_view::npos) + return false; + if (!TryParseMapAddress(line.substr(0, addressEnd), address)) + return false; + + line = line.substr(addressEnd + 1); + trim(line); + if (line.empty()) + return false; + + const auto symbolEnd = line.find_first_of(" \t"); + auto symbolToken = symbolEnd == std::string_view::npos ? line : line.substr(0, symbolEnd); + trim(symbolToken); + if (symbolToken.empty()) + return false; + + symbolName.assign(symbolToken); + return true; +} + +static std::optional GetRelocatedMapAddress(const DebuggerModuleInfo& moduleInfo, uint32 mapAddress) +{ + if (moduleInfo.textArea.ContainsOriginalAddress(mapAddress)) + return moduleInfo.textArea.base + (mapAddress - moduleInfo.textArea.origBase); + if (moduleInfo.dataArea.ContainsOriginalAddress(mapAddress)) + return moduleInfo.dataArea.base + (mapAddress - moduleInfo.dataArea.origBase); + return std::nullopt; +} + void DebuggerConfig::Load(XMLConfigParser& parser) { pin_to_main = parser.get("PinToMainWindow", true); @@ -282,26 +344,79 @@ void DebuggerWindow2::LoadModuleStorage(const DebuggerModuleInfo& moduleInfo) bool already_loaded = std::any_of(m_modulesStorage.begin(), m_modulesStorage.end(), [path](const std::unique_ptr& debug) { return debug->GetFilename() == path; }); if (!path.empty() && !already_loaded) { - m_modulesStorage.emplace_back(new XMLDebuggerModuleConfig(path, { moduleInfo, false }))->Load(); + auto& moduleStorage = m_modulesStorage.emplace_back(new XMLDebuggerModuleConfig(path, { moduleInfo, false })); + moduleStorage->Load(); + LoadModuleMap(moduleStorage->data()); } } void DebuggerWindow2::SaveModuleStorage(const DebuggerModuleInfo& moduleInfo, bool deleteModuleStorage) { auto path = GetModuleStoragePath(moduleInfo.moduleName, moduleInfo.patchCRC); - for (auto& moduleStorage : m_modulesStorage) + for (auto it = m_modulesStorage.begin(); it != m_modulesStorage.end(); ++it) { + auto& moduleStorage = *it; if (moduleStorage->data().moduleInfo.moduleName == moduleInfo.moduleName && moduleStorage->data().moduleInfo.patchCRC == moduleInfo.patchCRC) { moduleStorage->data().delete_breakpoints_after_saving = deleteModuleStorage; // make sure breakpoints are deleted when the storage is removed moduleStorage->Save(path); if (deleteModuleStorage) - m_modulesStorage.erase(std::find(m_modulesStorage.begin(), m_modulesStorage.end(), moduleStorage)); - break; + { + UnloadModuleMap(moduleStorage->data()); + m_modulesStorage.erase(it); + } + return; } } } +void DebuggerWindow2::LoadModuleMap(DebuggerModuleStorage& moduleStorage) +{ + UnloadModuleMap(moduleStorage); + + const auto mapPath = GetModuleMapPath(moduleStorage.moduleInfo.moduleName, moduleStorage.moduleInfo.patchCRC); + if (mapPath.empty()) + return; + + std::unique_ptr fileStream(FileStream::openFile(mapPath.c_str())); + if (!fileStream) + return; + + const auto fileSize = fileStream->GetSize(); + if (fileSize == 0 || fileSize > std::numeric_limits::max()) + return; + + const auto readSize = static_cast(fileSize); + std::vector fileData(readSize); + if (fileStream->readData(fileData.data(), readSize) != readSize) + return; + + std::string_view fileView(fileData.data(), fileData.size()); + for (const auto& line : StringHelpers::StringLineIterator(fileView)) + { + uint32 mapAddress = 0; + std::string symbolName; + if (TryParseMapSymbolLine(line, mapAddress, symbolName)) + { + const auto relocatedAddress = GetRelocatedMapAddress(moduleStorage.moduleInfo, mapAddress); + if (relocatedAddress) + { + moduleStorage.loaded_map_symbols.emplace_back(rplSymbolStorage_store(moduleStorage.moduleInfo.moduleName.c_str(), symbolName.c_str(), *relocatedAddress, RPL_STORED_SYMBOL_MAP)); + } + } + } +} + +void DebuggerWindow2::UnloadModuleMap(DebuggerModuleStorage& moduleStorage) +{ + for (auto* symbol : moduleStorage.loaded_map_symbols) + { + if (symbol) + rplSymbolStorage_remove(symbol); + } + moduleStorage.loaded_map_symbols.clear(); +} + DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size) : wxFrame(&parent, wxID_ANY, _("PPC Debugger"), wxDefaultPosition, wxSize(1280, 300), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT), m_module_address(0) @@ -537,6 +652,12 @@ std::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); } +std::wstring DebuggerWindow2::GetModuleMapPath(std::string module_name, uint32_t crc_hash) const +{ + if (module_name.empty() || crc_hash == 0) return {}; + return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.map", module_name, crc_hash).generic_wstring(); +} + void DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event) { PPCInterpreter_t* hCPU = debugger_lockDebugSession(); diff --git a/src/gui/wxgui/debugger/DebuggerWindow2.h b/src/gui/wxgui/debugger/DebuggerWindow2.h index 1b4d3c72..83cc5edb 100644 --- a/src/gui/wxgui/debugger/DebuggerWindow2.h +++ b/src/gui/wxgui/debugger/DebuggerWindow2.h @@ -16,6 +16,7 @@ class DumpWindow; class ModuleWindow; class SymbolWindow; class wxStaticText; +struct RPLStoredSymbol; wxDECLARE_EVENT(wxEVT_UPDATE_VIEW, wxCommandEvent); wxDECLARE_EVENT(wxEVT_BREAKPOINT_HIT, wxCommandEvent); @@ -54,12 +55,18 @@ struct DebuggerModuleInfo struct ModuleArea { MPTR base; + MPTR origBase; uint32 size; - bool ContainsAddress(MPTR addr) + bool ContainsAddress(MPTR addr) const { return addr >= base && (addr < (base+size)); } + + bool ContainsOriginalAddress(MPTR addr) const + { + return addr >= origBase && (addr < (origBase + size)); + } }; std::string moduleName; @@ -74,6 +81,7 @@ struct DebuggerModuleStorage { DebuggerModuleInfo moduleInfo; bool delete_breakpoints_after_saving; + std::vector loaded_map_symbols; void Load(XMLConfigParser& parser); void Save(XMLConfigParser& parser); @@ -126,6 +134,9 @@ private: void CreateMenuBar(); void UpdateModuleLabel(uint32 address = 0); + void LoadModuleMap(DebuggerModuleStorage& moduleStorage); + void UnloadModuleMap(DebuggerModuleStorage& moduleStorage); + std::wstring GetModuleMapPath(std::string module_name, uint32_t crc_hash) const; void UpdateViewThreadsafe() override; void NotifyDebugBreakpointHit() override; diff --git a/src/gui/wxgui/debugger/DisasmCtrl.cpp b/src/gui/wxgui/debugger/DisasmCtrl.cpp index 33da4774..913df026 100644 --- a/src/gui/wxgui/debugger/DisasmCtrl.cpp +++ b/src/gui/wxgui/debugger/DisasmCtrl.cpp @@ -14,6 +14,8 @@ #include "Cemu/ExpressionParser/ExpressionParser.h" #include "Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h" +#include + wxDEFINE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent); #define MAX_SYMBOL_LEN (120) @@ -699,20 +701,11 @@ void DisasmCtrl::OnMouseDClick(const wxPoint& position, uint32 line) void DisasmCtrl::CopyToClipboard(std::string text) { -#if BOOST_OS_WINDOWS - if (OpenClipboard(nullptr)) + if (wxClipboard::Get()->Open()) { - EmptyClipboard(); - const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1); - if (hGlobal) - { - memcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1); - GlobalUnlock(hGlobal); - SetClipboardData(CF_TEXT, hGlobal); - } - CloseClipboard(); + wxClipboard::Get()->SetData(new wxTextDataObject(text)); + wxClipboard::Get()->Close(); } -#endif } static uint32 GetUnrelocatedAddress(MPTR address) diff --git a/src/gui/wxgui/debugger/SymbolCtrl.cpp b/src/gui/wxgui/debugger/SymbolCtrl.cpp index 77f55529..8675259c 100644 --- a/src/gui/wxgui/debugger/SymbolCtrl.cpp +++ b/src/gui/wxgui/debugger/SymbolCtrl.cpp @@ -2,6 +2,7 @@ #include "Cafe/OS/RPL/rpl_symbol_storage.h" #include "Cafe/HW/Espresso/Debugger/Debugger.h" #include +#include enum ItemColumns { @@ -38,13 +39,12 @@ SymbolListCtrl::SymbolListCtrl(wxWindow* parent, const wxWindowID& id, const wxP m_list_filter.Clear(); OnGameLoaded(); - - SetItemCount(m_data.size()); } void SymbolListCtrl::OnGameLoaded() { m_data.clear(); + m_visible_items.clear(); const auto symbol_map = rplSymbolStorage_lockSymbolMap(); for (auto const& [address, symbol_info] : symbol_map) { @@ -56,48 +56,30 @@ void SymbolListCtrl::OnGameLoaded() wxString searchNameWX = libNameWX + symbolNameWX; searchNameWX.MakeLower(); - auto new_entry = m_data.try_emplace( - symbol_info->address, - symbolNameWX, + m_data.try_emplace( + address, + symbolNameWX, libNameWX, - searchNameWX, - false + searchNameWX ); - - if (m_list_filter.IsEmpty()) - new_entry.first->second.visible = true; - else if (new_entry.first->second.searchName.Contains(m_list_filter)) - new_entry.first->second.visible = true; } rplSymbolStorage_unlockSymbolMap(); - SetItemCount(m_data.size()); - if (m_data.size() > 0) - RefreshItems(GetTopItem(), std::min(m_data.size() - 1, GetTopItem() + GetCountPerPage() + 1)); + RebuildVisibleItems(); } wxString SymbolListCtrl::OnGetItemText(long item, long column) const { - if (item >= GetItemCount()) + if (item < 0 || item >= static_cast(m_visible_items.size())) return wxEmptyString; - long visible_idx = 0; - for (const auto& [address, symbol] : m_data) - { - if (!symbol.visible) - continue; - - if (item == visible_idx) - { - if (column == ColumnName) - return wxString(symbol.name); - if (column == ColumnAddress) - return wxString::Format("%08x", address); - if (column == ColumnModule) - return wxString(symbol.libName); - } - visible_idx++; - } + const auto& [address, symbol] = *m_visible_items[item]; + if (column == ColumnName) + return symbol.name; + if (column == ColumnAddress) + return wxString::Format("%08x", address); + if (column == ColumnModule) + return symbol.libName; return wxEmptyString; } @@ -106,10 +88,9 @@ wxString SymbolListCtrl::OnGetItemText(long item, long column) const void SymbolListCtrl::OnLeftDClick(wxListEvent& event) { long selected = GetFirstSelected(); - if (selected == wxNOT_FOUND) + if (selected == wxNOT_FOUND || selected >= static_cast(m_visible_items.size())) return; - const auto text = GetItemText(selected, ColumnAddress); - const auto address = std::stoul(text.ToStdString(), nullptr, 16); + const auto address = m_visible_items[selected]->first; if (address == 0) return; debugger_jumpToAddressInDisasm(address); @@ -118,46 +99,40 @@ void SymbolListCtrl::OnLeftDClick(wxListEvent& event) void SymbolListCtrl::OnRightClick(wxListEvent& event) { long selected = GetFirstSelected(); - if (selected == wxNOT_FOUND) + if (selected == wxNOT_FOUND || selected >= static_cast(m_visible_items.size())) return; - auto text = GetItemText(selected, ColumnAddress); - text = "0x" + text; -#if BOOST_OS_WINDOWS - if (OpenClipboard(nullptr)) + if (wxClipboard::Get()->Open()) { - EmptyClipboard(); - const HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size()+1); - if (hGlobal) - { - memcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1); - GlobalUnlock(hGlobal); - - SetClipboardData(CF_TEXT, hGlobal); - GlobalFree(hGlobal); - } - CloseClipboard(); + wxClipboard::Get()->SetData(new wxTextDataObject(wxString::Format("0x%08x", m_visible_items[selected]->first))); + wxClipboard::Get()->Close(); } -#endif +} + +void SymbolListCtrl::RebuildVisibleItems() +{ + m_visible_items.clear(); + m_visible_items.reserve(m_data.size()); + const bool has_filter = !m_list_filter.IsEmpty(); + for (auto it = m_data.cbegin(); it != m_data.cend(); ++it) + { + if (has_filter && !it->second.searchName.Contains(m_list_filter)) + continue; + + m_visible_items.emplace_back(it); + } + + SetItemCount(static_cast(m_visible_items.size())); + if (!m_visible_items.empty()) + { + const auto top_item = std::min(GetTopItem(), static_cast(m_visible_items.size() - 1)); + RefreshItems(top_item, std::min(static_cast(m_visible_items.size() - 1), top_item + GetCountPerPage() + 1)); + } + else + Refresh(); } void SymbolListCtrl::ChangeListFilter(wxString filter) { m_list_filter = filter.MakeLower(); - - size_t visible_entries = m_data.size(); - for (auto& [address, symbol] : m_data) - { - if (m_list_filter.IsEmpty()) - symbol.visible = true; - else if (symbol.searchName.Contains(m_list_filter)) - symbol.visible = true; - else - { - visible_entries--; - symbol.visible = false; - } - } - SetItemCount(visible_entries); - if (visible_entries > 0) - RefreshItems(GetTopItem(), std::min(visible_entries - 1, GetTopItem() + GetCountPerPage() + 1)); + RebuildVisibleItems(); } diff --git a/src/gui/wxgui/debugger/SymbolCtrl.h b/src/gui/wxgui/debugger/SymbolCtrl.h index cb592ee7..938361c0 100644 --- a/src/gui/wxgui/debugger/SymbolCtrl.h +++ b/src/gui/wxgui/debugger/SymbolCtrl.h @@ -10,22 +10,23 @@ public: void ChangeListFilter(wxString filter); - private: +private: struct SymbolItem { - SymbolItem() = default; - SymbolItem(wxString name, wxString libName, wxString searchName, bool visible) : name(name), libName(libName), searchName(searchName), visible(visible) {} - + SymbolItem() = default; + SymbolItem(const wxString& name, const wxString& libName, const wxString& searchName) : name(name), libName(libName), searchName(searchName) {} wxString name; wxString libName; wxString searchName; - bool visible; }; + using SymbolMap = std::map; - std::map m_data; + SymbolMap m_data; wxString m_list_filter; + std::vector m_visible_items; - wxString OnGetItemText(long item, long column) const; + wxString OnGetItemText(long item, long column) const override; + void RebuildVisibleItems(); void OnLeftDClick(wxListEvent& event); void OnRightClick(wxListEvent& event); };