Skip to content

Add support for inline DWARF source files. #75880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 4, 2024

Conversation

adrian-prantl
Copy link
Collaborator

@adrian-prantl adrian-prantl commented Dec 19, 2023

LLVM supports DWARF 5 linetable extension to store source files inline in DWARF. This is particularly useful for compiler-generated source code. This implementation tries to materialize them as temporary files lazily, so SBAPI clients don't need to be aware of them.

rdar://110926168

@adrian-prantl adrian-prantl requested review from clayborg and removed request for JDevlieghere December 19, 2023 01:03
@llvmbot llvmbot added the lldb label Dec 19, 2023
@llvmbot
Copy link
Member

llvmbot commented Dec 19, 2023

@llvm/pr-subscribers-lldb

Author: Adrian Prantl (adrian-prantl)

Changes

LLVM supports DWARF 5 linetable extension to store source files inline in DWARF. This is particularly useful for compiler-generated source code. This implementation tries to materialize them as temporary files lazily, so SBAPI clients don't need to be aware of them.


Full diff: https://github.com/llvm/llvm-project/pull/75880.diff

10 Files Affected:

  • (modified) lldb/include/lldb/Utility/FileSpecList.h (+40-6)
  • (modified) lldb/source/Core/ModuleList.cpp (+5-3)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp (+6-6)
  • (modified) lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp (+3-3)
  • (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+46)
  • (modified) lldb/source/Utility/FileSpecList.cpp (+11-8)
  • (added) lldb/test/API/functionalities/inline-sourcefile/Makefile (+11)
  • (added) lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py (+17)
  • (added) lldb/test/API/functionalities/inline-sourcefile/inline.ll (+39)
  • (added) lldb/test/API/functionalities/inline-sourcefile/main.c (+8)
diff --git a/lldb/include/lldb/Utility/FileSpecList.h b/lldb/include/lldb/Utility/FileSpecList.h
index 77587aa917916b..078fd7208e7b5f 100644
--- a/lldb/include/lldb/Utility/FileSpecList.h
+++ b/lldb/include/lldb/Utility/FileSpecList.h
@@ -17,13 +17,40 @@
 namespace lldb_private {
 class Stream;
 
+/// Represents a source file whose contents is known (for example
+/// because it can be reconstructed from debug info), but that
+/// hasn't been written to a local disk yet.
+struct LazyFileSpec {
+  virtual ~LazyFileSpec() {}
+  virtual const FileSpec &Materialize() = 0;
+};
+
+/// Wraps either a FileSpec that represents a local file or a
+/// LazyFileSpec that could be materialized into a local file.
+class FileSpecHolder {
+  FileSpec m_file_spec;
+  std::shared_ptr<LazyFileSpec> m_lazy;
+public:
+  FileSpecHolder(const FileSpec &spec, std::shared_ptr<LazyFileSpec> lazy = {})
+      : m_file_spec(spec), m_lazy(lazy) {}
+  FileSpecHolder(const FileSpecHolder &other) = default;
+  FileSpecHolder(FileSpecHolder &&other) = default;
+  FileSpecHolder &operator=(const FileSpecHolder &other) = default;
+  const FileSpec &GetSpecOnly() const { return m_file_spec; };
+  const FileSpec &Materialize() const {
+    if (m_lazy)
+      return m_lazy->Materialize();
+    return m_file_spec;
+  }
+};
+
 /// \class FileSpecList FileSpecList.h "lldb/Utility/FileSpecList.h"
 /// A file collection class.
 ///
 /// A class that contains a mutable list of FileSpec objects.
 class FileSpecList {
 public:
-  typedef std::vector<FileSpec> collection;
+  typedef std::vector<FileSpecHolder> collection;
   typedef collection::const_iterator const_iterator;
 
   /// Default constructor.
@@ -38,7 +65,10 @@ class FileSpecList {
   FileSpecList(FileSpecList &&rhs) = default;
 
   /// Initialize this object from a vector of FileSpecs
-  FileSpecList(std::vector<FileSpec> &&rhs) : m_files(std::move(rhs)) {}
+  FileSpecList(std::vector<FileSpec> &&rhs) {
+    for (auto &fs : rhs)
+      m_files.emplace_back(fs);
+  }
 
   /// Destructor.
   ~FileSpecList();
@@ -83,7 +113,11 @@ class FileSpecList {
   /// \param[in] args
   ///     Arguments to create the FileSpec
   template <class... Args> void EmplaceBack(Args &&...args) {
-    m_files.emplace_back(std::forward<Args>(args)...);
+    m_files.emplace_back(FileSpec(std::forward<Args>(args)...));
+  }
+
+  void Append(FileSpecHolder &&fsh) {
+    m_files.push_back(std::move(fsh));
   }
 
   /// Clears the file list.
@@ -175,10 +209,10 @@ class FileSpecList {
 
   bool Insert(size_t idx, const FileSpec &file) {
     if (idx < m_files.size()) {
-      m_files.insert(m_files.begin() + idx, file);
+      m_files.insert(m_files.begin() + idx, FileSpecHolder(file));
       return true;
     } else if (idx == m_files.size()) {
-      m_files.push_back(file);
+      m_files.push_back(FileSpecHolder(file));
       return true;
     }
     return false;
@@ -186,7 +220,7 @@ class FileSpecList {
 
   bool Replace(size_t idx, const FileSpec &file) {
     if (idx < m_files.size()) {
-      m_files[idx] = file;
+      m_files[idx] = FileSpecHolder(file);
       return true;
     }
     return false;
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index aa89c93c8d0521..3b6c3ea899caf7 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -164,11 +164,13 @@ void ModuleListProperties::UpdateSymlinkMappings() {
   llvm::sys::ScopedWriter lock(m_symlink_paths_mutex);
   const bool notify = false;
   m_symlink_paths.Clear(notify);
-  for (FileSpec symlink : list) {
+  for (auto symlink : list) {
     FileSpec resolved;
-    Status status = FileSystem::Instance().Readlink(symlink, resolved);
+    Status status =
+        FileSystem::Instance().Readlink(symlink.Materialize(), resolved);
     if (status.Success())
-      m_symlink_paths.Append(symlink.GetPath(), resolved.GetPath(), notify);
+      m_symlink_paths.Append(symlink.Materialize().GetPath(),
+                             resolved.GetPath(), notify);
   }
 }
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 68bdd96e8adb03..ec03a38752c2fe 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -488,8 +488,8 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
 
   // Build a list of files we need to analyze to build the configuration.
   FileSpecList files;
-  for (const FileSpec &f : sc.comp_unit->GetSupportFiles())
-    files.AppendIfUnique(f);
+  for (auto &f : sc.comp_unit->GetSupportFiles())
+    files.AppendIfUnique(f.Materialize());
   // We also need to look at external modules in the case of -gmodules as they
   // contain the support files for libc++ and the C library.
   llvm::DenseSet<SymbolFile *> visited_symbol_files;
@@ -498,8 +498,8 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
         for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) {
           const FileSpecList &support_files =
               module.GetCompileUnitAtIndex(i)->GetSupportFiles();
-          for (const FileSpec &f : support_files) {
-            files.AppendIfUnique(f);
+          for (auto &f : support_files) {
+            files.AppendIfUnique(f.Materialize());
           }
         }
         return false;
@@ -508,9 +508,9 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
   LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze",
            files.GetSize());
   if (log && log->GetVerbose()) {
-    for (const FileSpec &f : files)
+    for (auto &f : files)
       LLDB_LOGV(log, "[C++ module config] Analyzing support file: {0}",
-                f.GetPath());
+                f.Materialize().GetPath());
   }
 
   // Try to create a configuration from the files. If there is no valid
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
index 847dab6592b886..0ea5b1581c8e06 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
@@ -134,9 +134,9 @@ bool CppModuleConfiguration::hasValidConfig() {
 CppModuleConfiguration::CppModuleConfiguration(
     const FileSpecList &support_files, const llvm::Triple &triple) {
   // Analyze all files we were given to build the configuration.
-  bool error = !llvm::all_of(support_files,
-                             std::bind(&CppModuleConfiguration::analyzeFile,
-                                       this, std::placeholders::_1, triple));
+  bool error = !llvm::all_of(support_files, [&](auto &file) {
+    return CppModuleConfiguration::analyzeFile(file.Materialize(), triple);
+  });
   // If we have a valid configuration at this point, set the
   // include directories and module list that should be used.
   if (!error && hasValidConfig()) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 7eddc5074eff12..f9faa85056b1a0 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -10,6 +10,7 @@
 
 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/Threading.h"
 
@@ -235,6 +236,51 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module,
   for (size_t idx = first_file_idx; idx <= last_file_idx; ++idx) {
     std::string remapped_file;
     if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) {
+      auto entry = prologue.getFileNameEntry(idx);
+      auto source = entry.Source.getAsCString();
+      if (!source)
+        consumeError(source.takeError());
+      else {
+        llvm::StringRef source_ref(*source);
+        if (!source_ref.empty()) {
+          /// Wrap a path for an in-DWARF source file. Lazily write it
+          /// to disk when Materialize() is called.
+          struct LazyDWARFFile : public LazyFileSpec {
+            LazyDWARFFile(std::string file_name, llvm::StringRef source,
+                          FileSpec::Style style)
+                : file_name(file_name), source(source), style(style) {}
+            std::string file_name;
+            FileSpec tmp_file;
+            llvm::StringRef source;
+            std::unique_ptr<llvm::FileRemover> remover;
+            FileSpec::Style style;
+
+            const FileSpec &Materialize() override {
+              if (tmp_file)
+                return tmp_file;
+              llvm::SmallString<0> name;
+              int fd;
+              auto ec = llvm::sys::fs::createTemporaryFile(
+                  "", llvm::sys::path::filename(file_name, style), fd, name);
+              if (ec || fd <= 0) {
+                LLDB_LOG(GetLog(DWARFLog::DebugInfo),
+                         "Could not create temporary file");
+                return tmp_file;
+              }
+              remover = std::make_unique<llvm::FileRemover>(name);
+              NativeFile file(fd, File::eOpenOptionWriteOnly, true);
+              size_t num_bytes = source.size();
+              file.Write(source.data(), num_bytes);
+              tmp_file.SetPath(name);
+              return tmp_file;
+            }
+          };
+          support_files.Append(FileSpecHolder(
+              FileSpec(*file_path),
+              std::make_shared<LazyDWARFFile>(*file_path, *source, style)));
+          continue;
+        }
+      }
       if (auto remapped = module->RemapSourceFile(llvm::StringRef(*file_path)))
         remapped_file = *remapped;
       else
diff --git a/lldb/source/Utility/FileSpecList.cpp b/lldb/source/Utility/FileSpecList.cpp
index d5369ac4bbe516..749fdcc6431117 100644
--- a/lldb/source/Utility/FileSpecList.cpp
+++ b/lldb/source/Utility/FileSpecList.cpp
@@ -30,7 +30,9 @@ void FileSpecList::Append(const FileSpec &file_spec) {
 // a copy of "file_spec".
 bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
   collection::iterator end = m_files.end();
-  if (find(m_files.begin(), end, file_spec) == end) {
+  if (find_if(m_files.begin(), end, [&](auto &holder) {
+        return holder.GetSpecOnly() == file_spec;
+      }) == end) {
     m_files.push_back(file_spec);
     return true;
   }
@@ -44,7 +46,7 @@ void FileSpecList::Clear() { m_files.clear(); }
 void FileSpecList::Dump(Stream *s, const char *separator_cstr) const {
   collection::const_iterator pos, end = m_files.end();
   for (pos = m_files.begin(); pos != end; ++pos) {
-    pos->Dump(s->AsRawOstream());
+    pos->GetSpecOnly().Dump(s->AsRawOstream());
     if (separator_cstr && ((pos + 1) != end))
       s->PutCString(separator_cstr);
   }
@@ -64,13 +66,14 @@ size_t FileSpecList::FindFileIndex(size_t start_idx, const FileSpec &file_spec,
   bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
 
   for (size_t idx = start_idx; idx < num_files; ++idx) {
+    auto f = m_files[idx].GetSpecOnly();
     if (compare_filename_only) {
       if (ConstString::Equals(
-              m_files[idx].GetFilename(), file_spec.GetFilename(),
-              file_spec.IsCaseSensitive() || m_files[idx].IsCaseSensitive()))
+              f.GetFilename(), file_spec.GetFilename(),
+              file_spec.IsCaseSensitive() || f.IsCaseSensitive()))
         return idx;
     } else {
-      if (FileSpec::Equal(m_files[idx], file_spec, full))
+      if (FileSpec::Equal(f, file_spec, full))
         return idx;
     }
   }
@@ -92,7 +95,7 @@ size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
   const bool full = !file_spec.GetDirectory().IsEmpty();
 
   for (size_t idx = start_idx; idx < num_files; ++idx) {
-    const FileSpec &curr_file = m_files[idx];
+    const FileSpec &curr_file = m_files[idx].GetSpecOnly();
 
     // Always start by matching the filename first
     if (!curr_file.FileEquals(file_spec))
@@ -135,7 +138,7 @@ size_t FileSpecList::FindCompatibleIndex(size_t start_idx,
 // an empty FileSpec object will be returned.
 const FileSpec &FileSpecList::GetFileSpecAtIndex(size_t idx) const {
   if (idx < m_files.size())
-    return m_files[idx];
+    return m_files[idx].Materialize();
   static FileSpec g_empty_file_spec;
   return g_empty_file_spec;
 }
@@ -148,7 +151,7 @@ size_t FileSpecList::MemorySize() const {
   size_t mem_size = sizeof(FileSpecList);
   collection::const_iterator pos, end = m_files.end();
   for (pos = m_files.begin(); pos != end; ++pos) {
-    mem_size += pos->MemorySize();
+    mem_size += pos->GetSpecOnly().MemorySize();
   }
 
   return mem_size;
diff --git a/lldb/test/API/functionalities/inline-sourcefile/Makefile b/lldb/test/API/functionalities/inline-sourcefile/Makefile
new file mode 100644
index 00000000000000..adb29d3a88e26c
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/Makefile
@@ -0,0 +1,11 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -gdwarf-5
+
+include Makefile.rules
+
+OBJECTS += inline.o
+
+$(EXE): main.c inline.o
+
+%.o: %.ll
+	$(CC) $< -c -o $@
diff --git a/lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py b/lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py
new file mode 100644
index 00000000000000..6daf970b895b0f
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py
@@ -0,0 +1,17 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbplatform
+from lldbsuite.test import lldbutil
+
+
+class InlineSourceFilesTestCase(TestBase):
+    @skipIf(compiler="gcc")
+    @skipIf(compiler="clang", compiler_version=["<", "18.0"])
+    def test(self):
+        """Test DWARF inline source files."""
+        self.build()
+        #target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
+        #    self, 'break here', lldb.SBFileSpec('inlined.c'))
+        target, process, thread, bkpt = lldbutil.run_to_name_breakpoint(
+            self, 'f')
diff --git a/lldb/test/API/functionalities/inline-sourcefile/inline.ll b/lldb/test/API/functionalities/inline-sourcefile/inline.ll
new file mode 100644
index 00000000000000..56194e45b81387
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/inline.ll
@@ -0,0 +1,39 @@
+; ModuleID = '/tmp/t.c'
+source_filename = "/tmp/t.c"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
+define void @f() #0 !dbg !9 {
+entry:
+  call void @stop(), !dbg !13
+  ret void, !dbg !14
+}
+
+declare void @stop(...) #1
+
+attributes #0 = { noinline nounwind optnone ssp uwtable(sync) }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0git ([email protected]:llvm/llvm-project.git 29ee66f4a0967e43a035f147c960743c7b640f2f)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
+!1 = !DIFile(filename: "/INLINE/inlined.c", directory: "/Volumes/Data/llvm-project", checksumkind: CSK_MD5, checksum: "3183154a5cb31debe9a8e27ca500bc3c")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"uwtable", i32 1}
+!7 = !{i32 7, !"frame-pointer", i32 1}
+!8 = !{!"clang version 18.0.0git ([email protected]:llvm/llvm-project.git 29ee66f4a0967e43a035f147c960743c7b640f2f)"}
+!9 = distinct !DISubprogram(name: "f", scope: !10, file: !10, line: 2, type: !11, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DIFile(filename: "/INLINE/inlined.c", directory: "", source: "void stop();
+void f() {
+  // This is inline source code.
+  stop(); // break here
+}
+")
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 4, column: 3, scope: !9)
+!14 = !DILocation(line: 5, column: 1, scope: !9)
diff --git a/lldb/test/API/functionalities/inline-sourcefile/main.c b/lldb/test/API/functionalities/inline-sourcefile/main.c
new file mode 100644
index 00000000000000..29a22d956ad510
--- /dev/null
+++ b/lldb/test/API/functionalities/inline-sourcefile/main.c
@@ -0,0 +1,8 @@
+void f();
+void stop() {}
+
+int main(int argc, char const *argv[])
+{
+    f();
+    return 0;
+}

Copy link

github-actions bot commented Dec 19, 2023

⚠️ Python code formatter, darker found issues in your code. ⚠️

You can test this locally with the following command:
darker --check --diff -r 7df28fd61aa4603846b3ce16f9f988ccc780a584...9af00c37715c614cac700cd8763ee3d8167111e5 lldb/test/API/functionalities/inline-sourcefile/TestInlineSourceFiles.py
View the diff from darker here.
--- TestInlineSourceFiles.py	2024-01-04 17:03:16.000000 +0000
+++ TestInlineSourceFiles.py	2024-01-04 17:06:09.764133 +0000
@@ -9,7 +9,7 @@
     @skipIf(compiler="gcc")
     @skipIf(compiler="clang", compiler_version=["<", "18.0"])
     def test(self):
         """Test DWARF inline source files."""
         self.build()
-        lldbutil.run_to_name_breakpoint(self, 'f')
+        lldbutil.run_to_name_breakpoint(self, "f")
         self.expect("list f", substrs=["This is inline source code"])

Copy link

github-actions bot commented Dec 19, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@adrian-prantl
Copy link
Collaborator Author

The primary use-case I have in mind for this are Swift macro expansions, which may produce hundreds of tiny inline files per source file, hence the lazy approach.

@adrian-prantl adrian-prantl force-pushed the inline-dwarf-sources branch 2 times, most recently from 437b780 to f66f34f Compare December 20, 2023 01:47
@adrian-prantl
Copy link
Collaborator Author

@JDevlieghere and I had an offline conversation about whether we couldn't separate out a SupportFileList from FileSpecList to limit the amount of places that need to think about lazy files and also to potentially move the FileSpec::m_checksum into. Here is a very rough patch that implements this idea to show how much of LLDB is affected by the change.

@adrian-prantl
Copy link
Collaborator Author

Ping @JDevlieghere

@adrian-prantl
Copy link
Collaborator Author

@JDevlieghere I think I addressed your comments. Mind taking another look?

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks awesome. Without the need for copying the SupportFileList, can we make the UnspooledSupportFile a subclass of SupportFile and store unique pointers in the support file list?

@adrian-prantl
Copy link
Collaborator Author

@JDevlieghere I merged the two. This made the regular (on-disk) case somewhat less efficient because all SupportFiles are now on the Heap but that probably isn't even measurable.

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@adrian-prantl adrian-prantl changed the title [DRAFT] Add support for inline DWARF source files. Add support for inline DWARF source files. Jan 4, 2024
@adrian-prantl adrian-prantl force-pushed the inline-dwarf-sources branch 2 times, most recently from bce8320 to 4368519 Compare January 4, 2024 00:46
LLVM supports DWARF 5 linetable extension to store source files inline
in DWARF. This is particularly useful for compiler-generated source
code. This implementation tries to materialize them as temporary files
lazily, so SBAPI clients don't need to be aware of them.

As an implementation detail, this patch separate SupportFileList from
FileSpecList and makes SupportFileList uncopyable.
@adrian-prantl adrian-prantl merged commit 917b404 into llvm:main Jan 4, 2024
adrian-prantl added a commit to adrian-prantl/llvm-project that referenced this pull request Jan 4, 2024
LLVM supports DWARF 5 linetable extension to store source files inline
in DWARF. This is particularly useful for compiler-generated source
code. This implementation tries to materialize them as temporary files
lazily, so SBAPI clients don't need to be aware of them.

rdar://110926168
(cherry picked from commit 917b404)

 Conflicts:
	lldb/include/lldb/Symbol/CompileUnit.h
	lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
	lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
	lldb/source/Symbol/CompileUnit.cpp
	lldb/source/Utility/FileSpecList.cpp
@DavidSpickett
Copy link
Collaborator

This is failing on Windows: https://lab.llvm.org/buildbot/#/builders/219/builds/7982

Any obvious reason that this would be happening? I do see the DWARF in the binary:

0x00000078: DW_TAG_compile_unit
              DW_AT_producer    ("clang version 18.0.0git ([email protected]:llvm/llvm-project.git 29ee66f4a0967e43a035f147c960743c7b640f2f)")
              DW_AT_language    (DW_LANG_C11)
              DW_AT_name        ("/INLINE/inlined.c")
              DW_AT_LLVM_sysroot        ("/")
              DW_AT_str_offsets_base    (0x00000034)
              DW_AT_stmt_list   (0x0000007a)
              DW_AT_comp_dir    ("/Volumes/Data/llvm-project")
              DW_AT_low_pc      (0x0000000140001034)
              DW_AT_high_pc     (0x0000000140001044)
              DW_AT_addr_base   (0x00000020)

0x00000090:   DW_TAG_subprogram
                DW_AT_low_pc    (0x0000000140001034)
                DW_AT_high_pc   (0x0000000140001044)
                DW_AT_frame_base        (DW_OP_reg31 WSP)
                DW_AT_name      ("f")
                DW_AT_decl_file (0x01)
                DW_AT_decl_line (2)
                DW_AT_external  (true)

0x0000009b:   NULL

Maybe it is path style, but at least at a glance, the code is handling that.

@DavidSpickett
Copy link
Collaborator

Skipped for now 8b49ed8

@adrian-prantl
Copy link
Collaborator Author

I'll probably need some help from someone with a windows machine to debug this. Your hunch about path separators sounds plausible.

@amordo
Copy link
Contributor

amordo commented Feb 29, 2024

@adrian-prantl, I'll be glad to help:)
dwarf on Win has warnings like objdump: Warning: DW_FORM_line_strp offset too big: 0x4008a16c and no inlined source
here is a part of $ objdump --dwarf a.out (full)

 The File Name Table (offset 0xaf, lines 2, columns 3):
  Entry Dir     (Unknown format content type 8193)      Name
  0     0objdump: Warning: DW_FORM_line_strp offset too big: 0x4008a161
        (indirect line string, offset: 0x4008a161): <offset is too big>objdump: Warning: DW_FORM_line_strp offset too big: 0x4008a14f
        (indirect line string, offset: 0x4008a14f): <offset is too big>
  1     1objdump: Warning: DW_FORM_line_strp offset too big: 0x4008a16c
        (indirect line string, offset: 0x4008a16c): <offset is too big>objdump: Warning: DW_FORM_line_strp offset too big: 0x4008a162
        (indirect line string, offset: 0x4008a162): <offset is too big>

while linux has one

 The File Name Table (offset 0xad, lines 2, columns 3):
  Entry	Dir	(Unknown format content type 8193)	Name
  0	0	(indirect line string, offset: 0x159): 	(indirect line string, offset: 0xf4): /INLINE/inlined.c
  1	1	(indirect line string, offset: 0x106): void stop();
void f() {
  // This is inline source code.
  stop(); // break here
}

you can look at Win test result there (+ added 2 .md with the objdump outputs)
https://github.com/amordo/TestInlineSourceFiles.test_dwarf/tree/main

ps. played replacing '/' on '\' in paths in inline.ll, no effect

@amordo
Copy link
Contributor

amordo commented Apr 2, 2024

Hi again! Some notes about Win test fail I discovered:

Setting function breakpoints on binary with -gdwarf-5 on Windows doesn't work; the case is rased #87327

The next analysis was done from repo based on b4001e3.
During b f command this path was executed in SymbolFileDWARF::ParseFunction():

if (lowest_func_addr == LLDB_INVALID_ADDRESS ||
      lowest_func_addr >= highest_func_addr ||
      lowest_func_addr < m_first_code_address)
    return nullptr;

particularly lowest_func_addr < m_first_code_address.
Analyzing DWARFDebugInfoEntry::GetAttributeAddressRanges() and sections loading it was noticed no section was found by type eSectionTypeDWARFDebugAddr: m_sections[idx]->GetType() == sect_type from SectionList::FindSectionByType() wasn't succeeded because section with debug_addr name had eSectionTypeData type.
I've logged Dump(stream, 1, nullptr, true, UINT32_MAX); in SectionList::FindSectionByType() and got

  SectID     Type             File Address                             Perm File Off.  File Size  Flags      Section Name
 ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
 0xffffffffffffffff regular          [0x0000000140000000-0x0000000140000600)  r--  0x00000000 0x00000600 0x00000000 a.out.PECOFF header
 0x00000001 code             [0x0000000140001000-0x000000014005d216)  r-x  0x00000600 0x0005c400 0x60000020 a.out..text
 0x00000002 data             [0x000000014005e000-0x000000014006f864)  r--  0x0005ca00 0x00011a00 0x40000040 a.out..rdata
 0x00000003 data             [0x0000000140070000-0x00000001400726c0)  rw-  0x0006e400 0x00000e00 0xc0000040 a.out..data
 0x00000004 data             [0x0000000140073000-0x0000000140077764)  r--  0x0006f200 0x00004800 0x40000040 a.out..pdata
 0x00000005 data             [0x0000000140078000-0x0000000140081f20)  r--  0x00073a00 0x0000a000 0x40000040 a.out..gxfg
 0x00000006 data             [0x0000000140082000-0x00000001400821f4)  r--  0x0007da00 0x00000200 0x40000040 a.out._RDATA
 0x00000007 regular          [0x0000000140083000-0x0000000140083108)  ---  0x0007dc00 0x00000200 0x00000000 a.out.memcpy_
 0x00000008 regular          [0x0000000140084000-0x00000001400847fc)  r--  0x0007de00 0x00000800 0x42000040 a.out..reloc
 0x00000009 dwarf-abbrev     [0x0000000140085000-0x0000000140085098)  r--  0x0007e600 0x00000200 0x42000040 a.out..debug_abbrev
 0x0000000a data             [0x0000000140086000-0x0000000140086028)  r--  0x0007e800 0x00000200 0x42000040 a.out..debug_addr
 0x0000000b dwarf-info       [0x0000000140087000-0x000000014008709c)  r--  0x0007ea00 0x00000200 0x42000040 a.out..debug_info
 0x0000000c dwarf-line       [0x0000000140088000-0x00000001400880db)  r--  0x0007ec00 0x00000200 0x42000040 a.out..debug_line
 0x0000000d data             [0x0000000140089000-0x00000001400891db)  r--  0x0007ee00 0x00000200 0x42000040 a.out..debug_line_str
 0x0000000e dwarf-names      [0x000000014008a000-0x000000014008a050)  r--  0x0007f000 0x00000200 0x42000040 a.out..debug_names
 0x0000000f dwarf-str        [0x000000014008b000-0x000000014008b20a)  r--  0x0007f200 0x00000400 0x42000040 a.out..debug_str
 0x00000010 data             [0x000000014008c000-0x000000014008c048)  r--  0x0007f600 0x00000200 0x42000040 a.out..debug_str_offsets

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants