[dsymutil] Implement support for universal mach-o object files.
authorFrederic Riss <friss@apple.com>
Fri, 24 Jul 2015 06:41:11 +0000 (06:41 +0000)
committerFrederic Riss <friss@apple.com>
Fri, 24 Jul 2015 06:41:11 +0000 (06:41 +0000)
This patch allows llvm-dsymutil to read universal (aka fat) macho object
files and archives. The patch touches nearly everything in the BinaryHolder,
but it is fairly mechinical: the methods that returned MemoryBufferRefs or
ObjectFiles now return a vector of those, and the high-level access function
takes a triple argument to select the architecture.

There is no support yet for handling fat executables and thus no support for
writing fat object files.

llvm-svn: 243096

13 files changed:
llvm/test/tools/dsymutil/ARM/fat-arch-not-found.test [new file with mode: 0644]
llvm/test/tools/dsymutil/ARM/lit.local.cfg [new file with mode: 0644]
llvm/test/tools/dsymutil/Inputs/fat-test.c [new file with mode: 0644]
llvm/test/tools/dsymutil/Inputs/fat-test.o [new file with mode: 0644]
llvm/test/tools/dsymutil/Inputs/libfat-test.a [new file with mode: 0644]
llvm/test/tools/dsymutil/X86/fat-archive-input-i386.test [new file with mode: 0644]
llvm/test/tools/dsymutil/X86/fat-object-input-x86_64.test [new file with mode: 0644]
llvm/test/tools/dsymutil/X86/fat-object-input-x86_64h.test [new file with mode: 0644]
llvm/tools/dsymutil/BinaryHolder.cpp
llvm/tools/dsymutil/BinaryHolder.h
llvm/tools/dsymutil/DebugMap.cpp
llvm/tools/dsymutil/DwarfLinker.cpp
llvm/tools/dsymutil/MachODebugMapParser.cpp

diff --git a/llvm/test/tools/dsymutil/ARM/fat-arch-not-found.test b/llvm/test/tools/dsymutil/ARM/fat-arch-not-found.test
new file mode 100644 (file)
index 0000000..89b518c
--- /dev/null
@@ -0,0 +1,13 @@
+# REQUIRES: object-emission
+# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - 2>&1 | FileCheck %s
+
+---
+triple:          'armv7-apple-darwin'
+objects:
+  - filename: libfat-test.a(fat-test.o)
+    symbols:
+      - { sym: _armv7_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
+...
+
+# CHECK: libfat-test.a(fat-test.o): No object file for requested architecture
+
diff --git a/llvm/test/tools/dsymutil/ARM/lit.local.cfg b/llvm/test/tools/dsymutil/ARM/lit.local.cfg
new file mode 100644 (file)
index 0000000..c8625f4
--- /dev/null
@@ -0,0 +1,2 @@
+if not 'X86' in config.root.targets:
+    config.unsupported = True
diff --git a/llvm/test/tools/dsymutil/Inputs/fat-test.c b/llvm/test/tools/dsymutil/Inputs/fat-test.c
new file mode 100644 (file)
index 0000000..42c1fce
--- /dev/null
@@ -0,0 +1,17 @@
+/* Compile with:
+   clang -c -g -arch x86_64h -arch x86_64 -arch i386 fat-test.c
+   libtool -static -o libfat-test.a fat-test.o
+
+   To reduce the size of the fat .o:
+   lipo -thin i386 -o fat-test.i386.o fat-test.o 
+   lipo -thin x86_64 -o fat-test.x86_64.o fat-test.o 
+   lipo -thin x86_64h -o fat-test.x86_64h.o fat-test.o 
+   lipo -create -arch x86_64h fat-test.x86_64h.o -arch x86_64 fat-test.x86_64.o -arch i386 fat-test.i386.o -o fat-test.o -segalign i386 8 -segalign x86_64 8 -segalign x86_64h 8
+ */
+#ifdef __x86_64h__
+int x86_64h_var;
+#elif defined(__x86_64__)
+int x86_64_var;
+#else
+int i386_var;
+#endif
diff --git a/llvm/test/tools/dsymutil/Inputs/fat-test.o b/llvm/test/tools/dsymutil/Inputs/fat-test.o
new file mode 100644 (file)
index 0000000..8159cc7
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/fat-test.o differ
diff --git a/llvm/test/tools/dsymutil/Inputs/libfat-test.a b/llvm/test/tools/dsymutil/Inputs/libfat-test.a
new file mode 100644 (file)
index 0000000..6b34b0f
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/libfat-test.a differ
diff --git a/llvm/test/tools/dsymutil/X86/fat-archive-input-i386.test b/llvm/test/tools/dsymutil/X86/fat-archive-input-i386.test
new file mode 100644 (file)
index 0000000..7f17ff4
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: object-emission
+# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s
+
+---
+triple:          'i386-apple-darwin'
+objects:
+  - filename: libfat-test.a(fat-test.o)
+    symbols:
+      - { sym: _i386_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
+...
+
+# CHECK: .debug_info contents:
+# CHECK: DW_TAG_variable
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK:  DW_AT_name{{.*}}"i386_var"
+
diff --git a/llvm/test/tools/dsymutil/X86/fat-object-input-x86_64.test b/llvm/test/tools/dsymutil/X86/fat-object-input-x86_64.test
new file mode 100644 (file)
index 0000000..489afec
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: object-emission
+# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s
+
+---
+triple:          'x86_64-apple-darwin'
+objects:
+  - filename: fat-test.o
+    symbols:
+      - { sym: _x86_64_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
+...
+
+# CHECK: .debug_info contents:
+# CHECK: DW_TAG_variable
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK:  DW_AT_name{{.*}}"x86_64_var"
+
diff --git a/llvm/test/tools/dsymutil/X86/fat-object-input-x86_64h.test b/llvm/test/tools/dsymutil/X86/fat-object-input-x86_64h.test
new file mode 100644 (file)
index 0000000..f611f55
--- /dev/null
@@ -0,0 +1,16 @@
+# REQUIRES: object-emission
+# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck %s
+
+---
+triple:          'x86_64h-apple-darwin'
+objects:
+  - filename: fat-test.o
+    symbols:
+      - { sym: _x86_64h_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 }
+...
+
+# CHECK: .debug_info contents:
+# CHECK: DW_TAG_variable
+# CHECK-NOT: {{DW_TAG|NULL}}
+# CHECK:  DW_AT_name{{.*}}"x86_64h_var"
+
index 3f0c9b1..7ff4fd6 100644 (file)
@@ -28,30 +28,44 @@ Triple BinaryHolder::getTriple(const object::MachOObjectFile &Obj) {
   return ThumbTriple.getArch() ? ThumbTriple : T;
 }
 
+static std::vector<MemoryBufferRef>
+getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
+                         object::MachOUniversalBinary &Fat) {
+  std::vector<MemoryBufferRef> Buffers;
+  StringRef FatData = Fat.getData();
+  for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
+       ++It) {
+    StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
+    Buffers.emplace_back(ObjData, Filename);
+  }
+  return Buffers;
+}
+
 void BinaryHolder::changeBackingMemoryBuffer(
     std::unique_ptr<MemoryBuffer> &&Buf) {
-  CurrentArchive.reset();
-  CurrentObjectFile.reset();
+  CurrentArchives.clear();
+  CurrentObjectFiles.clear();
+  CurrentFatBinary.reset();
 
   CurrentMemoryBuffer = std::move(Buf);
 }
 
-ErrorOr<MemoryBufferRef>
-BinaryHolder::GetMemoryBufferForFile(StringRef Filename,
-                                     sys::TimeValue Timestamp) {
+ErrorOr<std::vector<MemoryBufferRef>>
+BinaryHolder::GetMemoryBuffersForFile(StringRef Filename,
+                                      sys::TimeValue Timestamp) {
   if (Verbose)
     outs() << "trying to open '" << Filename << "'\n";
 
   // Try that first as it doesn't involve any filesystem access.
-  if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp))
-    return *ErrOrArchiveMember;
+  if (auto ErrOrArchiveMembers = GetArchiveMemberBuffers(Filename, Timestamp))
+    return *ErrOrArchiveMembers;
 
   // If the name ends with a closing paren, there is a huge chance
   // it is an archive member specification.
   if (Filename.endswith(")"))
-    if (auto ErrOrArchiveMember =
-            MapArchiveAndGetMemberBuffer(Filename, Timestamp))
-      return *ErrOrArchiveMember;
+    if (auto ErrOrArchiveMembers =
+            MapArchiveAndGetMemberBuffers(Filename, Timestamp))
+      return *ErrOrArchiveMembers;
 
   // Otherwise, just try opening a standard file. If this is an
   // archive member specifiaction and any of the above didn't handle it
@@ -65,43 +79,64 @@ BinaryHolder::GetMemoryBufferForFile(StringRef Filename,
   changeBackingMemoryBuffer(std::move(*ErrOrFile));
   if (Verbose)
     outs() << "\tloaded file.\n";
-  return CurrentMemoryBuffer->getMemBufferRef();
+
+  auto ErrOrFat = object::MachOUniversalBinary::create(
+      CurrentMemoryBuffer->getMemBufferRef());
+  if (ErrOrFat.getError()) {
+    // Not a fat binary must be a standard one. Return a one element vector.
+    return std::vector<MemoryBufferRef>{CurrentMemoryBuffer->getMemBufferRef()};
+  }
+
+  CurrentFatBinary = std::move(*ErrOrFat);
+  return getMachOFatMemoryBuffers(Filename, *CurrentMemoryBuffer,
+                                  *CurrentFatBinary);
 }
 
-ErrorOr<MemoryBufferRef>
-BinaryHolder::GetArchiveMemberBuffer(StringRef Filename,
-                                     sys::TimeValue Timestamp) {
-  if (!CurrentArchive)
+ErrorOr<std::vector<MemoryBufferRef>>
+BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
+                                      sys::TimeValue Timestamp) {
+  if (CurrentArchives.empty())
     return make_error_code(errc::no_such_file_or_directory);
 
-  StringRef CurArchiveName = CurrentArchive->getFileName();
+  StringRef CurArchiveName = CurrentArchives.front()->getFileName();
   if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
     return make_error_code(errc::no_such_file_or_directory);
 
   // Remove the archive name and the parens around the archive member name.
   Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
 
-  for (const auto &Child : CurrentArchive->children()) {
-    if (auto NameOrErr = Child.getName())
-      if (*NameOrErr == Filename) {
-        if (Timestamp != sys::TimeValue::PosixZeroTime() &&
-            Timestamp != Child.getLastModified()) {
+  std::vector<MemoryBufferRef> Buffers;
+  Buffers.reserve(CurrentArchives.size());
+
+  for (const auto &CurrentArchive : CurrentArchives) {
+    for (const auto &Child : CurrentArchive->children()) {
+      if (auto NameOrErr = Child.getName()) {
+        if (*NameOrErr == Filename) {
+          if (Timestamp != sys::TimeValue::PosixZeroTime() &&
+              Timestamp != Child.getLastModified()) {
+            if (Verbose)
+              outs() << "\tmember had timestamp mismatch.\n";
+            continue;
+          }
           if (Verbose)
-            outs() << "\tmember had timestamp mismatch.\n";
-          continue;
+            outs() << "\tfound member in current archive.\n";
+          auto ErrOrMem = Child.getMemoryBufferRef();
+          if (auto Err = ErrOrMem.getError())
+            return Err;
+          Buffers.push_back(*ErrOrMem);
         }
-        if (Verbose)
-          outs() << "\tfound member in current archive.\n";
-        return Child.getMemoryBufferRef();
       }
+    }
   }
 
-  return make_error_code(errc::no_such_file_or_directory);
+  if (Buffers.empty())
+    return make_error_code(errc::no_such_file_or_directory);
+  return Buffers;
 }
 
-ErrorOr<MemoryBufferRef>
-BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename,
-                                           sys::TimeValue Timestamp) {
+ErrorOr<std::vector<MemoryBufferRef>>
+BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
+                                            sys::TimeValue Timestamp) {
   StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
 
   auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
@@ -112,29 +147,60 @@ BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename,
     outs() << "\topened new archive '" << ArchiveFilename << "'\n";
 
   changeBackingMemoryBuffer(std::move(*ErrOrBuff));
-  auto ErrOrArchive =
-      object::Archive::create(CurrentMemoryBuffer->getMemBufferRef());
-  if (auto Err = ErrOrArchive.getError())
-    return Err;
-
-  CurrentArchive = std::move(*ErrOrArchive);
+  std::vector<MemoryBufferRef> ArchiveBuffers;
+  auto ErrOrFat = object::MachOUniversalBinary::create(
+      CurrentMemoryBuffer->getMemBufferRef());
+  if (ErrOrFat.getError()) {
+    // Not a fat binary must be a standard one.
+    ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef());
+  } else {
+    CurrentFatBinary = std::move(*ErrOrFat);
+    ArchiveBuffers = getMachOFatMemoryBuffers(
+        ArchiveFilename, *CurrentMemoryBuffer, *CurrentFatBinary);
+  }
 
-  return GetArchiveMemberBuffer(Filename, Timestamp);
+  for (auto MemRef : ArchiveBuffers) {
+    auto ErrOrArchive = object::Archive::create(MemRef);
+    if (auto Err = ErrOrArchive.getError())
+      return Err;
+    CurrentArchives.push_back(std::move(*ErrOrArchive));
+  }
+  return GetArchiveMemberBuffers(Filename, Timestamp);
 }
 
 ErrorOr<const object::ObjectFile &>
-BinaryHolder::GetObjectFile(StringRef Filename, sys::TimeValue Timestamp) {
-  auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename, Timestamp);
-  if (auto Err = ErrOrMemBufferRef.getError())
-    return Err;
+BinaryHolder::getObjfileForArch(const Triple &T) {
+  for (const auto &Obj : CurrentObjectFiles) {
+    if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
+      if (getTriple(*MachO).str() == T.str())
+        return *MachO;
+    } else if (Obj->getArch() == T.getArch())
+      return *Obj;
+  }
+
+  return make_error_code(object::object_error::arch_not_found);
+}
 
-  auto ErrOrObjectFile =
-      object::ObjectFile::createObjectFile(*ErrOrMemBufferRef);
-  if (auto Err = ErrOrObjectFile.getError())
+ErrorOr<std::vector<const object::ObjectFile *>>
+BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) {
+  auto ErrOrMemBufferRefs = GetMemoryBuffersForFile(Filename, Timestamp);
+  if (auto Err = ErrOrMemBufferRefs.getError())
     return Err;
 
-  CurrentObjectFile = std::move(*ErrOrObjectFile);
-  return *CurrentObjectFile;
+  std::vector<const object::ObjectFile *> Objects;
+  Objects.reserve(ErrOrMemBufferRefs->size());
+
+  CurrentObjectFiles.clear();
+  for (auto MemBuf : *ErrOrMemBufferRefs) {
+    auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf);
+    if (auto Err = ErrOrObjectFile.getError())
+      return Err;
+
+    Objects.push_back(ErrOrObjectFile->get());
+    CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile));
+  }
+
+  return std::move(Objects);
 }
 }
 }
index e455858..9d7b4bd 100644 (file)
@@ -17,6 +17,7 @@
 #include "llvm/ADT/Triple.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/Error.h"
+#include "llvm/Object/MachOUniversal.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/ErrorOr.h"
@@ -37,77 +38,95 @@ namespace dsymutil {
 /// meaning that a mapping request will invalidate the previous memory
 /// mapping.
 class BinaryHolder {
-  std::unique_ptr<object::Archive> CurrentArchive;
+  std::vector<std::unique_ptr<object::Archive>> CurrentArchives;
   std::unique_ptr<MemoryBuffer> CurrentMemoryBuffer;
-  std::unique_ptr<object::ObjectFile> CurrentObjectFile;
+  std::vector<std::unique_ptr<object::ObjectFile>> CurrentObjectFiles;
+  std::unique_ptr<object::MachOUniversalBinary> CurrentFatBinary;
   bool Verbose;
 
-  /// \brief Get the MemoryBufferRef for the file specification in \p
-  /// Filename from the current archive.
+  /// Get the MemoryBufferRefs for the file specification in \p
+  /// Filename from the current archive. Multiple buffers are returned
+  /// when there are multiple architectures available for the
+  /// requested file.
   ///
   /// This function performs no system calls, it just looks up a
   /// potential match for the given \p Filename in the currently
   /// mapped archive if there is one.
-  ErrorOr<MemoryBufferRef> GetArchiveMemberBuffer(StringRef Filename,
-                                                  sys::TimeValue Timestamp);
+  ErrorOr<std::vector<MemoryBufferRef>>
+  GetArchiveMemberBuffers(StringRef Filename, sys::TimeValue Timestamp);
 
-  /// \brief Interpret Filename as an archive member specification,
-  /// map the corresponding archive to memory and return the
-  /// MemoryBufferRef corresponding to the described member.
-  ErrorOr<MemoryBufferRef>
-  MapArchiveAndGetMemberBuffer(StringRef Filename, sys::TimeValue Timestamp);
+  /// Interpret Filename as an archive member specification map the
+  /// corresponding archive to memory and return the MemoryBufferRefs
+  /// corresponding to the described member. Multiple buffers are
+  /// returned when there are multiple architectures available for the
+  /// requested file.
+  ErrorOr<std::vector<MemoryBufferRef>>
+  MapArchiveAndGetMemberBuffers(StringRef Filename, sys::TimeValue Timestamp);
 
-  /// \brief Return the MemoryBufferRef that holds the memory
-  /// mapping for the given \p Filename. This function will try to
-  /// parse archive member specifications of the form
-  /// /path/to/archive.a(member.o).
+  /// Return the MemoryBufferRef that holds the memory mapping for the
+  /// given \p Filename. This function will try to parse archive
+  /// member specifications of the form /path/to/archive.a(member.o).
   ///
-  /// The returned MemoryBufferRef points to a buffer owned by this
+  /// The returned MemoryBufferRefs points to a buffer owned by this
   /// object. The buffer is valid until the next call to
   /// GetMemoryBufferForFile() on this object.
-  ErrorOr<MemoryBufferRef> GetMemoryBufferForFile(StringRef Filename,
-                                                  sys::TimeValue Timestamp);
+  /// Multiple buffers are returned when there are multiple
+  /// architectures available for the requested file.
+  ErrorOr<std::vector<MemoryBufferRef>>
+  GetMemoryBuffersForFile(StringRef Filename, sys::TimeValue Timestamp);
 
   void changeBackingMemoryBuffer(std::unique_ptr<MemoryBuffer> &&MemBuf);
+  ErrorOr<const object::ObjectFile &> getObjfileForArch(const Triple &T);
 
 public:
   BinaryHolder(bool Verbose) : Verbose(Verbose) {}
 
-  /// \brief Get the ObjectFile designated by the \p Filename. This
+  /// Get the ObjectFiles designated by the \p Filename. This
   /// might be an archive member specification of the form
   /// /path/to/archive.a(member.o).
   ///
   /// Calling this function invalidates the previous mapping owned by
-  /// the BinaryHolder.
-  ErrorOr<const object::ObjectFile &>
-  GetObjectFile(StringRef Filename,
-                sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime());
+  /// the BinaryHolder. Multiple buffers are returned when there are
+  /// multiple architectures available for the requested file.
+  ErrorOr<std::vector<const object::ObjectFile *>>
+  GetObjectFiles(StringRef Filename,
+                 sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime());
 
-  /// \brief Wraps GetObjectFile() to return a derived ObjectFile type.
+  /// Wraps GetObjectFiles() to return a derived ObjectFile type.
   template <typename ObjectFileType>
-  ErrorOr<const ObjectFileType &>
-  GetFileAs(StringRef Filename,
-            sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()) {
-    auto ErrOrObjFile = GetObjectFile(Filename);
+  ErrorOr<std::vector<const ObjectFileType *>>
+  GetFilesAs(StringRef Filename,
+             sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()) {
+    auto ErrOrObjFile = GetObjectFiles(Filename, Timestamp);
     if (auto Err = ErrOrObjFile.getError())
       return Err;
-    if (const auto *Derived = dyn_cast<ObjectFileType>(CurrentObjectFile.get()))
-      return *Derived;
-    return make_error_code(object::object_error::invalid_file_type);
+
+    std::vector<const ObjectFileType *> Objects;
+    Objects.reserve((*ErrOrObjFile).size());
+    for (const auto &Obj : *ErrOrObjFile) {
+      const auto *Derived = dyn_cast<ObjectFileType>(Obj);
+      if (!Derived)
+        return make_error_code(object::object_error::invalid_file_type);
+      Objects.push_back(Derived);
+    }
+    return std::move(Objects);
   }
 
-  /// \brief Access the currently owned ObjectFile. As successfull
-  /// call to GetObjectFile() or GetFileAs() must have been performed
-  /// before calling this.
-  const object::ObjectFile &Get() {
-    assert(CurrentObjectFile);
-    return *CurrentObjectFile;
+  /// Access the currently owned ObjectFile with architecture \p T. As
+  /// successfull call to GetObjectFiles() or GetFilesAs() must have
+  /// been performed before calling this.
+  ErrorOr<const object::ObjectFile &> Get(const Triple &T) {
+    return getObjfileForArch(T);
   }
 
-  /// \brief Access to a derived version of the currently owned
+  /// Access to a derived version of the currently owned
   /// ObjectFile. The conversion must be known to be valid.
-  template <typename ObjectFileType> const ObjectFileType &GetAs() {
-    return cast<ObjectFileType>(*CurrentObjectFile);
+  template <typename ObjectFileType>
+  ErrorOr<const ObjectFileType &> GetAs(const Triple &T) {
+    auto ErrOrObj = Get(T);
+    if (auto Err = ErrOrObj.getError())
+      return Err;
+    return cast<ObjectFileType>(*ErrOrObj);
   }
 
   static Triple getTriple(const object::MachOObjectFile &Obj);
index 24dedfc..e29c885 100644 (file)
@@ -178,9 +178,9 @@ SequenceTraits<std::vector<std::unique_ptr<dsymutil::DebugMapObject>>>::element(
 void MappingTraits<dsymutil::DebugMap>::mapping(IO &io,
                                                 dsymutil::DebugMap &DM) {
   io.mapRequired("triple", DM.BinaryTriple);
-  io.mapOptional("objects", DM.Objects);
   if (void *Ctxt = io.getContext())
     reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM.BinaryTriple;
+  io.mapOptional("objects", DM.Objects);
 }
 
 void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
@@ -188,9 +188,9 @@ void MappingTraits<std::unique_ptr<dsymutil::DebugMap>>::mapping(
   if (!DM)
     DM.reset(new DebugMap());
   io.mapRequired("triple", DM->BinaryTriple);
-  io.mapOptional("objects", DM->Objects);
   if (void *Ctxt = io.getContext())
     reinterpret_cast<YAMLContext *>(Ctxt)->BinaryTriple = DM->BinaryTriple;
+  io.mapOptional("objects", DM->Objects);
 }
 
 MappingTraits<dsymutil::DebugMapObject>::YamlDMO::YamlDMO(
@@ -210,11 +210,11 @@ MappingTraits<dsymutil::DebugMapObject>::YamlDMO::denormalize(IO &IO) {
   StringMap<uint64_t> SymbolAddresses;
 
   sys::path::append(Path, Filename);
-  auto ErrOrObjectFile = BinHolder.GetObjectFile(Path);
-  if (auto EC = ErrOrObjectFile.getError()) {
+  auto ErrOrObjectFiles = BinHolder.GetObjectFiles(Path);
+  if (auto EC = ErrOrObjectFiles.getError()) {
     llvm::errs() << "warning: Unable to open " << Path << " " << EC.message()
                  << '\n';
-  } else {
+  } else if (auto ErrOrObjectFile = BinHolder.Get(Ctxt.BinaryTriple)) {
     // Rewrite the object file symbol addresses in the debug map. The
     // YAML input is mainly used to test llvm-dsymutil without
     // requiring binaries checked-in. If we generate the object files
index ba136d1..484c86a 100644 (file)
@@ -1410,6 +1410,11 @@ private:
                      const DWARFDebugInfoEntryMinimal *DIE = nullptr) const;
 
   bool createStreamer(Triple TheTriple, StringRef OutputFilename);
+
+  /// \brief Attempt to load a debug object from disk.
+  ErrorOr<const object::ObjectFile &> loadObject(BinaryHolder &BinaryHolder,
+                                                 DebugMapObject &Obj,
+                                                 const DebugMap &Map);
   /// @}
 
 private:
@@ -3008,6 +3013,19 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO,
   }
 }
 
+ErrorOr<const object::ObjectFile &>
+DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj,
+                        const DebugMap &Map) {
+  auto ErrOrObjs =
+      BinaryHolder.GetObjectFiles(Obj.getObjectFilename(), Obj.getTimestamp());
+  if (std::error_code EC = ErrOrObjs.getError())
+    reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message());
+  auto ErrOrObj = BinaryHolder.Get(Map.getTriple());
+  if (std::error_code EC = ErrOrObj.getError())
+    reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message());
+  return ErrOrObj;
+}
+
 bool DwarfLinker::link(const DebugMap &Map) {
 
   if (Map.begin() == Map.end()) {
@@ -3027,12 +3045,9 @@ bool DwarfLinker::link(const DebugMap &Map) {
 
     if (Options.Verbose)
       outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
-    auto ErrOrObj =
-        BinHolder.GetObjectFile(Obj->getObjectFilename(), Obj->getTimestamp());
-    if (std::error_code EC = ErrOrObj.getError()) {
-      reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message());
+    auto ErrOrObj = loadObject(BinHolder, *Obj, Map);
+    if (!ErrOrObj)
       continue;
-    }
 
     // Look for relocations that correspond to debug map entries.
     if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
index cda4349..33554f1 100644 (file)
@@ -58,8 +58,8 @@ private:
   void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp);
   void resetParserState();
   uint64_t getMainBinarySymbolAddress(StringRef Name);
-  void loadMainBinarySymbols();
-  void loadCurrentObjectFileSymbols();
+  void loadMainBinarySymbols(const MachOObjectFile &MainBinary);
+  void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj);
   void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
                                   uint8_t SectionIndex, uint16_t Flags,
                                   uint64_t Value);
@@ -92,27 +92,38 @@ void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename,
   sys::path::append(Path, Filename);
 
   auto MachOOrError =
-      CurrentObjectHolder.GetFileAs<MachOObjectFile>(Path, Timestamp);
+      CurrentObjectHolder.GetFilesAs<MachOObjectFile>(Path, Timestamp);
   if (auto Error = MachOOrError.getError()) {
     Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
             Error.message() + "\n");
     return;
   }
 
-  loadCurrentObjectFileSymbols();
+  auto ErrOrAchObj =
+      CurrentObjectHolder.GetAs<MachOObjectFile>(Result->getTriple());
+  if (auto Err = ErrOrAchObj.getError()) {
+    return Warning(Twine("cannot open debug object \"") + Path.str() + "\": " +
+                   Err.message() + "\n");
+  }
+
   CurrentDebugMapObject = &Result->addDebugMapObject(Path, Timestamp);
+  loadCurrentObjectFileSymbols(*ErrOrAchObj);
 }
 
 /// This main parsing routine tries to open the main binary and if
 /// successful iterates over the STAB entries. The real parsing is
 /// done in handleStabSymbolTableEntry.
 ErrorOr<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
-  auto MainBinOrError = MainBinaryHolder.GetFileAs<MachOObjectFile>(BinaryPath);
+  auto MainBinOrError =
+      MainBinaryHolder.GetFilesAs<MachOObjectFile>(BinaryPath);
   if (auto Error = MainBinOrError.getError())
     return Error;
 
-  const MachOObjectFile &MainBinary = *MainBinOrError;
-  loadMainBinarySymbols();
+  if (MainBinOrError->size() != 1)
+    return make_error_code(object::object_error::invalid_file_type);
+
+  const MachOObjectFile &MainBinary = *MainBinOrError->front();
+  loadMainBinarySymbols(MainBinary);
   Result = make_unique<DebugMap>(BinaryHolder::getTriple(MainBinary));
   MainBinaryStrings = MainBinary.getStringTableData();
   for (const SymbolRef &Symbol : MainBinary.symbols()) {
@@ -189,10 +200,11 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
 }
 
 /// Load the current object file symbols into CurrentObjectAddresses.
-void MachODebugMapParser::loadCurrentObjectFileSymbols() {
+void MachODebugMapParser::loadCurrentObjectFileSymbols(
+    const object::MachOObjectFile &Obj) {
   CurrentObjectAddresses.clear();
 
-  for (auto Sym : CurrentObjectHolder.Get().symbols()) {
+  for (auto Sym : Obj.symbols()) {
     uint64_t Addr = Sym.getValue();
     ErrorOr<StringRef> Name = Sym.getName();
     if (!Name)
@@ -213,9 +225,10 @@ uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
 
 /// Load the interesting main binary symbols' addresses into
 /// MainBinarySymbolAddresses.
-void MachODebugMapParser::loadMainBinarySymbols() {
-  const MachOObjectFile &MainBinary = MainBinaryHolder.GetAs<MachOObjectFile>();
+void MachODebugMapParser::loadMainBinarySymbols(
+    const MachOObjectFile &MainBinary) {
   section_iterator Section = MainBinary.section_end();
+  MainBinarySymbolAddresses.clear();
   for (const auto &Sym : MainBinary.symbols()) {
     SymbolRef::Type Type = Sym.getType();
     // Skip undefined and STAB entries.