mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-24 19:11:37 +02:00
Debugger symbols: Add new symbol type: Notes.. Notes are for naming single instructions, or small groups of instructions.
Notes are separate from function symbols, and can be searched separately. Unlike functions, notes of different length can overlap each other. In the instruction window, a note will always display over the function symbol.
This commit is contained in:
@ -51,6 +51,7 @@ void SymbolDB::Clear(const char* prefix)
|
||||
{
|
||||
// TODO: honor prefix
|
||||
m_functions.clear();
|
||||
m_notes.clear();
|
||||
m_checksum_to_function.clear();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
Reference in New Issue
Block a user