https://github.com/satyajanga updated 
https://github.com/llvm/llvm-project/pull/217932

>From 502f4e37439e8e2771363e0e29788da61f0a67c8 Mon Sep 17 00:00:00 2001
From: satya janga <[email protected]>
Date: Fri, 21 Aug 2026 13:55:59 -0700
Subject: [PATCH 1/2] [lldb] Prefer readers with detailed debug information

Add a Symbols ability for object-file symbol data and make SymbolFileSymtab 
advertise it instead of claiming full Functions or GlobalVariables.

Order the ability bits so the existing numeric comparison prefers richer debug 
information. In particular, CompileUnits plus LineTables outranks Symbols plus 
CompileUnits.

Add focused coverage for plugin selection and SymbolFileSymtab abilities.
---
 lldb/include/lldb/Symbol/SymbolFile.h         | 24 +++--
 .../SymbolFile/Symtab/SymbolFileSymtab.cpp    | 13 +--
 lldb/unittests/Symbol/CMakeLists.txt          |  1 +
 lldb/unittests/Symbol/SymbolFileTest.cpp      | 95 +++++++++++++++++++
 lldb/unittests/Symbol/SymtabTest.cpp          |  5 +
 5 files changed, 123 insertions(+), 15 deletions(-)
 create mode 100644 lldb/unittests/Symbol/SymbolFileTest.cpp

diff --git a/lldb/include/lldb/Symbol/SymbolFile.h 
b/lldb/include/lldb/Symbol/SymbolFile.h
index b49c5ae230062..8174661b446b3 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -64,16 +64,22 @@ class SymbolFile : public PluginInterface {
   // Each symbol file can claim to support one or more symbol file abilities.
   // These get returned from SymbolFile::GetAbilities(). These help us to
   // determine which plug-in will be best to load the debug information found
-  // in files.
+  // in files. The values are ordered so that a simple numeric comparison
+  // prefers detailed debug information over data read directly from an object
+  // file's symbol table.
   enum Abilities {
-    CompileUnits = (1u << 0),
-    LineTables = (1u << 1),
-    Functions = (1u << 2),
-    Blocks = (1u << 3),
-    GlobalVariables = (1u << 4),
-    LocalVariables = (1u << 5),
-    VariableTypes = (1u << 6),
-    kAllAbilities = ((1u << 7) - 1u)
+    Symbols = (1u << 0),
+    CompileUnits = (1u << 1),
+    LineTables = (1u << 2),
+    Functions = (1u << 3),
+    Blocks = (1u << 4),
+    GlobalVariables = (1u << 5),
+    LocalVariables = (1u << 6),
+    VariableTypes = (1u << 7),
+    // All detailed debug-information abilities. Symbols is excluded because
+    // it describes information from the object file's symbol table.
+    kAllAbilities = CompileUnits | LineTables | Functions | Blocks |
+        GlobalVariables | LocalVariables | VariableTypes
   };
 
   static SymbolFile *FindPlugin(lldb::ObjectFileSP objfile_sp);
diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp 
b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
index 9c298374101fa..57fe9090aa694 100644
--- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
+++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -60,9 +60,13 @@ uint32_t SymbolFileSymtab::CalculateAbilities() {
   if (m_objfile_sp) {
     const Symtab *symtab = m_objfile_sp->GetSymtab();
     if (symtab) {
-      // The snippet of code below will get the indexes the module symbol table
-      // entries that are code, data, or function related (debug info), sort
-      // them by value (address) and dump the sorted symbols.
+      // Get the indexes of source, code, data, and function-related entries in
+      // the module symbol table. Only source-file entries provide a genuine
+      // debug-info ability. Code and data entries remain available as symbols
+      // but are not equivalent to debug-info functions or global variables.
+      if (symtab->GetNumSymbols() > 0)
+        abilities |= Symbols;
+
       if (symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile,
                                               m_source_indexes)) {
         abilities |= CompileUnits;
@@ -72,20 +76,17 @@ uint32_t SymbolFileSymtab::CalculateAbilities() {
               eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny,
               m_func_indexes)) {
         symtab->SortSymbolIndexesByValue(m_func_indexes, true);
-        abilities |= Functions;
       }
 
       if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, 
Symtab::eDebugNo,
                                               Symtab::eVisibilityAny,
                                               m_code_indexes)) {
         symtab->SortSymbolIndexesByValue(m_code_indexes, true);
-        abilities |= Functions;
       }
 
       if (symtab->AppendSymbolIndexesWithType(eSymbolTypeData,
                                               m_data_indexes)) {
         symtab->SortSymbolIndexesByValue(m_data_indexes, true);
-        abilities |= GlobalVariables;
       }
 
       lldb_private::Symtab::IndexCollection objc_class_indexes;
diff --git a/lldb/unittests/Symbol/CMakeLists.txt 
b/lldb/unittests/Symbol/CMakeLists.txt
index 0fdbc9d72445e..c3aa38e36a5c4 100644
--- a/lldb/unittests/Symbol/CMakeLists.txt
+++ b/lldb/unittests/Symbol/CMakeLists.txt
@@ -5,6 +5,7 @@ add_lldb_unittest(SymbolTests
   MangledTest.cpp
   PostfixExpressionTest.cpp
   SymbolLocatorTest.cpp
+  SymbolFileTest.cpp
   SymbolTest.cpp
   SymtabTest.cpp
   SymStoreTest.cpp
diff --git a/lldb/unittests/Symbol/SymbolFileTest.cpp 
b/lldb/unittests/Symbol/SymbolFileTest.cpp
new file mode 100644
index 0000000000000..9c14e637990a9
--- /dev/null
+++ b/lldb/unittests/Symbol/SymbolFileTest.cpp
@@ -0,0 +1,95 @@
+//===-- SymbolFileTest.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class FakeSymbolFile : public SymbolFileSymtab {
+public:
+  static void Initialize() {
+    PluginManager::RegisterPlugin("SymbolOnlyFakeSymbolFile", "",
+                                  CreateSymbolOnlyInstance);
+    PluginManager::RegisterPlugin("LineTableFakeSymbolFile", "",
+                                  CreateLineTableInstance);
+    PluginManager::RegisterPlugin("SymtabLikeFakeSymbolFile", "",
+                                  CreateSymtabInstance);
+  }
+
+  static void Terminate() {
+    PluginManager::UnregisterPlugin(CreateSymtabInstance);
+    PluginManager::UnregisterPlugin(CreateLineTableInstance);
+    PluginManager::UnregisterPlugin(CreateSymbolOnlyInstance);
+  }
+
+  llvm::StringRef GetPluginName() override { return m_plugin_name; }
+  uint32_t CalculateAbilities() override { return m_abilities; }
+
+private:
+  FakeSymbolFile(ObjectFileSP objfile_sp, llvm::StringRef plugin_name,
+                 uint32_t abilities)
+      : SymbolFileSymtab(std::move(objfile_sp)), m_plugin_name(plugin_name),
+        m_abilities(abilities) {}
+
+  static SymbolFile *CreateSymbolOnlyInstance(ObjectFileSP objfile_sp) {
+    return new FakeSymbolFile(std::move(objfile_sp), 
"SymbolOnlyFakeSymbolFile",
+                              Symbols);
+  }
+
+  static SymbolFile *CreateSymtabInstance(ObjectFileSP objfile_sp) {
+    return new FakeSymbolFile(std::move(objfile_sp), 
"SymtabLikeFakeSymbolFile",
+                              Symbols | CompileUnits);
+  }
+
+  static SymbolFile *CreateLineTableInstance(ObjectFileSP objfile_sp) {
+    return new FakeSymbolFile(std::move(objfile_sp), "LineTableFakeSymbolFile",
+                              CompileUnits | LineTables);
+  }
+
+  llvm::StringRef m_plugin_name;
+  uint32_t m_abilities;
+};
+
+class SymbolFileTest : public testing::Test {
+  SubsystemRAII<ObjectFileELF, FakeSymbolFile> subsystems;
+};
+
+TEST_F(SymbolFileTest, FindPluginPrefersLineTablesOverSymbols) {
+  llvm::Expected<TestFile> file = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_386
+)");
+  ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(file->moduleSpec());
+  ObjectFile *object_file = module_sp->GetObjectFile();
+  ASSERT_NE(object_file, nullptr);
+
+  std::unique_ptr<SymbolFile> symbol_file(
+      SymbolFile::FindPlugin(object_file->shared_from_this()));
+  ASSERT_NE(symbol_file, nullptr);
+  EXPECT_EQ(symbol_file->GetPluginName(), "LineTableFakeSymbolFile");
+  EXPECT_EQ(
+      symbol_file->GetAbilities(),
+      static_cast<uint32_t>(SymbolFile::CompileUnits | 
SymbolFile::LineTables));
+}
+
+} // namespace
diff --git a/lldb/unittests/Symbol/SymtabTest.cpp 
b/lldb/unittests/Symbol/SymtabTest.cpp
index fda92e4044919..dba75c0f6e1f6 100644
--- a/lldb/unittests/Symbol/SymtabTest.cpp
+++ b/lldb/unittests/Symbol/SymtabTest.cpp
@@ -739,6 +739,11 @@ TEST_F(SymtabTest, TestSymbolFileCreatedOnDemand) {
   // And we should be able to get it again once it has been created.
   Symtab *cached_module_symtab = module_sp->GetSymtab(/*can_create=*/false);
   ASSERT_EQ(module_symtab, cached_module_symtab);
+
+  SymbolFile *symbol_file = module_sp->GetSymbolFile();
+  ASSERT_NE(symbol_file, nullptr);
+  EXPECT_EQ(symbol_file->GetAbilities(),
+            static_cast<uint32_t>(SymbolFile::Symbols));
 }
 
 TEST_F(SymtabTest, TestSymbolTableCreatedOnDemand) {

>From d9151ed9b8e0a73dd4f1e71cecf18e058095c9f4 Mon Sep 17 00:00:00 2001
From: satya janga <[email protected]>
Date: Fri, 21 Aug 2026 14:03:45 -0700
Subject: [PATCH 2/2] [lldb][DWARF] Support standalone line tables

Parse valid .debug_line contributions when .debug_info is absent and create 
LLDB CompileUnit objects without synthesizing DWARFUnit objects. Build support 
files, line tables, and address ranges directly from the parsed contributions.

Add an SBAPI regression test for a DWARF v2 line-only object and focused 
coverage for malformed and padded line tables.
---
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      | 237 +++++++++++++++---
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |   6 +
 .../TestStandaloneDebugLine.py                |  63 +++++
 .../standalone-debug-line/main.s              |  14 ++
 .../DWARF/x86/standalone-debug-line.s         | 160 ++++++++++++
 5 files changed, 446 insertions(+), 34 deletions(-)
 create mode 100644 
lldb/test/API/python_api/symbol-context/standalone-debug-line/TestStandaloneDebugLine.py
 create mode 100644 
lldb/test/API/python_api/symbol-context/standalone-debug-line/main.s
 create mode 100644 lldb/test/Shell/SymbolFile/DWARF/x86/standalone-debug-line.s

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index b0007f04a31ab..899d3fc78b93a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -308,6 +308,68 @@ static void ParseSupportFilesFromPrologue(
   }
 }
 
+struct lldb_private::plugin::dwarf::StandaloneDWARFLineTableInfo {
+  std::vector<llvm::DWARFDebugLine::LineTable> line_tables;
+  llvm::once_flag aranges_once_flag;
+  DWARFDebugAranges aranges;
+
+  const llvm::DWARFDebugLine::LineTable *GetLineTable(uint32_t cu_idx) const;
+
+  const DWARFDebugAranges &GetAranges(lldb::addr_t first_code_address);
+};
+
+static std::unique_ptr<LineTable>
+ConvertLineTable(CompileUnit &comp_unit,
+                 const llvm::DWARFDebugLine::LineTable &line_table,
+                 lldb::addr_t first_code_address) {
+  // FIXME: Rather than parsing the whole line table and then copying it over
+  // into LLDB, we should explore using a callback to populate the line table
+  // while we parse to reduce memory usage.
+  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())
+    return nullptr;
+  return &line_tables[cu_idx];
+}
+
+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) {
+      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;
+}
+
 void SymbolFileDWARF::Initialize() {
   LogChannelDWARF::Initialize();
   PluginManager::RegisterPlugin(GetPluginNameStatic(),
@@ -651,11 +713,6 @@ uint32_t SymbolFileDWARF::CalculateAbilities() {
         return 0;
       }
 
-      section =
-          section_list->FindSectionByType(eSectionTypeDWARFDebugLine, true)
-              .get();
-      if (section)
-        debug_line_file_size = section->GetFileSize();
     } else {
       llvm::StringRef symfile_dir = m_objfile_sp->GetFileSpec().GetDirectory();
       if (symfile_dir.contains_insensitive(".dsym")) {
@@ -676,6 +733,12 @@ uint32_t SymbolFileDWARF::CalculateAbilities() {
       }
     }
 
+    // .debug_line may exist without .debug_info, so detect it independently.
+    section =
+        section_list->FindSectionByType(eSectionTypeDWARFDebugLine, 
true).get();
+    if (section)
+      debug_line_file_size = section->GetFileSize();
+
     constexpr uint64_t MaxDebugInfoSize = (1ull) << DW_DIE_OFFSET_MAX_BITSIZE;
     if (debug_info_file_size >= MaxDebugInfoSize) {
       m_objfile_sp->GetModule()->ReportWarning(
@@ -684,12 +747,18 @@ uint32_t SymbolFileDWARF::CalculateAbilities() {
       return 0;
     }
 
-    if (debug_abbrev_file_size > 0 && debug_info_file_size > 0)
+    if (debug_abbrev_file_size > 0 && debug_info_file_size > 0) {
       abilities |= CompileUnits | Functions | Blocks | GlobalVariables |
                    LocalVariables | VariableTypes;
 
-    if (debug_line_file_size > 0)
-      abilities |= LineTables;
+      if (debug_line_file_size > 0)
+        abilities |= LineTables;
+    } else if (debug_line_file_size > 0 &&
+               !GetStandaloneLineTableInfo().line_tables.empty()) {
+      // A standalone line table still supplies enough information to create
+      // compile units, even though there are no DIEs backing them.
+      abilities |= CompileUnits | LineTables;
+    }
   }
   return abilities;
 }
@@ -741,9 +810,59 @@ DWARFDebugInfo &SymbolFileDWARF::DebugInfo() {
   return *m_info;
 }
 
+StandaloneDWARFLineTableInfo &SymbolFileDWARF::GetStandaloneLineTableInfo() {
+  llvm::call_once(m_standalone_line_table_once_flag, [&] {
+    auto info = std::make_unique<StandaloneDWARFLineTableInfo>();
+
+    // A DWARFUnit implies the presence of .debug_info. Standalone line tables
+    // deliberately bypass DWARFUnit creation and directly synthesize LLDB
+    // compile units instead.
+    if (m_context.getOrLoadDebugInfoData().GetByteSize() != 0) {
+      m_standalone_line_table_info = std::move(info);
+      return;
+    }
+
+    llvm::DWARFDataExtractor line_data =
+        m_context.getOrLoadLineData().GetAsLLVMDWARF();
+    if (line_data.getData().empty()) {
+      m_standalone_line_table_info = std::move(info);
+      return;
+    }
+
+    llvm::DWARFContext &context = m_context.GetAsLLVM();
+    llvm::DWARFDebugLine::SectionParser parser(line_data, context,
+                                               context.normal_units());
+    Log *log = GetLog(DWARFLog::DebugInfo);
+    while (!parser.done()) {
+      bool valid = true;
+      auto recoverable = [&](llvm::Error error) {
+        LLDB_LOG_ERROR(log, std::move(error),
+                       "SymbolFileDWARF failed to parse standalone line "
+                       "table: {0}");
+      };
+      auto unrecoverable = [&](llvm::Error error) {
+        valid = false;
+        LLDB_LOG_ERROR(log, std::move(error),
+                       "SymbolFileDWARF failed to parse standalone line "
+                       "table: {0}");
+      };
+      llvm::DWARFDebugLine::LineTable line_table =
+          parser.parseNext(recoverable, unrecoverable);
+      if (valid && SupportedVersion(line_table.Prologue.getVersion()) &&
+          !line_table.Prologue.FileNames.empty())
+        info->line_tables.push_back(std::move(line_table));
+    }
+    m_standalone_line_table_info = std::move(info);
+  });
+  return *m_standalone_line_table_info;
+}
+
 DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) 
{
   if (!comp_unit)
     return nullptr;
+  if (m_standalone_line_table_info &&
+      comp_unit->GetUserData() == m_standalone_line_table_info.get())
+    return nullptr;
 
   // The compile unit ID is the index of the DWARF unit.
   DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(comp_unit->GetID());
@@ -888,6 +1007,12 @@ std::optional<uint32_t> 
SymbolFileDWARF::GetDWARFUnitIndex(uint32_t cu_idx) {
 }
 
 uint32_t SymbolFileDWARF::CalculateNumCompileUnits() {
+  if (!GetDebugMapSymfile()) {
+    StandaloneDWARFLineTableInfo &standalone = GetStandaloneLineTableInfo();
+    if (!standalone.line_tables.empty())
+      return standalone.line_tables.size();
+  }
+
   BuildCuTranslationTable();
   return m_lldb_cu_to_dwarf_unit.empty() ? DebugInfo().GetNumUnits()
                                          : m_lldb_cu_to_dwarf_unit.size();
@@ -895,6 +1020,33 @@ uint32_t SymbolFileDWARF::CalculateNumCompileUnits() {
 
 CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) {
   ASSERT_MODULE_LOCK(this);
+  StandaloneDWARFLineTableInfo &info = GetStandaloneLineTableInfo();
+  const llvm::DWARFDebugLine::LineTable *line_table =
+      GetDebugMapSymfile() ? nullptr : info.GetLineTable(cu_idx);
+  if (line_table) {
+    SupportFileList support_files;
+    ParseSupportFilesFromPrologue(support_files, m_objfile_sp->GetModule(),
+                                  line_table->Prologue,
+                                  m_objfile_sp->GetFileSpec().GetPathStyle());
+
+    // DWARF v5 guarantees that file index zero names the primary source file.
+    // Earlier versions are one-based and have no explicit primary-file field;
+    // use the first file in the table as the best available fallback.
+    const size_t primary_file_idx =
+        line_table->Prologue.getVersion() < 5 ? 1 : 0;
+    SupportFileNSP primary_file =
+        support_files.GetSupportFileAtIndex(primary_file_idx);
+
+    ModuleSP module_sp = m_objfile_sp->GetModule();
+    if (!module_sp)
+      return {};
+    CompUnitSP cu_sp = std::make_shared<CompileUnit>(
+        module_sp, m_standalone_line_table_info.get(), primary_file, cu_idx,
+        eLanguageTypeUnknown, eLazyBoolNo, std::move(support_files));
+    SetCompileUnitAtIndex(cu_idx, cu_sp);
+    return cu_sp;
+  }
+
   if (std::optional<uint32_t> dwarf_idx = GetDWARFUnitIndex(cu_idx)) {
     if (auto *dwarf_cu = llvm::cast_or_null<DWARFCompileUnit>(
             DebugInfo().GetUnitAtIndex(*dwarf_idx)))
@@ -1239,6 +1391,20 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit 
&comp_unit) {
   if (comp_unit.GetLineTable() != nullptr)
     return true;
 
+  if (m_standalone_line_table_info &&
+      comp_unit.GetUserData() == m_standalone_line_table_info.get()) {
+    const llvm::DWARFDebugLine::LineTable *line_table =
+        m_standalone_line_table_info->GetLineTable(comp_unit.GetID());
+    if (!line_table)
+      return false;
+    if (m_first_code_address == LLDB_INVALID_ADDRESS)
+      InitializeFirstCodeAddress();
+    comp_unit.SetLineTable(
+        ConvertLineTable(comp_unit, *line_table, m_first_code_address)
+            .release());
+    return true;
+  }
+
   DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit);
   if (!dwarf_cu)
     return false;
@@ -1255,32 +1421,8 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit 
&comp_unit) {
   if (!line_table)
     return false;
 
-  // FIXME: Rather than parsing the whole line table and then copying it over
-  // into LLDB, we should explore using a callback to populate the line table
-  // while we parse to reduce memory usage.
-  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. Check the comment at the
-    // m_first_code_address declaration for more details on this.
-    if (seq.LowPC < m_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));
-  }
-
   std::unique_ptr<LineTable> line_table_up =
-      std::make_unique<LineTable>(&comp_unit, std::move(sequences));
+      ConvertLineTable(comp_unit, *line_table, m_first_code_address);
 
   if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile()) {
     // We have an object file that has a line table with addresses that are not
@@ -2151,6 +2293,33 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const 
Address &so_addr,
        eSymbolContextLineEntry | eSymbolContextVariable)) {
     lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
 
+    StandaloneDWARFLineTableInfo &standalone = GetStandaloneLineTableInfo();
+    if (!GetDebugMapSymfile() && !standalone.line_tables.empty()) {
+      if (m_first_code_address == LLDB_INVALID_ADDRESS)
+        InitializeFirstCodeAddress();
+      const DWARFDebugAranges &aranges =
+          standalone.GetAranges(m_first_code_address);
+      const dw_offset_t cu_idx = aranges.FindAddress(file_vm_addr);
+      if (cu_idx == DW_INVALID_OFFSET)
+        return 0;
+
+      CompUnitSP cu_sp = GetCompileUnitAtIndex(cu_idx);
+      sc.comp_unit = cu_sp.get();
+      if (!sc.comp_unit)
+        return 0;
+      resolved |= eSymbolContextCompUnit;
+
+      if (resolve_scope & eSymbolContextLineEntry) {
+        if (LineTable *line_table = sc.comp_unit->GetLineTable()) {
+          Address exe_so_addr(so_addr);
+          if (FixupAddress(exe_so_addr) &&
+              line_table->FindLineEntryByAddress(exe_so_addr, sc.line_entry))
+            resolved |= eSymbolContextLineEntry;
+        }
+      }
+      return resolved;
+    }
+
     DWARFDebugInfo &debug_info = DebugInfo();
     const DWARFDebugAranges &aranges = debug_info.GetCompileUnitAranges();
     const dw_offset_t cu_offset = aranges.FindAddress(file_vm_addr);
@@ -2251,7 +2420,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(
   if (resolve_scope & eSymbolContextCompUnit) {
     for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus;
          ++cu_idx) {
-      CompileUnit *dc_cu = ParseCompileUnitAtIndex(cu_idx).get();
+      CompileUnit *dc_cu = GetCompileUnitAtIndex(cu_idx).get();
       if (!dc_cu)
         continue;
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 7321a22e85d81..2659eaa8d4b4d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -60,6 +60,7 @@ class DWARFTypeUnit;
 class SymbolFileDWARFDebugMap;
 class SymbolFileDWARFDwo;
 class SymbolFileDWARFDwp;
+struct StandaloneDWARFLineTableInfo;
 
 #define DIE_IS_BEING_PARSED ((lldb_private::Type *)1)
 
@@ -518,6 +519,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
   void BuildCuTranslationTable();
   std::optional<uint32_t> GetDWARFUnitIndex(uint32_t cu_idx);
 
+  StandaloneDWARFLineTableInfo &GetStandaloneLineTableInfo();
+
   void FindDwpSymbolFile();
 
   const SupportFileList *GetTypeUnitSupportFiles(DWARFTypeUnit &tu);
@@ -540,6 +543,9 @@ class SymbolFileDWARF : public SymbolFileCommon {
   llvm::once_flag m_info_once_flag;
   std::unique_ptr<DWARFDebugInfo> m_info;
 
+  llvm::once_flag m_standalone_line_table_once_flag;
+  std::unique_ptr<StandaloneDWARFLineTableInfo> m_standalone_line_table_info;
+
   std::unique_ptr<llvm::DWARFDebugAbbrev> m_abbr;
   std::unique_ptr<GlobalVariableMap> m_global_aranges_up;
 
diff --git 
a/lldb/test/API/python_api/symbol-context/standalone-debug-line/TestStandaloneDebugLine.py
 
b/lldb/test/API/python_api/symbol-context/standalone-debug-line/TestStandaloneDebugLine.py
new file mode 100644
index 0000000000000..13d6db338b019
--- /dev/null
+++ 
b/lldb/test/API/python_api/symbol-context/standalone-debug-line/TestStandaloneDebugLine.py
@@ -0,0 +1,63 @@
+import os
+
+import lldb
+from lldbsuite.test import configuration
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+
+class StandaloneDebugLineTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipUnlessPlatform(["linux"])
+    @skipIfLLVMTargetMissing("X86")
+    def test(self):
+        object_path = self.getBuildArtifact("line.o")
+        self.runBuildCommand(
+            [
+                os.path.join(configuration.llvm_tools_dir, "llvm-mc"),
+                "-triple=x86_64-pc-linux",
+                "-filetype=obj",
+                "-dwarf-version=2",
+                self.getSourcePath("main.s"),
+                "-o",
+                object_path,
+            ]
+        )
+
+        target = self.createTestTarget(object_path)
+
+        # The regular symbol table advertises functions, while the standalone
+        # line table must make SymbolFileDWARF the preferred reader.
+        module = target.GetModuleAtIndex(0)
+        self.assertTrue(module.FindSection(".debug_line").IsValid())
+        self.assertFalse(module.FindSection(".debug_info").IsValid())
+        self.assertFalse(module.FindSection(".debug_abbrev").IsValid())
+        self.assertTrue(module.FindSection(".symtab").IsValid())
+        self.assertEqual(module.GetNumCompileUnits(), 1)
+
+        # An address must resolve to its symbol, synthetic compile unit, and
+        # line entry. It must not manufacture a DWARF function.
+        symbol = module.FindSymbol("foo", lldb.eSymbolTypeCode)
+        self.assertTrue(symbol.IsValid())
+
+        address = symbol.GetStartAddress()
+        self.assertTrue(address.IsValid())
+        self.assertEqual(address.GetSymbol().GetName(), "foo")
+        self.assertFalse(address.GetFunction().IsValid())
+
+        compile_unit = address.GetCompileUnit()
+        self.assertTrue(compile_unit.IsValid())
+        self.assertEqual(compile_unit.GetFileSpec().GetFilename(), 
"standalone.c")
+
+        line_entry = address.GetLineEntry()
+        self.assertTrue(line_entry.IsValid())
+        self.assertEqual(line_entry.GetFileSpec().GetFilename(), 
"standalone.c")
+        self.assertEqual(line_entry.GetLine(), 42)
+        self.assertEqual(line_entry.GetColumn(), 7)
+
+        # Source-to-address lookup must use the same standalone line table.
+        breakpoint = target.BreakpointCreateByLocation("standalone.c", 42)
+        self.assertEqual(breakpoint.GetNumLocations(), 1)
+        breakpoint_address = breakpoint.GetLocationAtIndex(0).GetAddress()
+        self.assertEqual(breakpoint_address, address)
diff --git 
a/lldb/test/API/python_api/symbol-context/standalone-debug-line/main.s 
b/lldb/test/API/python_api/symbol-context/standalone-debug-line/main.s
new file mode 100644
index 0000000000000..e35bbabdbf7be
--- /dev/null
+++ b/lldb/test/API/python_api/symbol-context/standalone-debug-line/main.s
@@ -0,0 +1,14 @@
+# This file deliberately has a line table and symbols, but no debug-info DIEs.
+        .file 1 "/tmp/standalone.c"
+
+        .text
+        .globl foo
+        .type foo,@function
+foo:
+        .loc 1 42 7
+        nop
+        .loc 1 43 3
+        nop
+        retq
+.Lfoo_end:
+        .size foo, .Lfoo_end-foo
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/standalone-debug-line.s 
b/lldb/test/Shell/SymbolFile/DWARF/x86/standalone-debug-line.s
new file mode 100644
index 0000000000000..798d7d33193e1
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/standalone-debug-line.s
@@ -0,0 +1,160 @@
+# Test malformed and unusual standalone DWARF line tables. The ordinary
+# address and source lookup behavior is covered by the SBAPI test in
+# lldb/test/API/python_api/symbol-context/standalone-debug-line.
+
+# REQUIRES: lld
+# UNSUPPORTED: system-windows
+
+# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj -dwarf-version=2 \
+# RUN:   %s -o %t.good.o
+# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj \
+# RUN:   --defsym MALFORMED_BODY=1 %s -o %t.bad-body.o
+# RUN: ld.lld -e bad_body -Ttext=0x201000 %t.bad-body.o -o %t.bad-body
+# RUN: %lldb %t.bad-body -b -o "image dump symfile" \
+# RUN:   -o "image lookup -a 0x201000 -v" | \
+# RUN:   FileCheck %s --check-prefix=BAD-BODY
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
+# RUN:   %S/debug-types-line-tables.s -o %t.types.o
+# RUN: llvm-objcopy --remove-section=.debug_info %t.types.o %t.types
+# RUN: lldb-test symbols %t.types | FileCheck %s --check-prefix=TYPES
+# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj --defsym INFO_ONLY=1 \
+# RUN:   %s -o %t.info.o
+# RUN: ld.lld -e foo -Ttext=0x201000 %t.good.o %t.info.o -o %t.info
+# RUN: %lldb %t.info -b -o "image dump symfile" \
+# RUN:   -o "image lookup -a 0x201000 -v" | \
+# RUN:   FileCheck %s --check-prefix=INFO
+# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj --defsym RECOVERABLE=1 \
+# RUN:   %s -o %t.recoverable.o
+# RUN: ld.lld -e recoverable -Ttext=0x201000 %t.recoverable.o \
+# RUN:   -o %t.recoverable
+# RUN: %lldb %t.recoverable -b -o "image dump symfile" \
+# RUN:   -o "image lookup -a 0x201000 -v" | \
+# RUN:   FileCheck %s --check-prefix=RECOVERABLE
+
+        .ifdef INFO_ONLY
+        .section .debug_info,"",@progbits
+        .byte 0
+        .else
+        .ifdef MALFORMED_BODY
+        .text
+        .globl bad_body
+        .type bad_body,@function
+bad_body:
+        nop
+        retq
+.Lbad_body_end:
+        .size bad_body, .Lbad_body_end-bad_body
+
+        .section .debug_line,"",@progbits
+.Lbad_body_start:
+        .long .Lbad_body_end_table-.Lbad_body_version
+.Lbad_body_version:
+        .short 2
+        .long .Lbad_body_header_end-.Lbad_body_header
+.Lbad_body_header:
+        .byte 1
+        .byte 1
+        .byte -5
+        .byte 14
+        .byte 13
+        .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
+        .asciz "/tmp"
+        .byte 0
+        .asciz "bad-body.c"
+        .uleb128 1
+        .uleb128 0
+        .uleb128 0
+        .byte 0
+.Lbad_body_header_end:
+        .byte 0, 9, 2
+        .quad bad_body
+        .byte 3
+        .sleb128 6
+        .byte 1
+        .byte 2
+        .uleb128 2
+        .byte 0, 1, 1
+        .byte 3
+.Lbad_body_end_table:
+        .else
+        .ifdef RECOVERABLE
+        .text
+        .globl recoverable
+        .type recoverable,@function
+recoverable:
+        nop
+        retq
+.Lrecoverable_func_end:
+        .size recoverable, .Lrecoverable_func_end-recoverable
+
+        .section .debug_line,"",@progbits
+.Lrecoverable_start:
+        .long .Lrecoverable_end-.Lrecoverable_version
+.Lrecoverable_version:
+        .short 2
+        .long .Lrecoverable_header_end-.Lrecoverable_header
+.Lrecoverable_header:
+        .byte 1
+        .byte 1
+        .byte -5
+        .byte 14
+        .byte 13
+        .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
+        .asciz "/tmp"
+        .byte 0
+        .asciz "recoverable.c"
+        .uleb128 1
+        .uleb128 0
+        .uleb128 0
+        .byte 0
+        # CUDA line tables can contain padding at the end of the prologue.
+        .byte 0, 0, 0, 0
+.Lrecoverable_header_end:
+        .byte 0, 9, 2
+        .quad recoverable
+        .byte 3
+        .sleb128 6
+        .byte 5
+        .uleb128 5
+        .byte 1
+        .byte 2
+        .uleb128 2
+        .byte 0, 1, 1
+.Lrecoverable_end:
+        .else
+        .file 1 "/tmp/standalone-one.c"
+
+        .text
+        .p2align 4
+        .globl foo
+        .type foo,@function
+foo:
+        .loc 1 42 7
+        nop
+        .loc 1 43 3
+        nop
+        retq
+.Lfunc_end:
+        .size foo, .Lfunc_end-foo
+        .endif
+        .endif
+        .endif
+
+# BAD-BODY: SymbolFile symtab
+# BAD-BODY-LABEL: (lldb) image lookup -a 0x201000 -v
+# BAD-BODY-NOT: CompileUnit:
+# BAD-BODY: Symbol: {{.*}}name="bad_body"
+
+# TYPES: Compile units:
+# TYPES: CompileUnit{{.*}}file = '/tmp/b.cc'
+
+# INFO: SymbolFile symtab
+# INFO-LABEL: (lldb) image lookup -a 0x201000 -v
+# INFO-NOT: CompileUnit:
+# INFO: Symbol: {{.*}}name="foo"
+
+# RECOVERABLE: SymbolFile dwarf
+# RECOVERABLE-LABEL: (lldb) image lookup -a 0x201000 -v
+# RECOVERABLE: CompileUnit: {{.*}}file = "/tmp/recoverable.c"
+# RECOVERABLE: LineEntry: {{.*}}/tmp/recoverable.c:7:5
+# RECOVERABLE: Symbol: {{.*}}name="recoverable"

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to