summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Source/Core/Common/SymbolDB.cpp1
-rw-r--r--Source/Core/Common/SymbolDB.h13
-rw-r--r--Source/Core/Core/PowerPC/PPCSymbolDB.cpp89
-rw-r--r--Source/Core/Core/PowerPC/PPCSymbolDB.h5
-rw-r--r--Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp19
5 files changed, 122 insertions, 5 deletions
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<u32, Symbol>;
+ using XNoteMap = std::map<u32, Note>;
using XFuncPtrMap = std::map<u32, std::set<Symbol*>>;
SymbolDB();
@@ -86,6 +97,7 @@ public:
std::vector<Symbol*> 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();