PRESIDENT810 created this revision. PRESIDENT810 added reviewers: clayborg, jingham, jasonmolenda. Herald added a project: All. PRESIDENT810 requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
This fixes https://github.com/llvm/llvm-project/issues/50114 where lldb/mac can't load object files from thin archives. This patch allows lldb to identify thin archives, and load object files contained in them. I'm a novice at llvm not sure whether I'm fixing this right, so please tell me if anything wrong with this fix, thank you guys! Repository: rG LLVM Github Monorepo 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,12 +15,16 @@ #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, @@ -54,7 +58,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 +82,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 +164,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 +177,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) { @@ -164,6 +234,48 @@ // Now sort all of the object name pointers m_object_name_to_index_map.Sort(); } + 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 + str.assign((const char *)data.GetData(&offset, obj.size), obj.size); + obj.Clear(); + + // Retrieve object files + do { + offset = obj.ExtractFromThin(data, offset, llvm::StringRef(str)); + 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(); + } return m_objects.size(); } @@ -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 ")", @@ -313,6 +426,7 @@ new ObjectContainerBSDArchive(module_sp, archive_data_sp, archive_data_offset, file, file_offset, length)); + container_up->m_archive_type = archive_type; if (container_up) { if (archive_sp) { @@ -336,6 +450,7 @@ if (container_up) { // We already have this archive in our cache, use it container_up->SetArchive(archive_sp); + container_up->m_archive_type = archive_sp->GetArchiveType(); return container_up.release(); } } @@ -343,15 +458,23 @@ 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) { armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG; if (strncmp(armag, ARFMAG, 2) == 0) - return true; + return ArchiveType::Archive; } - return false; + if (armag && + ::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 ArchiveType::Invalid; } ObjectContainerBSDArchive::ObjectContainerBSDArchive( @@ -414,6 +537,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 +580,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