//===-- 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/Support/raw_ostream.h" namespace llvm { namespace dsymutil { ErrorOr BinaryHolder::GetMemoryBufferForFile(StringRef Filename) { 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 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; // 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; if (Verbose) outs() << "\tloaded file.\n"; CurrentArchive.reset(); CurrentMemoryBuffer = std::move(ErrOrFile.get()); return CurrentMemoryBuffer->getMemBufferRef(); } ErrorOr BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) { if (!CurrentArchive) return make_error_code(errc::no_such_file_or_directory); StringRef CurArchiveName = CurrentArchive->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(); } } return make_error_code(errc::no_such_file_or_directory); } ErrorOr BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) { 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"; auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef()); if (auto Err = ErrOrArchive.getError()) return Err; CurrentArchive = std::move(*ErrOrArchive); CurrentMemoryBuffer = std::move(*ErrOrBuff); return GetArchiveMemberBuffer(Filename); } ErrorOr BinaryHolder::GetObjectFile(StringRef Filename) { auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename); if (auto Err = ErrOrMemBufferRef.getError()) return Err; auto ErrOrObjectFile = object::ObjectFile::createObjectFile(*ErrOrMemBufferRef); if (auto Err = ErrOrObjectFile.getError()) return Err; CurrentObjectFile = std::move(*ErrOrObjectFile); return *CurrentObjectFile; } } }