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