Home | History | Annotate | Download | only in dsymutil
      1 //===-- BinaryHolder.cpp --------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This program is a utility that aims to be a dropin replacement for
     11 // Darwin's dsymutil.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "BinaryHolder.h"
     16 #include "llvm/Object/MachO.h"
     17 #include "llvm/Support/raw_ostream.h"
     18 
     19 namespace llvm {
     20 namespace dsymutil {
     21 
     22 Triple BinaryHolder::getTriple(const object::MachOObjectFile &Obj) {
     23   // If a ThumbTriple is returned, use it instead of the standard
     24   // one. This is because the thumb triple always allows to create a
     25   // target, whereas the non-thumb one might not.
     26   Triple ThumbTriple;
     27   Triple T = Obj.getArch(nullptr, &ThumbTriple);
     28   return ThumbTriple.getArch() ? ThumbTriple : T;
     29 }
     30 
     31 static std::vector<MemoryBufferRef>
     32 getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
     33                          object::MachOUniversalBinary &Fat) {
     34   std::vector<MemoryBufferRef> Buffers;
     35   StringRef FatData = Fat.getData();
     36   for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
     37        ++It) {
     38     StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
     39     Buffers.emplace_back(ObjData, Filename);
     40   }
     41   return Buffers;
     42 }
     43 
     44 void BinaryHolder::changeBackingMemoryBuffer(
     45     std::unique_ptr<MemoryBuffer> &&Buf) {
     46   CurrentArchives.clear();
     47   CurrentObjectFiles.clear();
     48   CurrentFatBinary.reset();
     49 
     50   CurrentMemoryBuffer = std::move(Buf);
     51 }
     52 
     53 ErrorOr<std::vector<MemoryBufferRef>>
     54 BinaryHolder::GetMemoryBuffersForFile(StringRef Filename,
     55                                       sys::TimeValue Timestamp) {
     56   if (Verbose)
     57     outs() << "trying to open '" << Filename << "'\n";
     58 
     59   // Try that first as it doesn't involve any filesystem access.
     60   if (auto ErrOrArchiveMembers = GetArchiveMemberBuffers(Filename, Timestamp))
     61     return *ErrOrArchiveMembers;
     62 
     63   // If the name ends with a closing paren, there is a huge chance
     64   // it is an archive member specification.
     65   if (Filename.endswith(")"))
     66     if (auto ErrOrArchiveMembers =
     67             MapArchiveAndGetMemberBuffers(Filename, Timestamp))
     68       return *ErrOrArchiveMembers;
     69 
     70   // Otherwise, just try opening a standard file. If this is an
     71   // archive member specifiaction and any of the above didn't handle it
     72   // (either because the archive is not there anymore, or because the
     73   // archive doesn't contain the requested member), this will still
     74   // provide a sensible error message.
     75   auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
     76   if (auto Err = ErrOrFile.getError())
     77     return Err;
     78 
     79   changeBackingMemoryBuffer(std::move(*ErrOrFile));
     80   if (Verbose)
     81     outs() << "\tloaded file.\n";
     82 
     83   auto ErrOrFat = object::MachOUniversalBinary::create(
     84       CurrentMemoryBuffer->getMemBufferRef());
     85   if (ErrOrFat.getError()) {
     86     // Not a fat binary must be a standard one. Return a one element vector.
     87     return std::vector<MemoryBufferRef>{CurrentMemoryBuffer->getMemBufferRef()};
     88   }
     89 
     90   CurrentFatBinary = std::move(*ErrOrFat);
     91   return getMachOFatMemoryBuffers(Filename, *CurrentMemoryBuffer,
     92                                   *CurrentFatBinary);
     93 }
     94 
     95 ErrorOr<std::vector<MemoryBufferRef>>
     96 BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
     97                                       sys::TimeValue Timestamp) {
     98   if (CurrentArchives.empty())
     99     return make_error_code(errc::no_such_file_or_directory);
    100 
    101   StringRef CurArchiveName = CurrentArchives.front()->getFileName();
    102   if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
    103     return make_error_code(errc::no_such_file_or_directory);
    104 
    105   // Remove the archive name and the parens around the archive member name.
    106   Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
    107 
    108   std::vector<MemoryBufferRef> Buffers;
    109   Buffers.reserve(CurrentArchives.size());
    110 
    111   for (const auto &CurrentArchive : CurrentArchives) {
    112     for (auto ChildOrErr : CurrentArchive->children()) {
    113       if (std::error_code Err = ChildOrErr.getError())
    114         return Err;
    115       const auto &Child = *ChildOrErr;
    116       if (auto NameOrErr = Child.getName()) {
    117         if (*NameOrErr == Filename) {
    118           if (Timestamp != sys::TimeValue::PosixZeroTime() &&
    119               Timestamp != Child.getLastModified()) {
    120             if (Verbose)
    121               outs() << "\tmember had timestamp mismatch.\n";
    122             continue;
    123           }
    124           if (Verbose)
    125             outs() << "\tfound member in current archive.\n";
    126           auto ErrOrMem = Child.getMemoryBufferRef();
    127           if (auto Err = ErrOrMem.getError())
    128             return Err;
    129           Buffers.push_back(*ErrOrMem);
    130         }
    131       }
    132     }
    133   }
    134 
    135   if (Buffers.empty())
    136     return make_error_code(errc::no_such_file_or_directory);
    137   return Buffers;
    138 }
    139 
    140 ErrorOr<std::vector<MemoryBufferRef>>
    141 BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
    142                                             sys::TimeValue Timestamp) {
    143   StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
    144 
    145   auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
    146   if (auto Err = ErrOrBuff.getError())
    147     return Err;
    148 
    149   if (Verbose)
    150     outs() << "\topened new archive '" << ArchiveFilename << "'\n";
    151 
    152   changeBackingMemoryBuffer(std::move(*ErrOrBuff));
    153   std::vector<MemoryBufferRef> ArchiveBuffers;
    154   auto ErrOrFat = object::MachOUniversalBinary::create(
    155       CurrentMemoryBuffer->getMemBufferRef());
    156   if (ErrOrFat.getError()) {
    157     // Not a fat binary must be a standard one.
    158     ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef());
    159   } else {
    160     CurrentFatBinary = std::move(*ErrOrFat);
    161     ArchiveBuffers = getMachOFatMemoryBuffers(
    162         ArchiveFilename, *CurrentMemoryBuffer, *CurrentFatBinary);
    163   }
    164 
    165   for (auto MemRef : ArchiveBuffers) {
    166     auto ErrOrArchive = object::Archive::create(MemRef);
    167     if (auto Err = ErrOrArchive.getError())
    168       return Err;
    169     CurrentArchives.push_back(std::move(*ErrOrArchive));
    170   }
    171   return GetArchiveMemberBuffers(Filename, Timestamp);
    172 }
    173 
    174 ErrorOr<const object::ObjectFile &>
    175 BinaryHolder::getObjfileForArch(const Triple &T) {
    176   for (const auto &Obj : CurrentObjectFiles) {
    177     if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
    178       if (getTriple(*MachO).str() == T.str())
    179         return *MachO;
    180     } else if (Obj->getArch() == T.getArch())
    181       return *Obj;
    182   }
    183 
    184   return make_error_code(object::object_error::arch_not_found);
    185 }
    186 
    187 ErrorOr<std::vector<const object::ObjectFile *>>
    188 BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) {
    189   auto ErrOrMemBufferRefs = GetMemoryBuffersForFile(Filename, Timestamp);
    190   if (auto Err = ErrOrMemBufferRefs.getError())
    191     return Err;
    192 
    193   std::vector<const object::ObjectFile *> Objects;
    194   Objects.reserve(ErrOrMemBufferRefs->size());
    195 
    196   CurrentObjectFiles.clear();
    197   for (auto MemBuf : *ErrOrMemBufferRefs) {
    198     auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf);
    199     if (auto Err = ErrOrObjectFile.getError())
    200       return Err;
    201 
    202     Objects.push_back(ErrOrObjectFile->get());
    203     CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile));
    204   }
    205 
    206   return std::move(Objects);
    207 }
    208 }
    209 }
    210