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/Support/raw_ostream.h"
     17 
     18 namespace llvm {
     19 namespace dsymutil {
     20 
     21 ErrorOr<MemoryBufferRef>
     22 BinaryHolder::GetMemoryBufferForFile(StringRef Filename) {
     23   if (Verbose)
     24     outs() << "trying to open '" << Filename << "'\n";
     25 
     26   // Try that first as it doesn't involve any filesystem access.
     27   if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename))
     28     return *ErrOrArchiveMember;
     29 
     30   // If the name ends with a closing paren, there is a huge chance
     31   // it is an archive member specification.
     32   if (Filename.endswith(")"))
     33     if (auto ErrOrArchiveMember = MapArchiveAndGetMemberBuffer(Filename))
     34       return *ErrOrArchiveMember;
     35 
     36   // Otherwise, just try opening a standard file. If this is an
     37   // archive member specifiaction and any of the above didn't handle it
     38   // (either because the archive is not there anymore, or because the
     39   // archive doesn't contain the requested member), this will still
     40   // provide a sensible error message.
     41   auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
     42   if (auto Err = ErrOrFile.getError())
     43     return Err;
     44 
     45   if (Verbose)
     46     outs() << "\tloaded file.\n";
     47   CurrentArchive.reset();
     48   CurrentMemoryBuffer = std::move(ErrOrFile.get());
     49   return CurrentMemoryBuffer->getMemBufferRef();
     50 }
     51 
     52 ErrorOr<MemoryBufferRef>
     53 BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) {
     54   if (!CurrentArchive)
     55     return make_error_code(errc::no_such_file_or_directory);
     56 
     57   StringRef CurArchiveName = CurrentArchive->getFileName();
     58   if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
     59     return make_error_code(errc::no_such_file_or_directory);
     60 
     61   // Remove the archive name and the parens around the archive member name.
     62   Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
     63 
     64   for (const auto &Child : CurrentArchive->children()) {
     65     if (auto NameOrErr = Child.getName())
     66       if (*NameOrErr == Filename) {
     67         if (Verbose)
     68           outs() << "\tfound member in current archive.\n";
     69         return Child.getMemoryBufferRef();
     70       }
     71   }
     72 
     73   return make_error_code(errc::no_such_file_or_directory);
     74 }
     75 
     76 ErrorOr<MemoryBufferRef>
     77 BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) {
     78   StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
     79 
     80   auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
     81   if (auto Err = ErrOrBuff.getError())
     82     return Err;
     83 
     84   if (Verbose)
     85     outs() << "\topened new archive '" << ArchiveFilename << "'\n";
     86   auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef());
     87   if (auto Err = ErrOrArchive.getError())
     88     return Err;
     89 
     90   CurrentArchive = std::move(*ErrOrArchive);
     91   CurrentMemoryBuffer = std::move(*ErrOrBuff);
     92 
     93   return GetArchiveMemberBuffer(Filename);
     94 }
     95 
     96 ErrorOr<const object::ObjectFile &>
     97 BinaryHolder::GetObjectFile(StringRef Filename) {
     98   auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename);
     99   if (auto Err = ErrOrMemBufferRef.getError())
    100     return Err;
    101 
    102   auto ErrOrObjectFile =
    103       object::ObjectFile::createObjectFile(*ErrOrMemBufferRef);
    104   if (auto Err = ErrOrObjectFile.getError())
    105     return Err;
    106 
    107   CurrentObjectFile = std::move(*ErrOrObjectFile);
    108   return *CurrentObjectFile;
    109 }
    110 }
    111 }
    112