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