forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			210 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- BinaryHolder.cpp --------------------------------------------------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This program is a utility that aims to be a dropin replacement for
 | 
						|
// Darwin's dsymutil.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "BinaryHolder.h"
 | 
						|
#include "llvm/Object/MachO.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
namespace dsymutil {
 | 
						|
 | 
						|
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 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 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
 | 
						|
  // (either because the archive is not there anymore, or because the
 | 
						|
  // archive doesn't contain the requested member), this will still
 | 
						|
  // provide a sensible error message.
 | 
						|
  auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
 | 
						|
  if (auto Err = ErrOrFile.getError())
 | 
						|
    return Err;
 | 
						|
 | 
						|
  changeBackingMemoryBuffer(std::move(*ErrOrFile));
 | 
						|
  if (Verbose)
 | 
						|
    outs() << "\tloaded file.\n";
 | 
						|
 | 
						|
  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<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 = 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();
 | 
						|
 | 
						|
  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);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Buffers.empty())
 | 
						|
    return make_error_code(errc::no_such_file_or_directory);
 | 
						|
  return Buffers;
 | 
						|
}
 | 
						|
 | 
						|
ErrorOr<std::vector<MemoryBufferRef>>
 | 
						|
BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
 | 
						|
                                            sys::TimeValue Timestamp) {
 | 
						|
  StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
 | 
						|
 | 
						|
  auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
 | 
						|
  if (auto Err = ErrOrBuff.getError())
 | 
						|
    return Err;
 | 
						|
 | 
						|
  if (Verbose)
 | 
						|
    outs() << "\topened new archive '" << ArchiveFilename << "'\n";
 | 
						|
 | 
						|
  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);
 | 
						|
  }
 | 
						|
 | 
						|
  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::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);
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
  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);
 | 
						|
}
 | 
						|
}
 | 
						|
}
 |