[Lldb-commits] [lldb] [lldb][DWARF] Support standalone line tables (PR #217932)
Greg Clayton via lldb-commits
lldb-commits at lists.llvm.org
Wed Oct 21 19:09:52 PDT 2026
================
@@ -309,6 +309,187 @@ static void ParseSupportFilesFromPrologue(
}
}
+struct lldb_private::plugin::dwarf::StandaloneDWARFLineTableInfo {
+ explicit StandaloneDWARFLineTableInfo(SymbolFileDWARF &symfile)
+ : m_symfile(symfile) {}
+
+ // Keep one entry per .debug_line contribution so compile unit indices remain
+ // stable when a contribution cannot be parsed.
+ std::vector<std::optional<llvm::DWARFDebugLine::LineTable>> line_tables;
+ llvm::once_flag aranges_once_flag;
+ DWARFDebugAranges aranges;
+
+ bool HasLineTables() const;
+ uint32_t CalculateNumCompileUnits();
+ CompUnitSP ParseCompileUnitAtIndex(uint32_t cu_idx);
+ bool ParseLineTable(CompileUnit &comp_unit);
+ uint32_t ResolveSymbolContext(const Address &so_addr,
+ SymbolContextItem resolve_scope,
+ SymbolContext &sc);
+
+ const llvm::DWARFDebugLine::LineTable *GetLineTable(uint32_t cu_idx) const;
+
+ const DWARFDebugAranges &GetAranges(lldb::addr_t first_code_address);
+
+private:
+ SymbolFileDWARF &m_symfile;
+ std::optional<uint32_t> m_num_compile_units;
+};
+
+static std::unique_ptr<LineTable>
+ConvertLineTable(CompileUnit &comp_unit,
+ const llvm::DWARFDebugLine::LineTable &line_table,
+ lldb::addr_t first_code_address) {
+ std::vector<LineTable::Sequence> sequences;
+ // The Sequences view contains only valid line sequences. Don't iterate over
+ // the Rows directly.
+ for (const llvm::DWARFDebugLine::Sequence &seq : line_table.Sequences) {
+ // Ignore line sequences that do not start after the first code address.
+ // All addresses generated in a sequence are incremental so we only need
+ // to check the first one of the sequence.
+ if (seq.LowPC < first_code_address)
+ continue;
+ LineTable::Sequence sequence;
+ for (unsigned idx = seq.FirstRowIndex; idx < seq.LastRowIndex; ++idx) {
+ const llvm::DWARFDebugLine::Row &row = line_table.Rows[idx];
+ LineTable::AppendLineEntryToSequence(
+ sequence, row.Address.Address, row.Line, row.Column, row.File,
+ row.IsStmt, row.BasicBlock, row.PrologueEnd, row.EpilogueBegin,
+ row.EndSequence);
+ }
+ sequences.push_back(std::move(sequence));
+ }
+
+ return std::make_unique<LineTable>(&comp_unit, std::move(sequences));
+}
+
+const llvm::DWARFDebugLine::LineTable *
+StandaloneDWARFLineTableInfo::GetLineTable(uint32_t cu_idx) const {
+ if (cu_idx >= line_tables.size() || !line_tables[cu_idx])
+ return nullptr;
+ return &*line_tables[cu_idx];
+}
+
+bool StandaloneDWARFLineTableInfo::HasLineTables() const {
+ return llvm::any_of(line_tables, [](const auto &line_table) {
+ return line_table.has_value();
+ });
+}
+
+const DWARFDebugAranges &
+StandaloneDWARFLineTableInfo::GetAranges(lldb::addr_t first_code_address) {
+ llvm::call_once(aranges_once_flag, [&] {
+ for (uint32_t cu_idx = 0; cu_idx < line_tables.size(); ++cu_idx) {
+ if (!line_tables[cu_idx])
+ continue;
+ for (const llvm::DWARFDebugLine::Sequence &seq :
+ line_tables[cu_idx]->Sequences) {
+ if (seq.isValid() && seq.LowPC >= first_code_address)
+ aranges.AppendRange(cu_idx, seq.LowPC, seq.HighPC);
+ }
+ }
+ aranges.Sort(/*minimize=*/true);
+ });
+ return aranges;
+}
+
+uint32_t StandaloneDWARFLineTableInfo::CalculateNumCompileUnits() {
+ if (m_num_compile_units)
+ return *m_num_compile_units;
+
+ llvm::DWARFDataExtractor line_data =
+ m_symfile.m_context.getOrLoadLineData().GetAsLLVMDWARF();
+ if (line_data.getData().empty()) {
+ m_num_compile_units = 0;
+ return 0;
+ }
+
+ llvm::DWARFContext &context = m_symfile.m_context.GetAsLLVM();
+ llvm::DWARFDebugLine::SectionParser parser(line_data, context,
+ context.normal_units());
+ Log *log = GetLog(DWARFLog::DebugInfo);
+ auto error_handler = [&](llvm::Error error) {
+ LLDB_LOG_ERROR(log, std::move(error),
+ "SymbolFileDWARF failed to parse standalone line "
+ "table prologue: {0}");
+ };
+ uint32_t num_compile_units = 0;
+ while (!parser.done()) {
+ parser.skip(error_handler, error_handler);
+ ++num_compile_units;
+ }
+ m_num_compile_units = num_compile_units;
+ return num_compile_units;
----------------
clayborg wrote:
In the `SymbolFileDWARF::GetStandaloneLineTableInfo()` function it already parses and store everything in `StandaloneDWARFLineTableInfo::line_tables` right? And the functionality in `SymbolFileDWARF::GetStandaloneLineTableInfo()` really belongs in `StandaloneDWARFLineTableInfo::StandaloneDWARFLineTableInfo(...)` (the constructor).
It would be good if the `StandaloneDWARFLineTableInfo` constructor does as little as possible to construct itself. Like maybe `StandaloneDWARFLineTableInfo::line_tables` is a lazily populated line table array instead of parsing all lines tables up front. So all we would need to do is create the `StandaloneDWARFLineTableInfo::line_tables` array and return its size for this function.
Then as line tables are asked to be created, we create them one by one. The only issue is if we need the address ranges, we will need to parse all of them.
Without changing the code in `SymbolFileDWARF::GetStandaloneLineTableInfo()`, can't we just return `line_tables.size()` here and remove `num_compile_units`?
https://github.com/llvm/llvm-project/pull/217932
More information about the lldb-commits
mailing list