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