BinaryHolder.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. //===-- BinaryHolder.cpp --------------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This program is a utility that aims to be a dropin replacement for
  10. // Darwin's dsymutil.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "BinaryHolder.h"
  14. #include "llvm/Object/MachO.h"
  15. #include "llvm/Support/WithColor.h"
  16. #include "llvm/Support/raw_ostream.h"
  17. namespace llvm {
  18. namespace dsymutil {
  19. static std::pair<StringRef, StringRef>
  20. getArchiveAndObjectName(StringRef Filename) {
  21. StringRef Archive = Filename.substr(0, Filename.rfind('('));
  22. StringRef Object = Filename.substr(Archive.size() + 1).drop_back();
  23. return {Archive, Object};
  24. }
  25. static bool isArchive(StringRef Filename) { return Filename.endswith(")"); }
  26. static std::vector<MemoryBufferRef>
  27. getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
  28. object::MachOUniversalBinary &Fat) {
  29. std::vector<MemoryBufferRef> Buffers;
  30. StringRef FatData = Fat.getData();
  31. for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
  32. ++It) {
  33. StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
  34. Buffers.emplace_back(ObjData, Filename);
  35. }
  36. return Buffers;
  37. }
  38. Error BinaryHolder::ArchiveEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
  39. StringRef Filename,
  40. TimestampTy Timestamp, bool Verbose) {
  41. StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
  42. // Try to load archive and force it to be memory mapped.
  43. auto ErrOrBuff = (ArchiveFilename == "-")
  44. ? MemoryBuffer::getSTDIN()
  45. : VFS->getBufferForFile(ArchiveFilename, -1, false);
  46. if (auto Err = ErrOrBuff.getError())
  47. return errorCodeToError(Err);
  48. MemBuffer = std::move(*ErrOrBuff);
  49. if (Verbose)
  50. WithColor::note() << "loaded archive '" << ArchiveFilename << "'\n";
  51. // Load one or more archive buffers, depending on whether we're dealing with
  52. // a fat binary.
  53. std::vector<MemoryBufferRef> ArchiveBuffers;
  54. auto ErrOrFat =
  55. object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef());
  56. if (!ErrOrFat) {
  57. consumeError(ErrOrFat.takeError());
  58. ArchiveBuffers.push_back(MemBuffer->getMemBufferRef());
  59. } else {
  60. FatBinary = std::move(*ErrOrFat);
  61. FatBinaryName = std::string(ArchiveFilename);
  62. ArchiveBuffers =
  63. getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary);
  64. }
  65. // Finally, try to load the archives.
  66. Archives.reserve(ArchiveBuffers.size());
  67. for (auto MemRef : ArchiveBuffers) {
  68. auto ErrOrArchive = object::Archive::create(MemRef);
  69. if (!ErrOrArchive)
  70. return ErrOrArchive.takeError();
  71. Archives.push_back(std::move(*ErrOrArchive));
  72. }
  73. return Error::success();
  74. }
  75. Error BinaryHolder::ObjectEntry::load(IntrusiveRefCntPtr<vfs::FileSystem> VFS,
  76. StringRef Filename, TimestampTy Timestamp,
  77. bool Verbose) {
  78. // Try to load regular binary and force it to be memory mapped.
  79. auto ErrOrBuff = (Filename == "-")
  80. ? MemoryBuffer::getSTDIN()
  81. : VFS->getBufferForFile(Filename, -1, false);
  82. if (auto Err = ErrOrBuff.getError())
  83. return errorCodeToError(Err);
  84. if (Filename != "-" && Timestamp != sys::TimePoint<>()) {
  85. llvm::ErrorOr<vfs::Status> Stat = VFS->status(Filename);
  86. if (!Stat)
  87. return errorCodeToError(Stat.getError());
  88. if (Timestamp != std::chrono::time_point_cast<std::chrono::seconds>(
  89. Stat->getLastModificationTime()))
  90. WithColor::warning() << Filename
  91. << ": timestamp mismatch between object file ("
  92. << Stat->getLastModificationTime()
  93. << ") and debug map (" << Timestamp << ")\n";
  94. }
  95. MemBuffer = std::move(*ErrOrBuff);
  96. if (Verbose)
  97. WithColor::note() << "loaded object.\n";
  98. // Load one or more object buffers, depending on whether we're dealing with a
  99. // fat binary.
  100. std::vector<MemoryBufferRef> ObjectBuffers;
  101. auto ErrOrFat =
  102. object::MachOUniversalBinary::create(MemBuffer->getMemBufferRef());
  103. if (!ErrOrFat) {
  104. consumeError(ErrOrFat.takeError());
  105. ObjectBuffers.push_back(MemBuffer->getMemBufferRef());
  106. } else {
  107. FatBinary = std::move(*ErrOrFat);
  108. FatBinaryName = std::string(Filename);
  109. ObjectBuffers =
  110. getMachOFatMemoryBuffers(FatBinaryName, *MemBuffer, *FatBinary);
  111. }
  112. Objects.reserve(ObjectBuffers.size());
  113. for (auto MemRef : ObjectBuffers) {
  114. auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemRef);
  115. if (!ErrOrObjectFile)
  116. return ErrOrObjectFile.takeError();
  117. Objects.push_back(std::move(*ErrOrObjectFile));
  118. }
  119. return Error::success();
  120. }
  121. std::vector<const object::ObjectFile *>
  122. BinaryHolder::ObjectEntry::getObjects() const {
  123. std::vector<const object::ObjectFile *> Result;
  124. Result.reserve(Objects.size());
  125. for (auto &Object : Objects) {
  126. Result.push_back(Object.get());
  127. }
  128. return Result;
  129. }
  130. Expected<const object::ObjectFile &>
  131. BinaryHolder::ObjectEntry::getObject(const Triple &T) const {
  132. for (const auto &Obj : Objects) {
  133. if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
  134. if (MachO->getArchTriple().str() == T.str())
  135. return *MachO;
  136. } else if (Obj->getArch() == T.getArch())
  137. return *Obj;
  138. }
  139. return errorCodeToError(object::object_error::arch_not_found);
  140. }
  141. Expected<const BinaryHolder::ObjectEntry &>
  142. BinaryHolder::ArchiveEntry::getObjectEntry(StringRef Filename,
  143. TimestampTy Timestamp,
  144. bool Verbose) {
  145. StringRef ArchiveFilename;
  146. StringRef ObjectFilename;
  147. std::tie(ArchiveFilename, ObjectFilename) = getArchiveAndObjectName(Filename);
  148. KeyTy Key = {ObjectFilename, Timestamp};
  149. // Try the cache first.
  150. std::lock_guard<std::mutex> Lock(MemberCacheMutex);
  151. if (MemberCache.count(Key))
  152. return *MemberCache[Key];
  153. // Create a new ObjectEntry, but don't add it to the cache yet. Loading of
  154. // the archive members might fail and we don't want to lock the whole archive
  155. // during this operation.
  156. auto OE = std::make_unique<ObjectEntry>();
  157. for (const auto &Archive : Archives) {
  158. Error Err = Error::success();
  159. for (auto Child : Archive->children(Err)) {
  160. if (auto NameOrErr = Child.getName()) {
  161. if (*NameOrErr == ObjectFilename) {
  162. auto ModTimeOrErr = Child.getLastModified();
  163. if (!ModTimeOrErr)
  164. return ModTimeOrErr.takeError();
  165. if (Timestamp != sys::TimePoint<>() &&
  166. Timestamp != std::chrono::time_point_cast<std::chrono::seconds>(
  167. ModTimeOrErr.get())) {
  168. if (Verbose)
  169. WithColor::warning()
  170. << *NameOrErr
  171. << ": timestamp mismatch between archive member ("
  172. << ModTimeOrErr.get() << ") and debug map (" << Timestamp
  173. << ")\n";
  174. continue;
  175. }
  176. if (Verbose)
  177. WithColor::note() << "found member in archive.\n";
  178. auto ErrOrMem = Child.getMemoryBufferRef();
  179. if (!ErrOrMem)
  180. return ErrOrMem.takeError();
  181. auto ErrOrObjectFile =
  182. object::ObjectFile::createObjectFile(*ErrOrMem);
  183. if (!ErrOrObjectFile)
  184. return ErrOrObjectFile.takeError();
  185. OE->Objects.push_back(std::move(*ErrOrObjectFile));
  186. }
  187. }
  188. }
  189. if (Err)
  190. return std::move(Err);
  191. }
  192. if (OE->Objects.empty())
  193. return errorCodeToError(errc::no_such_file_or_directory);
  194. MemberCache[Key] = std::move(OE);
  195. return *MemberCache[Key];
  196. }
  197. Expected<const BinaryHolder::ObjectEntry &>
  198. BinaryHolder::getObjectEntry(StringRef Filename, TimestampTy Timestamp) {
  199. if (Verbose)
  200. WithColor::note() << "trying to open '" << Filename << "'\n";
  201. // If this is an archive, we might have either the object or the archive
  202. // cached. In this case we can load it without accessing the file system.
  203. if (isArchive(Filename)) {
  204. StringRef ArchiveFilename = getArchiveAndObjectName(Filename).first;
  205. std::lock_guard<std::mutex> Lock(ArchiveCacheMutex);
  206. if (ArchiveCache.count(ArchiveFilename)) {
  207. return ArchiveCache[ArchiveFilename]->getObjectEntry(Filename, Timestamp,
  208. Verbose);
  209. } else {
  210. auto AE = std::make_unique<ArchiveEntry>();
  211. auto Err = AE->load(VFS, Filename, Timestamp, Verbose);
  212. if (Err) {
  213. // Don't return the error here: maybe the file wasn't an archive.
  214. llvm::consumeError(std::move(Err));
  215. } else {
  216. ArchiveCache[ArchiveFilename] = std::move(AE);
  217. return ArchiveCache[ArchiveFilename]->getObjectEntry(
  218. Filename, Timestamp, Verbose);
  219. }
  220. }
  221. }
  222. // If this is an object, we might have it cached. If not we'll have to load
  223. // it from the file system and cache it now.
  224. std::lock_guard<std::mutex> Lock(ObjectCacheMutex);
  225. if (!ObjectCache.count(Filename)) {
  226. auto OE = std::make_unique<ObjectEntry>();
  227. auto Err = OE->load(VFS, Filename, Timestamp, Verbose);
  228. if (Err)
  229. return std::move(Err);
  230. ObjectCache[Filename] = std::move(OE);
  231. }
  232. return *ObjectCache[Filename];
  233. }
  234. void BinaryHolder::clear() {
  235. std::lock_guard<std::mutex> ArchiveLock(ArchiveCacheMutex);
  236. std::lock_guard<std::mutex> ObjectLock(ObjectCacheMutex);
  237. ArchiveCache.clear();
  238. ObjectCache.clear();
  239. }
  240. } // namespace dsymutil
  241. } // namespace llvm