friss created this revision.
friss added a reviewer: labath.
Herald added subscribers: MaskRay, emaste.
Herald added a reviewer: espindola.
Herald added a project: LLDB.

This patch extends the ModuleSpec class to include a
DataBufferSP which contains the module data. If this
data is provided, LLDB won't try to hit the filesystem
to create the Module, but use only the data stored in
the ModuleSpec.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D83512

Files:
  lldb/include/lldb/Core/Module.h
  lldb/include/lldb/Core/ModuleSpec.h
  lldb/include/lldb/Symbol/ObjectFile.h
  lldb/include/lldb/Utility/DataBuffer.h
  lldb/source/Core/Module.cpp
  lldb/source/Symbol/ObjectFile.cpp
  lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
  lldb/unittests/Symbol/TestLineEntry.cpp
  lldb/unittests/TestingSupport/TestUtilities.cpp
  lldb/unittests/TestingSupport/TestUtilities.h

Index: lldb/unittests/TestingSupport/TestUtilities.h
===================================================================
--- lldb/unittests/TestingSupport/TestUtilities.h
+++ lldb/unittests/TestingSupport/TestUtilities.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H
 #define LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H
 
+#include "lldb/Utility/DataBuffer.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/Error.h"
@@ -31,25 +32,39 @@
 
 class TestFile {
 public:
-  static llvm::Expected<TestFile> fromYaml(llvm::StringRef Yaml);
-  static llvm::Expected<TestFile> fromYamlFile(const llvm::Twine &Name);
+  static llvm::Expected<TestFile> fromYaml(llvm::StringRef Yaml,
+                                           bool InMemory = false);
+  static llvm::Expected<TestFile> fromYamlFile(const llvm::Twine &Name,
+                                               bool InMemory = false);
 
-  TestFile(TestFile &&RHS) : Name(std::move(RHS.Name)) {
+  TestFile(TestFile &&RHS)
+      : Name(std::move(RHS.Name)), Buffer(std::move(RHS.Buffer)) {
     RHS.Name = llvm::None;
+    RHS.Buffer = llvm::None;
   }
 
   ~TestFile();
 
   llvm::StringRef name() { return *Name; }
 
+  lldb::DataBufferSP dataBuffer() {
+    auto *buffer = reinterpret_cast<const uint8_t *>(Buffer->data());
+    return std::make_shared<DataBufferUnowned>(const_cast<uint8_t *>(buffer),
+                                               Buffer->size());
+  }
+
 private:
   TestFile(llvm::StringRef Name, llvm::FileRemover &&Remover)
       : Name(std::string(Name)) {
     Remover.releaseFile();
   }
+
+  TestFile(std::string &&Buffer) : Buffer(Buffer) {}
+
   void operator=(const TestFile &) = delete;
 
   llvm::Optional<std::string> Name;
+  llvm::Optional<std::string> Buffer;
 };
 }
 
Index: lldb/unittests/TestingSupport/TestUtilities.cpp
===================================================================
--- lldb/unittests/TestingSupport/TestUtilities.cpp
+++ lldb/unittests/TestingSupport/TestUtilities.cpp
@@ -26,9 +26,21 @@
   return std::string(result.str());
 }
 
-llvm::Expected<TestFile> TestFile::fromYaml(llvm::StringRef Yaml) {
+llvm::Expected<TestFile> TestFile::fromYaml(llvm::StringRef Yaml,
+                                            bool InMemory) {
   const auto *Info = testing::UnitTest::GetInstance()->current_test_info();
   assert(Info);
+
+  if (InMemory) {
+    std::string Buffer;
+    llvm::raw_string_ostream OS(Buffer);
+    llvm::yaml::Input YIn(Yaml);
+    if (!llvm::yaml::convertYAML(YIn, OS, [](const llvm::Twine &Msg) {}))
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "convertYAML() failed");
+    return TestFile(std::move(Buffer));
+  }
+
   llvm::SmallString<128> Name;
   int FD;
   if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
@@ -46,13 +58,14 @@
   return TestFile(Name, std::move(Remover));
 }
 
-llvm::Expected<TestFile> TestFile::fromYamlFile(const llvm::Twine &Name) {
+llvm::Expected<TestFile> TestFile::fromYamlFile(const llvm::Twine &Name,
+                                                bool InMemory) {
   auto BufferOrError =
       llvm::MemoryBuffer::getFile(GetInputFilePath(Name), /*FileSize*/ -1,
                                   /*RequiresNullTerminator*/ false);
   if (!BufferOrError)
     return llvm::errorCodeToError(BufferOrError.getError());
-  return fromYaml(BufferOrError.get()->getBuffer());
+  return fromYaml(BufferOrError.get()->getBuffer(), InMemory);
 }
 
 TestFile::~TestFile() {
Index: lldb/unittests/Symbol/TestLineEntry.cpp
===================================================================
--- lldb/unittests/Symbol/TestLineEntry.cpp
+++ lldb/unittests/Symbol/TestLineEntry.cpp
@@ -46,10 +46,11 @@
 };
 
 void LineEntryTest::SetUp() {
-  auto ExpectedFile = TestFile::fromYamlFile("inlined-functions.yaml");
+  auto ExpectedFile = TestFile::fromYamlFile("inlined-functions.yaml", true);
   ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
   m_file.emplace(std::move(*ExpectedFile));
-  m_module_sp = std::make_shared<Module>(ModuleSpec(FileSpec(m_file->name())));
+  m_module_sp = std::make_shared<Module>(
+      ModuleSpec(FileSpec("<from memory>"), UUID(), m_file->dataBuffer()));
 }
 
 llvm::Expected<LineEntry> LineEntryTest::GetLineEntryForLine(uint32_t line) {
Index: lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
===================================================================
--- lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
+++ lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp
@@ -88,12 +88,13 @@
     Size:            0x0000000000000004
     Binding:         STB_GLOBAL
 ...
-)");
+)",
+                                         true);
   ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
 
-  ModuleSpec spec{FileSpec(ExpectedFile->name())};
-  spec.GetSymbolFileSpec().SetFile(ExpectedFile->name(),
-                                   FileSpec::Style::native);
+  ModuleSpec spec{FileSpec("<from memory>"), UUID(),
+                  ExpectedFile->dataBuffer()};
+  //  spec.GetSymbolFileSpec() = spec;
   auto module_sp = std::make_shared<Module>(spec);
   SectionList *list = module_sp->GetSectionList();
   ASSERT_NE(nullptr, list);
Index: lldb/source/Symbol/ObjectFile.cpp
===================================================================
--- lldb/source/Symbol/ObjectFile.cpp
+++ lldb/source/Symbol/ObjectFile.cpp
@@ -207,9 +207,11 @@
 size_t ObjectFile::GetModuleSpecifications(const FileSpec &file,
                                            lldb::offset_t file_offset,
                                            lldb::offset_t file_size,
-                                           ModuleSpecList &specs) {
-  DataBufferSP data_sp =
-      FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512, file_offset);
+                                           ModuleSpecList &specs,
+                                           DataBufferSP data_sp) {
+  if (!data_sp)
+    data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512,
+                                                      file_offset);
   if (data_sp) {
     if (file_size == 0) {
       const lldb::offset_t actual_file_size =
Index: lldb/source/Core/Module.cpp
===================================================================
--- lldb/source/Core/Module.cpp
+++ lldb/source/Core/Module.cpp
@@ -147,11 +147,13 @@
                   : module_spec.GetObjectName().AsCString(""),
               module_spec.GetObjectName().IsEmpty() ? "" : ")");
 
+  auto data_sp = module_spec.GetData();
+
   // First extract all module specifications from the file using the local file
   // path. If there are no specifications, then don't fill anything in
   ModuleSpecList modules_specs;
   if (ObjectFile::GetModuleSpecifications(module_spec.GetFileSpec(), 0, 0,
-                                          modules_specs) == 0)
+                                          modules_specs, data_sp) == 0)
     return;
 
   // Now make sure that one of the module specifications matches what we just
@@ -170,11 +172,20 @@
     return;
   }
 
-  if (module_spec.GetFileSpec())
-    m_mod_time = FileSystem::Instance().GetModificationTime(module_spec.GetFileSpec());
-  else if (matching_module_spec.GetFileSpec())
-    m_mod_time =
-        FileSystem::Instance().GetModificationTime(matching_module_spec.GetFileSpec());
+  // Set m_data_sp if it was initially provided in the ModuleSpec. Note that
+  // we cannot use the data_sp variable here, because it will have been
+  // modified by GetModuleSpecifications().
+  if (auto module_spec_data_sp = module_spec.GetData()) {
+    m_data_sp = module_spec_data_sp;
+    m_mod_time = {};
+  } else {
+    if (module_spec.GetFileSpec())
+      m_mod_time =
+          FileSystem::Instance().GetModificationTime(module_spec.GetFileSpec());
+    else if (matching_module_spec.GetFileSpec())
+      m_mod_time = FileSystem::Instance().GetModificationTime(
+          matching_module_spec.GetFileSpec());
+  }
 
   // Copy the architecture from the actual spec if we got one back, else use
   // the one that was specified
@@ -1110,6 +1121,10 @@
 }
 
 bool Module::FileHasChanged() const {
+  // We have provided the DataBuffer for this module to avoid accessing the
+  // filesystem. We never want to reload those files.
+  if (m_data_sp)
+    return false;
   if (!m_file_has_changed)
     m_file_has_changed =
         (FileSystem::Instance().GetModificationTime(m_file) != m_mod_time);
@@ -1229,12 +1244,19 @@
       static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
       Timer scoped_timer(func_cat, "Module::GetObjectFile () module = %s",
                          GetFileSpec().GetFilename().AsCString(""));
-      DataBufferSP data_sp;
       lldb::offset_t data_offset = 0;
-      const lldb::offset_t file_size =
-          FileSystem::Instance().GetByteSize(m_file);
+      lldb::offset_t file_size;
+
+      if (m_data_sp)
+        file_size = m_data_sp->GetByteSize();
+      else
+        file_size = FileSystem::Instance().GetByteSize(m_file);
+
       if (file_size > m_object_offset) {
         m_did_load_objfile = true;
+        // FindPlugin will modify its data_sp argument. Do not let it
+        // modify our m_data_sp member.
+        auto data_sp = m_data_sp;
         m_objfile_sp = ObjectFile::FindPlugin(
             shared_from_this(), &m_file, m_object_offset,
             file_size - m_object_offset, data_sp, data_offset);
Index: lldb/include/lldb/Utility/DataBuffer.h
===================================================================
--- lldb/include/lldb/Utility/DataBuffer.h
+++ lldb/include/lldb/Utility/DataBuffer.h
@@ -79,6 +79,20 @@
   }
 };
 
+class DataBufferUnowned : public DataBuffer {
+public:
+  DataBufferUnowned(uint8_t *bytes, lldb::offset_t size)
+      : m_bytes(bytes), m_size(size) {}
+
+  uint8_t *GetBytes() override { return m_bytes; }
+  const uint8_t *GetBytes() const override { return m_bytes; }
+  lldb::offset_t GetByteSize() const override { return m_size; }
+
+private:
+  uint8_t *m_bytes;
+  lldb::offset_t m_size;
+};
+
 } // namespace lldb_private
 
 #endif /// #if defined(__cplusplus)
Index: lldb/include/lldb/Symbol/ObjectFile.h
===================================================================
--- lldb/include/lldb/Symbol/ObjectFile.h
+++ lldb/include/lldb/Symbol/ObjectFile.h
@@ -172,10 +172,10 @@
                                        lldb::addr_t header_addr,
                                        lldb::DataBufferSP &file_data_sp);
 
-  static size_t GetModuleSpecifications(const FileSpec &file,
-                                        lldb::offset_t file_offset,
-                                        lldb::offset_t file_size,
-                                        ModuleSpecList &specs);
+  static size_t
+  GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset,
+                          lldb::offset_t file_size, ModuleSpecList &specs,
+                          lldb::DataBufferSP data_sp = lldb::DataBufferSP());
 
   static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,
                                         lldb::DataBufferSP &data_sp,
Index: lldb/include/lldb/Core/ModuleSpec.h
===================================================================
--- lldb/include/lldb/Core/ModuleSpec.h
+++ lldb/include/lldb/Core/ModuleSpec.h
@@ -30,11 +30,15 @@
         m_object_name(), m_object_offset(0), m_object_size(0),
         m_source_mappings() {}
 
-  ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID())
+  /// If the \param data argument is passed, its contents will be used
+  /// as the module contents instead of trying to read them from
+  /// \param file_spec.
+  ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID(),
+             lldb::DataBufferSP data = lldb::DataBufferSP())
       : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(),
         m_uuid(uuid), m_object_name(), m_object_offset(0),
         m_object_size(FileSystem::Instance().GetByteSize(file_spec)),
-        m_source_mappings() {}
+        m_source_mappings(), m_data(data) {}
 
   ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch)
       : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(arch),
@@ -62,6 +66,7 @@
       m_object_size = rhs.m_object_size;
       m_object_mod_time = rhs.m_object_mod_time;
       m_source_mappings = rhs.m_source_mappings;
+      m_data = rhs.m_data;
     }
     return *this;
   }
@@ -146,6 +151,8 @@
 
   PathMappingList &GetSourceMappingList() const { return m_source_mappings; }
 
+  lldb::DataBufferSP GetData() const { return m_data; }
+
   void Clear() {
     m_file.Clear();
     m_platform_file.Clear();
@@ -289,6 +296,7 @@
   uint64_t m_object_size;
   llvm::sys::TimePoint<> m_object_mod_time;
   mutable PathMappingList m_source_mappings;
+  lldb::DataBufferSP m_data = {};
 };
 
 class ModuleSpecList {
Index: lldb/include/lldb/Core/Module.h
===================================================================
--- lldb/include/lldb/Core/Module.h
+++ lldb/include/lldb/Core/Module.h
@@ -958,6 +958,12 @@
                              ///by \a m_file.
   uint64_t m_object_offset;
   llvm::sys::TimePoint<> m_object_mod_time;
+
+  /// DataBuffer containing the module image, if it was provided at
+  /// construction time. Otherwise the data will be retrieved by mapping
+  /// one of the FileSpec members above.
+  lldb::DataBufferSP m_data_sp;
+
   lldb::ObjectFileSP m_objfile_sp; ///< A shared pointer to the object file
                                    ///parser for this module as it may or may
                                    ///not be shared with the SymbolFile
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to