OSDN Git Service

Update aosp/master LLVM for rebase to r256229
[android-x86/external-llvm.git] / tools / dsymutil / BinaryHolder.cpp
index ad66105..4c2c1d1 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "BinaryHolder.h"
+#include "llvm/Object/MachO.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace llvm {
 namespace dsymutil {
 
-ErrorOr<MemoryBufferRef>
-BinaryHolder::GetMemoryBufferForFile(StringRef Filename) {
+Triple BinaryHolder::getTriple(const object::MachOObjectFile &Obj) {
+  // If a ThumbTriple is returned, use it instead of the standard
+  // one. This is because the thumb triple always allows to create a
+  // target, whereas the non-thumb one might not.
+  Triple ThumbTriple;
+  Triple T = Obj.getArch(nullptr, &ThumbTriple);
+  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) {
+  CurrentArchives.clear();
+  CurrentObjectFiles.clear();
+  CurrentFatBinary.reset();
+
+  CurrentMemoryBuffer = std::move(Buf);
+}
+
+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))
-    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))
-      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
@@ -42,39 +76,70 @@ BinaryHolder::GetMemoryBufferForFile(StringRef Filename) {
   if (auto Err = ErrOrFile.getError())
     return Err;
 
+  changeBackingMemoryBuffer(std::move(*ErrOrFile));
   if (Verbose)
     outs() << "\tloaded file.\n";
-  CurrentArchive.reset();
-  CurrentMemoryBuffer = std::move(ErrOrFile.get());
-  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) {
-  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 (Verbose)
-          outs() << "\tfound member in current archive.\n";
-        return Child.getMemoryBufferRef();
+  std::vector<MemoryBufferRef> Buffers;
+  Buffers.reserve(CurrentArchives.size());
+
+  for (const auto &CurrentArchive : CurrentArchives) {
+    for (auto ChildOrErr : CurrentArchive->children()) {
+      if (std::error_code Err = ChildOrErr.getError())
+        return Err;
+      const auto &Child = *ChildOrErr;
+      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() << "\tfound member in current archive.\n";
+          auto ErrOrMem = Child.getMemoryBufferRef();
+          if (auto Err = ErrOrMem.getError())
+            return Err;
+          Buffers.push_back(*ErrOrMem);
+        }
       }
+    }
   }
 
-  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) {
+ErrorOr<std::vector<MemoryBufferRef>>
+BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
+                                            sys::TimeValue Timestamp) {
   StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
 
   auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
@@ -83,29 +148,62 @@ BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) {
 
   if (Verbose)
     outs() << "\topened new archive '" << ArchiveFilename << "'\n";
-  auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef());
-  if (auto Err = ErrOrArchive.getError())
-    return Err;
 
-  CurrentArchive = std::move(*ErrOrArchive);
-  CurrentMemoryBuffer = std::move(*ErrOrBuff);
+  changeBackingMemoryBuffer(std::move(*ErrOrBuff));
+  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);
+  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) {
-  auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename);
-  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;
+  }
 
-  auto ErrOrObjectFile =
-      object::ObjectFile::createObjectFile(*ErrOrMemBufferRef);
-  if (auto Err = ErrOrObjectFile.getError())
+  return make_error_code(object::object_error::arch_not_found);
+}
+
+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);
 }
 }
 }