diff --git a/Source/Core/Common/SymbolDB.cpp b/Source/Core/Common/SymbolDB.cpp index f9d352b415..bfdd9f57db 100644 --- a/Source/Core/Common/SymbolDB.cpp +++ b/Source/Core/Common/SymbolDB.cpp @@ -51,6 +51,7 @@ void SymbolDB::Clear(const char* prefix) { // TODO: honor prefix m_functions.clear(); + m_notes.clear(); m_checksum_to_function.clear(); } diff --git a/Source/Core/Common/SymbolDB.h b/Source/Core/Common/SymbolDB.h index 255994b3c2..8930b95996 100644 --- a/Source/Core/Common/SymbolDB.h +++ b/Source/Core/Common/SymbolDB.h @@ -29,6 +29,16 @@ struct SCall u32 call_address; }; +struct Note +{ + std::string name; + u32 address = 0; + u32 size = 0; + int layer = 0; + + Note() = default; +}; + struct Symbol { enum class Type @@ -71,6 +81,7 @@ class SymbolDB { public: using XFuncMap = std::map; + using XNoteMap = std::map; using XFuncPtrMap = std::map>; SymbolDB(); @@ -86,6 +97,7 @@ public: std::vector GetSymbolsFromHash(u32 hash); const XFuncMap& Symbols() const { return m_functions; } + const XNoteMap& Notes() const { return m_notes; } XFuncMap& AccessSymbols() { return m_functions; } bool IsEmpty() const; void Clear(const char* prefix = ""); @@ -94,6 +106,7 @@ public: protected: XFuncMap m_functions; + XNoteMap m_notes; XFuncPtrMap m_checksum_to_function; }; } // namespace Common diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp index 5351d1ec28..4e98beafef 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.cpp +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.cpp @@ -91,6 +91,46 @@ void PPCSymbolDB::AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAdd } } +void PPCSymbolDB::AddKnownNote(u32 start_addr, u32 size, const std::string& name) +{ + auto iter = m_notes.find(start_addr); + + if (iter != m_notes.end()) + { + // Already got it, just update the name and size. + Common::Note* tempfunc = &iter->second; + tempfunc->name = name; + tempfunc->size = size; + } + else + { + Common::Note tf; + tf.name = name; + tf.address = start_addr; + tf.size = size; + + m_notes[start_addr] = tf; + } +} + +void PPCSymbolDB::DetermineNoteLayers() +{ + if (m_notes.empty()) + return; + + for (auto& note : m_notes) + note.second.layer = 0; + + for (auto iter = m_notes.begin(); iter != m_notes.end(); ++iter) + { + const u32 range = iter->second.address + iter->second.size; + auto search = m_notes.lower_bound(range); + + while (--search != iter) + search->second.layer += 1; + } +} + Common::Symbol* PPCSymbolDB::GetSymbolFromAddr(u32 addr) { auto it = m_functions.lower_bound(addr); @@ -112,6 +152,36 @@ Common::Symbol* PPCSymbolDB::GetSymbolFromAddr(u32 addr) return nullptr; } +Common::Note* PPCSymbolDB::GetNoteFromAddr(u32 addr) +{ + if (m_notes.empty()) + return nullptr; + + auto itn = m_notes.lower_bound(addr); + + // If the address is exactly the start address of a symbol, we're done. + if (itn != m_notes.end() && itn->second.address == addr) + return &itn->second; + + // Otherwise, check whether the address is within the bounds of a symbol. + if (itn == m_notes.begin()) + return nullptr; + + do + { + --itn; + + // If itn's range reaches the address. + if (addr < itn->second.address + itn->second.size) + return &itn->second; + + // If layer is 0, it's the last note that could possibly reach the address, as there are no more + // underlying notes. + } while (itn != m_notes.begin() && itn->second.layer != 0); + + return nullptr; +} + std::string_view PPCSymbolDB::GetDescription(u32 addr) { if (const Common::Symbol* const symbol = GetSymbolFromAddr(addr)) @@ -406,6 +476,7 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string& if (strlen(name) > 0) { bool good; + // Notes will be treated the same as Data. const Common::Symbol::Type type = section_name == ".text" || section_name == ".init" ? Common::Symbol::Type::Function : Common::Symbol::Type::Data; @@ -438,7 +509,11 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string& if (good) { ++good_count; - AddKnownSymbol(guard, vaddress, size, name_string, object_filename_string, type); + + if (section_name == ".note") + AddKnownNote(vaddress, size, name); + else + AddKnownSymbol(guard, vaddress, size, name_string, object_filename_string, type); } else { @@ -448,6 +523,7 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string& } Index(); + DetermineNoteLayers(); NOTICE_LOG_FMT(SYMBOLS, "{} symbols loaded, {} symbols ignored.", good_count, bad_count); return true; } @@ -495,6 +571,17 @@ bool PPCSymbolDB::SaveSymbolMap(const std::string& filename) const file.WriteString(line); } + // Write .note section + auto note_symbols = m_notes | std::views::transform([](auto f) { return f.second; }); + file.WriteString("\n.note section layout\n"); + for (const auto& symbol : note_symbols) + { + // Write symbol address, size, virtual address, alignment, name + const std::string line = fmt::format("{:08x} {:06x} {:08x} {} {}\n", symbol.address, + symbol.size, symbol.address, 0, symbol.name); + file.WriteString(line); + } + return true; } diff --git a/Source/Core/Core/PowerPC/PPCSymbolDB.h b/Source/Core/Core/PowerPC/PPCSymbolDB.h index de3e210327..c9fae570d8 100644 --- a/Source/Core/Core/PowerPC/PPCSymbolDB.h +++ b/Source/Core/Core/PowerPC/PPCSymbolDB.h @@ -25,13 +25,16 @@ public: void AddKnownSymbol(const Core::CPUThreadGuard& guard, u32 startAddr, u32 size, const std::string& name, const std::string& object_name, Common::Symbol::Type type = Common::Symbol::Type::Function); + void AddKnownNote(u32 start_addr, u32 size, const std::string& name); Common::Symbol* GetSymbolFromAddr(u32 addr) override; + bool NoteExists() const { return !m_notes.empty(); } + Common::Note* GetNoteFromAddr(u32 addr); + void DetermineNoteLayers(); std::string_view GetDescription(u32 addr); void FillInCallers(); - bool LoadMap(const Core::CPUThreadGuard& guard, const std::string& filename, bool bad = false); bool SaveSymbolMap(const std::string& filename) const; bool SaveCodeMap(const Core::CPUThreadGuard& guard, const std::string& filename) const; diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp index 1f5de76ff0..fd9155a680 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp @@ -137,8 +137,9 @@ constexpr int CODE_VIEW_COLUMN_ADDRESS = 1; constexpr int CODE_VIEW_COLUMN_INSTRUCTION = 2; constexpr int CODE_VIEW_COLUMN_PARAMETERS = 3; constexpr int CODE_VIEW_COLUMN_DESCRIPTION = 4; -constexpr int CODE_VIEW_COLUMN_BRANCH_ARROWS = 5; -constexpr int CODE_VIEW_COLUMNCOUNT = 6; +constexpr int CODE_VIEW_COLUMN_NOTE = 5; +constexpr int CODE_VIEW_COLUMN_BRANCH_ARROWS = 6; +constexpr int CODE_VIEW_COLUMNCOUNT = 7; CodeViewWidget::CodeViewWidget() : m_system(Core::System::GetInstance()), m_ppc_symbol_db(m_system.GetPPCSymbolDB()) @@ -161,6 +162,7 @@ CodeViewWidget::CodeViewWidget() setHorizontalHeaderItem(CODE_VIEW_COLUMN_INSTRUCTION, new QTableWidgetItem(tr("Instr."))); setHorizontalHeaderItem(CODE_VIEW_COLUMN_PARAMETERS, new QTableWidgetItem(tr("Parameters"))); setHorizontalHeaderItem(CODE_VIEW_COLUMN_DESCRIPTION, new QTableWidgetItem(tr("Symbols"))); + setHorizontalHeaderItem(CODE_VIEW_COLUMN_NOTE, new QTableWidgetItem(tr("Notes"))); setHorizontalHeaderItem(CODE_VIEW_COLUMN_BRANCH_ARROWS, new QTableWidgetItem(tr("Branches"))); setFont(Settings::Instance().GetDebugFont()); @@ -333,6 +335,11 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard) std::string param = (split == std::string::npos ? "" : disas.substr(split + 1)); const std::string_view desc = debug_interface.GetDescription(addr); + const Common::Note* note = m_ppc_symbol_db.GetNoteFromAddr(addr); + std::string note_string; + if (note != nullptr) + note_string = note->name; + // Adds whitespace and a minimum size to ins and param. Helps to prevent frequent resizing while // scrolling. const QString ins_formatted = @@ -344,9 +351,11 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard) auto* ins_item = new QTableWidgetItem(ins_formatted); auto* param_item = new QTableWidgetItem(param_formatted); auto* description_item = new QTableWidgetItem(desc_formatted); + auto* note_item = new QTableWidgetItem(QString::fromStdString(note_string)); auto* branch_item = new QTableWidgetItem(); - for (auto* item : {bp_item, addr_item, ins_item, param_item, description_item, branch_item}) + for (auto* item : + {bp_item, addr_item, ins_item, param_item, description_item, note_item, branch_item}) { item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); item->setData(Qt::UserRole, addr); @@ -408,6 +417,7 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard) setItem(i, CODE_VIEW_COLUMN_INSTRUCTION, ins_item); setItem(i, CODE_VIEW_COLUMN_PARAMETERS, param_item); setItem(i, CODE_VIEW_COLUMN_DESCRIPTION, description_item); + setItem(i, CODE_VIEW_COLUMN_NOTE, note_item); setItem(i, CODE_VIEW_COLUMN_BRANCH_ARROWS, branch_item); if (addr == GetAddress()) @@ -416,6 +426,9 @@ void CodeViewWidget::Update(const Core::CPUThreadGuard* guard) } } + m_ppc_symbol_db.NoteExists() ? showColumn(CODE_VIEW_COLUMN_NOTE) : + hideColumn(CODE_VIEW_COLUMN_NOTE); + CalculateBranchIndentation(); m_ppc_symbol_db.FillInCallers();