JDevlieghere created this revision.
JDevlieghere added a reviewer: jasonmolenda.
Herald added a subscriber: mgorny.
Herald added a project: All.
JDevlieghere requested review of this revision.

https://reviews.llvm.org/D132433

Files:
  lldb/include/lldb/Symbol/ObjectFile.h
  lldb/source/Plugins/ObjectContainer/CMakeLists.txt
  lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/CMakeLists.txt
  
lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp
  
lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.h
  lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -941,6 +941,17 @@
   data.SetData(data_sp, data_offset, data_length);
   lldb::offset_t offset = 0;
   uint32_t magic = data.GetU32(&offset);
+
+  offset += 4; // cputype
+  offset += 4; // cpusubtype
+  uint32_t filetype = data.GetU32(&offset);
+
+  // A fileset has a Mach-O header but is not an
+  // individual file and must be handled via an
+  // ObjectContainer plugin.
+  if (filetype == llvm::MachO::MH_FILESET)
+    return false;
+
   return MachHeaderSizeFromMagic(magic) != 0;
 }
 
Index: lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.h
@@ -0,0 +1,78 @@
+//===-- ObjectContainerMachOFileset.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_MACH_O_FILESET_OBJECTCONTAINERMADCHOFILESET_H
+#define LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_MACH_O_FILESET_OBJECTCONTAINERMADCHOFILESET_H
+
+#include "lldb/Host/SafeMachO.h"
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Utility/FileSpec.h"
+
+namespace lldb_private {
+
+class ObjectContainerMachOFileset : public lldb_private::ObjectContainer {
+public:
+  ObjectContainerMachOFileset(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);
+
+  ~ObjectContainerMachOFileset() override;
+
+  static void Initialize();
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() { return "mach-o-fileset"; }
+
+  static llvm::StringRef GetPluginDescriptionStatic() {
+    return "Mach-O Fileset container reader.";
+  }
+
+  static lldb_private::ObjectContainer *
+  CreateInstance(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);
+
+  static size_t GetModuleSpecifications(const lldb_private::FileSpec &file,
+                                        lldb::DataBufferSP &data_sp,
+                                        lldb::offset_t data_offset,
+                                        lldb::offset_t file_offset,
+                                        lldb::offset_t length,
+                                        lldb_private::ModuleSpecList &specs);
+
+  static bool MagicBytesMatch(const lldb_private::DataExtractor &data);
+
+  bool ParseHeader() override;
+
+  void Dump(lldb_private::Stream *s) const override;
+
+  size_t GetNumObjects() const override { return m_entries.size(); }
+
+  lldb::ObjectFileSP GetObjectFile(const lldb_private::FileSpec *file) override;
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+private:
+  struct Entry {
+    Entry(uint64_t vmaddr, uint64_t fileoff, std::string id)
+        : vmaddr(vmaddr), fileoff(fileoff), id(id) {}
+    uint64_t vmaddr;
+    uint64_t fileoff;
+    std::string id;
+  };
+
+  static bool ParseHeader(lldb_private::DataExtractor &data,
+                          std::vector<Entry> &entries);
+
+  std::vector<Entry> m_entries;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_MACH_O_FILESET_OBJECTCONTAINERMADCHOFILESET_H
Index: lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp
@@ -0,0 +1,234 @@
+//===-- ObjectContainerMachOFileset.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerMachOFileset.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::MachO;
+
+LLDB_PLUGIN_DEFINE(ObjectContainerMachOFileset)
+
+void ObjectContainerMachOFileset::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                GetPluginDescriptionStatic(), CreateInstance,
+                                GetModuleSpecifications);
+}
+
+void ObjectContainerMachOFileset::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+ObjectContainerMachOFileset::ObjectContainerMachOFileset(
+    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)
+    : ObjectContainer(module_sp, file, offset, length, data_sp, data_offset) {}
+
+ObjectContainer *ObjectContainerMachOFileset::CreateInstance(
+    const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
+    lldb::offset_t data_offset, const FileSpec *file,
+    lldb::offset_t file_offset, lldb::offset_t length) {
+  if (!data_sp)
+    return {};
+
+  DataExtractor data;
+  data.SetData(data_sp, data_offset, length);
+  if (!MagicBytesMatch(data))
+    return {};
+
+  // We need the whole file in order to parse all the load commands.
+  if (data_sp->GetByteSize() < length) {
+    data_sp = ObjectFile::MapFileData(*file, length, file_offset);
+    if (!data_sp)
+      return nullptr;
+    data_offset = 0;
+  }
+
+  auto container_up = std::make_unique<ObjectContainerMachOFileset>(
+      module_sp, data_sp, data_offset, file, file_offset, length);
+  if (!container_up->ParseHeader())
+    return {};
+
+  return container_up.release();
+}
+
+ObjectContainerMachOFileset::~ObjectContainerMachOFileset() = default;
+
+bool ObjectContainerMachOFileset::ParseHeader() {
+  return ParseHeader(m_data, m_entries);
+}
+
+bool ObjectContainerMachOFileset::ParseHeader(lldb_private::DataExtractor &data,
+                                              std::vector<Entry> &entries) {
+  llvm::MachO::mach_header header = {};
+
+  lldb::offset_t offset = 0;
+  size_t header_size = 0;
+  header.magic = data.GetU32(&offset);
+
+  switch (header.magic) {
+  case MH_MAGIC:
+    data.SetByteOrder(endian::InlHostByteOrder());
+    data.SetAddressByteSize(4);
+    header_size = sizeof(struct llvm::MachO::mach_header);
+    break;
+  case MH_MAGIC_64:
+    data.SetByteOrder(endian::InlHostByteOrder());
+    data.SetAddressByteSize(8);
+    header_size = sizeof(struct llvm::MachO::mach_header_64);
+    break;
+  case MH_CIGAM:
+    data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+                          ? eByteOrderLittle
+                          : eByteOrderBig);
+    data.SetAddressByteSize(4);
+    header_size = sizeof(struct llvm::MachO::mach_header);
+    break;
+  case MH_CIGAM_64:
+    data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+                          ? eByteOrderLittle
+                          : eByteOrderBig);
+    data.SetAddressByteSize(8);
+    header_size = sizeof(struct llvm::MachO::mach_header_64);
+    break;
+  default:
+    return false;
+  }
+
+  header.cputype = data.GetU32(&offset);
+  header.cpusubtype = data.GetU32(&offset);
+  header.filetype = data.GetU32(&offset);
+  header.ncmds = data.GetU32(&offset);
+  header.sizeofcmds = data.GetU32(&offset);
+
+  assert(header.filetype == llvm::MachO::MH_FILESET && "Not a fileset?");
+  assert(header.sizeofcmds <= data.GetByteSize() &&
+         "Entire file must be mapped");
+
+  offset = header_size;
+  for (uint32_t i = 0; i < header.ncmds; ++i) {
+    const lldb::offset_t load_cmd_offset = offset;
+    llvm::MachO::load_command lc = {};
+    if (data.GetU32(&offset, &lc.cmd, 2) == nullptr)
+      break;
+
+    if (lc.cmd == LC_FILESET_ENTRY) {
+      llvm::MachO::fileset_entry_command entry;
+      data.CopyData(load_cmd_offset, sizeof(llvm::MachO::fileset_entry_command),
+                    &entry);
+      lldb::offset_t entry_id_offset = load_cmd_offset + entry.entry_id;
+      const char *id = data.GetCStr(&entry_id_offset);
+      entries.emplace_back(entry.vmaddr, entry.fileoff, std::string(id));
+    }
+    offset = load_cmd_offset + lc.cmdsize;
+  }
+
+  return true;
+}
+
+size_t ObjectContainerMachOFileset::GetModuleSpecifications(
+    const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
+    lldb::offset_t data_offset, lldb::offset_t file_offset,
+    lldb::offset_t file_size, lldb_private::ModuleSpecList &specs) {
+  const size_t initial_count = specs.GetSize();
+
+  // We need the whole file in order to parse all the load commands.
+  if (data_sp->GetByteSize() < file_size) {
+    data_sp = ObjectFile::MapFileData(file, file_size, file_offset);
+    if (!data_sp)
+      return 0;
+  }
+
+  DataExtractor data;
+  data.SetData(data_sp, data_offset, data_sp->GetByteSize());
+
+  if (MagicBytesMatch(data)) {
+    std::vector<Entry> entries;
+    if (ParseHeader(data, entries)) {
+      for (const Entry &entry : entries) {
+        const lldb::offset_t entry_offset = entry.fileoff + file_offset;
+        if (ObjectFile::GetModuleSpecifications(
+                file, entry_offset, file_size - entry_offset, specs)) {
+          ModuleSpec &spec = specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
+          spec.GetObjectName() = ConstString(entry.id);
+        }
+      }
+    }
+  }
+  return specs.GetSize() - initial_count;
+}
+
+bool ObjectContainerMachOFileset::MagicBytesMatch(const DataExtractor &data) {
+  lldb::offset_t offset = 0;
+  uint32_t magic = data.GetU32(&offset);
+  switch (magic) {
+  case MH_MAGIC:
+  case MH_CIGAM:
+  case MH_MAGIC_64:
+  case MH_CIGAM_64:
+    break;
+  default:
+    return false;
+  }
+  offset += 4; // cputype
+  offset += 4; // cpusubtype
+  uint32_t filetype = data.GetU32(&offset);
+  return filetype == llvm::MachO::MH_FILESET;
+}
+
+ObjectFileSP
+ObjectContainerMachOFileset::GetObjectFile(const lldb_private::FileSpec *file) {
+  ModuleSP module_sp(GetModule());
+  if (!module_sp)
+    return {};
+
+  ConstString object_name = module_sp->GetObjectName();
+  if (!object_name)
+    return {};
+
+  std::string object_name_str = object_name.GetCString();
+  auto it = std::find_if(m_entries.begin(), m_entries.end(),
+                         [object_name_str](const Entry &entry) {
+                           return object_name_str == entry.id;
+                         });
+  if (it == m_entries.end())
+    return {};
+
+  const Entry &entry = *it;
+
+  DataBufferSP data_sp;
+  lldb::offset_t data_offset = 0;
+  return ObjectFile::FindPlugin(module_sp, file, m_offset + entry.fileoff,
+                                m_data.GetByteSize() - entry.fileoff, data_sp,
+                                data_offset);
+}
+
+void ObjectContainerMachOFileset::Dump(Stream *s) const {
+  s->Printf("%p: ", static_cast<const void *>(this));
+  s->Indent();
+
+  const size_t num_objects = GetNumObjects();
+  s->Printf("ObjectContainerMachOFileset, num_objects = %zu", num_objects);
+
+  for (size_t i = 0; i < num_objects; i++) {
+    s->Indent();
+    s->Printf("object[%zu] = %s\n", i, m_entries[i].id.c_str());
+  }
+
+  s->IndentLess();
+  s->EOL();
+}
Index: lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginObjectContainerMachOFileset PLUGIN
+  ObjectContainerMachOFileset.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbHost
+    lldbSymbol
+    lldbTarget
+    lldbUtility
+  )
Index: lldb/source/Plugins/ObjectContainer/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ObjectContainer/CMakeLists.txt
+++ lldb/source/Plugins/ObjectContainer/CMakeLists.txt
@@ -1,2 +1,3 @@
 add_subdirectory(BSD-Archive)
 add_subdirectory(Universal-Mach-O)
+add_subdirectory(Mach-O-Fileset)
Index: lldb/include/lldb/Symbol/ObjectFile.h
===================================================================
--- lldb/include/lldb/Symbol/ObjectFile.h
+++ lldb/include/lldb/Symbol/ObjectFile.h
@@ -723,6 +723,8 @@
   /// file when storing cached data.
   uint32_t GetCacheHash();
 
+  static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size,
+                                        uint64_t Offset);
 
 protected:
   // Member variables.
@@ -764,9 +766,6 @@
   /// The number of bytes to read when going through the plugins.
   static size_t g_initial_bytes_to_read;
 
-  static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size,
-                                        uint64_t Offset);
-
 private:
   ObjectFile(const ObjectFile &) = delete;
   const ObjectFile &operator=(const ObjectFile &) = delete;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] ... Jonas Devlieghere via Phabricator via lldb-commits

Reply via email to