PRESIDENT810 updated this revision to Diff 432857.
PRESIDENT810 added a comment.

I have refactored my code so it should looks cleaner now, but I'm not sure how 
to add a test. It seems that adding a test for thin archive on macOS platforms 
can be not so straightforward. I see that in 
lldb/test/API/functionalities/archives/Makefile, the test suite is using 
libtool instead of ar to create archives on macOS platforms, and I don't know 
whether I can produce a thin archive with that. Also, ld on macOS platforms 
seems to be unable to identify thin archives (I'm using ld64.lld when testing 
my code locally).

I would really appreciate it if someone can provide some advice about how to 
implement such a test case here, thank you!


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D126464/new/

https://reviews.llvm.org/D126464

Files:
  lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
  lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h

Index: lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
===================================================================
--- lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
+++ lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -15,19 +15,24 @@
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/FileSpec.h"
 
+#include "llvm/Object/Archive.h"
 #include "llvm/Support/Chrono.h"
+#include "llvm/Support/Path.h"
 
 #include <map>
 #include <memory>
 #include <mutex>
 
+enum class ArchiveType { Invalid, Archive, ThinArchive };
+
 class ObjectContainerBSDArchive : public lldb_private::ObjectContainer {
 public:
   ObjectContainerBSDArchive(const lldb::ModuleSP &module_sp,
                             lldb::DataBufferSP &data_sp,
                             lldb::offset_t data_offset,
                             const lldb_private::FileSpec *file,
-                            lldb::offset_t offset, lldb::offset_t length);
+                            lldb::offset_t offset, lldb::offset_t length,
+                            ArchiveType archive_type);
 
   ~ObjectContainerBSDArchive() override;
 
@@ -54,7 +59,7 @@
                                         lldb::offset_t length,
                                         lldb_private::ModuleSpecList &specs);
 
-  static bool MagicBytesMatch(const lldb_private::DataExtractor &data);
+  static ArchiveType MagicBytesMatch(const lldb_private::DataExtractor &data);
 
   // Member Functions
   bool ParseHeader() override;
@@ -78,6 +83,10 @@
 
     void Clear();
 
+    lldb::offset_t ExtractFromThin(const lldb_private::DataExtractor &data,
+                                   lldb::offset_t offset,
+                                   llvm::StringRef stringTable);
+
     lldb::offset_t Extract(const lldb_private::DataExtractor &data,
                            lldb::offset_t offset);
     /// Object name in the archive.
@@ -156,6 +165,8 @@
 
     lldb_private::DataExtractor &GetData() { return m_data; }
 
+    ArchiveType GetArchiveType() { return m_archive_type; }
+
   protected:
     typedef lldb_private::UniqueCStringMap<uint32_t> ObjectNameToIndexMap;
     // Member Variables
@@ -167,11 +178,14 @@
     lldb_private::DataExtractor m_data; ///< The data for this object container
                                         ///so we don't lose data if the .a files
                                         ///gets modified
+    ArchiveType m_archive_type;
   };
 
   void SetArchive(Archive::shared_ptr &archive_sp);
 
   Archive::shared_ptr m_archive_sp;
+
+  ArchiveType m_archive_type;
 };
 
 #endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BSD_ARCHIVE_OBJECTCONTAINERBSDARCHIVE_H
Index: lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
===================================================================
--- lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -40,6 +40,8 @@
 using namespace lldb;
 using namespace lldb_private;
 
+using namespace llvm::object;
+
 LLDB_PLUGIN_DEFINE(ObjectContainerBSDArchive)
 
 ObjectContainerBSDArchive::Object::Object() : ar_name() {}
@@ -55,6 +57,74 @@
   file_size = 0;
 }
 
+lldb::offset_t ObjectContainerBSDArchive::Object::ExtractFromThin(
+    const DataExtractor &data, lldb::offset_t offset,
+    llvm::StringRef stringTable) {
+  size_t ar_name_len = 0;
+  std::string str;
+  char *err;
+
+  // File header
+  //
+  // The common format is as follows.
+  //
+  //  Offset  Length	Name            Format
+  //  0       16      File name       ASCII right padded with spaces (no spaces
+  //  allowed in file name)
+  //  16      12      File mod        Decimal as cstring right padded with
+  //  spaces
+  //  28      6       Owner ID        Decimal as cstring right padded with
+  //  spaces
+  //  34      6       Group ID        Decimal as cstring right padded with
+  //  spaces
+  //  40      8       File mode       Octal   as cstring right padded with
+  //  spaces
+  //  48      10      File byte size  Decimal as cstring right padded with
+  //  spaces
+  //  58      2       File magic      0x60 0x0A
+
+  // Make sure there is enough data for the file header and bail if not
+  if (!data.ValidOffsetForDataOfSize(offset, 60))
+    return LLDB_INVALID_OFFSET;
+
+  str.assign((const char *)data.GetData(&offset, 16), 16);
+  if (!(llvm::StringRef(str).startswith("//") || stringTable.empty())) {
+    // Strip off any trailing spaces.
+    const size_t last_pos = str.find_last_not_of(' ');
+    if (last_pos != std::string::npos) {
+      if (last_pos + 1 < 16)
+        str.erase(last_pos + 1);
+    }
+    int start = strtoul(str.c_str() + 1, &err, 10);
+    int end = stringTable.find('\n', start);
+    str.assign(stringTable.data() + start, end - start - 1);
+    ar_name.SetCString(str.c_str());
+  }
+
+  str.assign((const char *)data.GetData(&offset, 12), 12);
+  modification_time = strtoul(str.c_str(), &err, 10);
+
+  str.assign((const char *)data.GetData(&offset, 6), 6);
+  uid = strtoul(str.c_str(), &err, 10);
+
+  str.assign((const char *)data.GetData(&offset, 6), 6);
+  gid = strtoul(str.c_str(), &err, 10);
+
+  str.assign((const char *)data.GetData(&offset, 8), 8);
+  mode = strtoul(str.c_str(), &err, 8);
+
+  str.assign((const char *)data.GetData(&offset, 10), 10);
+  size = strtoul(str.c_str(), &err, 10);
+
+  str.assign((const char *)data.GetData(&offset, 2), 2);
+  if (str == ARFMAG) {
+    file_offset = offset;
+    file_size = size - ar_name_len;
+    return offset;
+  }
+  return LLDB_INVALID_OFFSET;
+}
+
 lldb::offset_t
 ObjectContainerBSDArchive::Object::Extract(const DataExtractor &data,
                                            lldb::offset_t offset) {
@@ -161,6 +231,48 @@
       obj.Clear();
     } while (data.ValidOffset(offset));
 
+    // Now sort all of the object name pointers
+    m_object_name_to_index_map.Sort();
+  } else if (str == ThinArchiveMagic) {
+    Object obj;
+    size_t obj_idx;
+
+    // Retrieve symbol table
+    offset = obj.ExtractFromThin(data, offset, "");
+    if (offset == LLDB_INVALID_OFFSET)
+      return m_objects.size();
+    obj_idx = m_objects.size();
+    m_objects.push_back(obj);
+    // Insert all of the C strings out of order for now...
+    m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
+    offset += obj.file_size;
+    obj.Clear();
+
+    // Retrieve string table
+    offset = obj.ExtractFromThin(data, offset, "");
+    if (offset == LLDB_INVALID_OFFSET)
+      return m_objects.size();
+    obj_idx = m_objects.size();
+    m_objects.push_back(obj);
+    // Insert all of the C strings out of order for now...
+    m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
+    // Extract string table
+    llvm::StringRef strtab((const char *)data.GetData(&offset, obj.size),
+                           obj.size);
+    obj.Clear();
+
+    // Retrieve object files
+    do {
+      offset = obj.ExtractFromThin(data, offset, strtab);
+      if (offset == LLDB_INVALID_OFFSET)
+        break;
+      obj_idx = m_objects.size();
+      m_objects.push_back(obj);
+      // Insert all of the C strings out of order for now...
+      m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
+      obj.Clear();
+    } while (data.ValidOffset(offset));
+
     // Now sort all of the object name pointers
     m_object_name_to_index_map.Sort();
   }
@@ -288,7 +400,8 @@
     // contents for the archive and cache it
     DataExtractor data;
     data.SetData(data_sp, data_offset, length);
-    if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) {
+    ArchiveType archive_type = ObjectContainerBSDArchive::MagicBytesMatch(data);
+    if (file && data_sp && archive_type != ArchiveType::Invalid) {
       LLDB_SCOPED_TIMERF(
           "ObjectContainerBSDArchive::CreateInstance (module = %s, file = "
           "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
@@ -312,7 +425,7 @@
       std::unique_ptr<ObjectContainerBSDArchive> container_up(
           new ObjectContainerBSDArchive(module_sp, archive_data_sp,
                                         archive_data_offset, file, file_offset,
-                                        length));
+                                        length, archive_type));
 
       if (container_up) {
         if (archive_sp) {
@@ -331,7 +444,8 @@
     if (archive_sp) {
       std::unique_ptr<ObjectContainerBSDArchive> container_up(
           new ObjectContainerBSDArchive(module_sp, data_sp, data_offset, file,
-                                        file_offset, length));
+                                        file_offset, length,
+                                        archive_sp->GetArchiveType()));
 
       if (container_up) {
         // We already have this archive in our cache, use it
@@ -343,23 +457,35 @@
   return nullptr;
 }
 
-bool ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) {
+ArchiveType
+ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) {
   uint32_t offset = 0;
   const char *armag = (const char *)data.PeekData(offset, sizeof(ar_hdr));
-  if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0) {
+  if (armag == nullptr)
+    return ArchiveType::Invalid;
+  if (::strncmp(armag, ARMAG, SARMAG) == 0) {
     armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
     if (strncmp(armag, ARFMAG, 2) == 0)
-      return true;
+      return ArchiveType::Archive;
+  } else if (::strncmp(armag, ThinArchiveMagic, strlen(ThinArchiveMagic)) ==
+             0) {
+    armag += offsetof(struct ar_hdr, ar_fmag) + strlen(ThinArchiveMagic);
+    if (strncmp(armag, ARFMAG, 2) == 0) {
+      return ArchiveType::ThinArchive;
+    }
   }
-  return false;
+  return ArchiveType::Invalid;
 }
 
 ObjectContainerBSDArchive::ObjectContainerBSDArchive(
     const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
     lldb::offset_t data_offset, const lldb_private::FileSpec *file,
-    lldb::offset_t file_offset, lldb::offset_t size)
+    lldb::offset_t file_offset, lldb::offset_t size, ArchiveType archive_type)
     : ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset),
-      m_archive_sp() {}
+      m_archive_sp() {
+  m_archive_type = archive_type;
+}
+
 void ObjectContainerBSDArchive::SetArchive(Archive::shared_ptr &archive_sp) {
   m_archive_sp = archive_sp;
 }
@@ -414,6 +540,29 @@
       Object *object = m_archive_sp->FindObject(
           module_sp->GetObjectName(), module_sp->GetObjectModificationTime());
       if (object) {
+        if (m_archive_type == ArchiveType::ThinArchive) {
+          // Set file to child object file
+          llvm::SmallString<128> FullPath;
+          if (llvm::sys::path::is_absolute(object->ar_name.GetStringRef())) {
+            FullPath = object->ar_name.GetStringRef();
+          } else {
+            FullPath = m_file.GetDirectory().GetStringRef();
+            llvm::sys::path::append(FullPath, object->ar_name.GetStringRef());
+          }
+          FileSpec child =
+              FileSpec(FullPath.str(), llvm::sys::path::Style::posix);
+          lldb::offset_t file_offset = 0;
+          lldb::offset_t file_size = object->size;
+          std::shared_ptr<DataBuffer> child_data_sp =
+              FileSystem::Instance().CreateDataBuffer(child, file_size,
+                                                      file_offset);
+          if (child_data_sp->GetByteSize() != object->file_size)
+            return ObjectFileSP();
+          lldb::offset_t data_offset = 0;
+          return ObjectFile::FindPlugin(
+              module_sp, &child, m_offset + object->file_offset,
+              object->file_size, child_data_sp, data_offset);
+        }
         lldb::offset_t data_offset = object->file_offset;
         return ObjectFile::FindPlugin(
             module_sp, file, m_offset + object->file_offset, object->file_size,
@@ -434,7 +583,8 @@
   // contents for the archive and cache it
   DataExtractor data;
   data.SetData(data_sp, data_offset, data_sp->GetByteSize());
-  if (!file || !data_sp || !ObjectContainerBSDArchive::MagicBytesMatch(data))
+  if (!file || !data_sp ||
+      ObjectContainerBSDArchive::MagicBytesMatch(data) == ArchiveType::Invalid)
     return 0;
 
   const size_t initial_count = specs.GetSize();
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to