183 lines · c
1//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This program is a utility that aims to be a dropin replacement for10// Darwin's dsymutil.11//12//===----------------------------------------------------------------------===//13#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H14#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H15 16#include "llvm/ADT/DenseMap.h"17#include "llvm/ADT/StringMap.h"18#include "llvm/Object/Archive.h"19#include "llvm/Object/Error.h"20#include "llvm/Object/MachOUniversal.h"21#include "llvm/Object/ObjectFile.h"22#include "llvm/Support/Chrono.h"23#include "llvm/Support/Errc.h"24#include "llvm/Support/ErrorOr.h"25#include "llvm/Support/VirtualFileSystem.h"26#include "llvm/TargetParser/Triple.h"27 28#include <mutex>29 30namespace llvm {31namespace dsymutil {32 33/// The BinaryHolder class is responsible for creating and owning34/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple35/// OwningBinary in that it handles accessing and caching of archives and its36/// members.37class BinaryHolder {38public:39 using TimestampTy = sys::TimePoint<std::chrono::seconds>;40 41 struct Options {42 Options(bool Verbose = false, bool Warn = true)43 : Verbose(Verbose), Warn(Warn) {}44 bool Verbose;45 bool Warn;46 };47 48 BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS,49 BinaryHolder::Options Opts = {});50 51 // Forward declarations for friend declaration.52 class ObjectEntry;53 class ArchiveEntry;54 55 /// Base class shared by cached entries, representing objects and archives.56 class EntryBase {57 protected:58 std::unique_ptr<MemoryBuffer> MemBuffer;59 std::unique_ptr<object::MachOUniversalBinary> FatBinary;60 std::string FatBinaryName;61 };62 63 /// Cached entry holding one or more (in case of a fat binary) object files.64 class ObjectEntry : public EntryBase {65 public:66 /// Load the given object binary in memory.67 Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,68 TimestampTy Timestamp, BinaryHolder::Options = {});69 70 /// Access all owned ObjectFiles.71 std::vector<const object::ObjectFile *> getObjects() const;72 73 /// Access to a derived version of all the currently owned ObjectFiles. The74 /// conversion might be invalid, in which case an Error is returned.75 template <typename ObjectFileType>76 Expected<std::vector<const ObjectFileType *>> getObjectsAs() const {77 std::vector<const ObjectFileType *> Result;78 Result.reserve(Objects.size());79 for (auto &Object : Objects) {80 const auto *Derived = dyn_cast<ObjectFileType>(Object.get());81 if (!Derived)82 return errorCodeToError(object::object_error::invalid_file_type);83 Result.push_back(Derived);84 }85 return Result;86 }87 88 /// Access the owned ObjectFile with architecture \p T.89 Expected<const object::ObjectFile &> getObject(const Triple &T) const;90 91 /// Access to a derived version of the currently owned ObjectFile with92 /// architecture \p T. The conversion must be known to be valid.93 template <typename ObjectFileType>94 Expected<const ObjectFileType &> getObjectAs(const Triple &T) const {95 auto Object = getObject(T);96 if (!Object)97 return Object.takeError();98 return cast<ObjectFileType>(*Object);99 }100 101 private:102 std::vector<std::unique_ptr<object::ObjectFile>> Objects;103 friend ArchiveEntry;104 };105 106 /// Cached entry holding one or more (in the of a fat binary) archive files.107 class ArchiveEntry : public EntryBase {108 public:109 struct KeyTy {110 std::string Filename;111 TimestampTy Timestamp;112 113 KeyTy() = default;114 KeyTy(StringRef Filename, TimestampTy Timestamp)115 : Filename(Filename.str()), Timestamp(Timestamp) {}116 };117 118 /// Load the given object binary in memory.119 Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,120 TimestampTy Timestamp, BinaryHolder::Options = {});121 122 Expected<const ObjectEntry &> getObjectEntry(StringRef Filename,123 TimestampTy Timestamp,124 BinaryHolder::Options = {});125 126 private:127 std::vector<std::unique_ptr<object::Archive>> Archives;128 DenseMap<KeyTy, std::unique_ptr<ObjectEntry>> MemberCache;129 std::mutex MemberCacheMutex;130 };131 132 Expected<const ObjectEntry &>133 getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy());134 135 void clear();136 void eraseObjectEntry(StringRef Filename);137 138private:139 /// Cache of static archives. Objects that are part of a static archive are140 /// stored under this object, rather than in the map below.141 StringMap<std::unique_ptr<ArchiveEntry>> ArchiveCache;142 StringMap<uint32_t> ArchiveRefCounter;143 std::mutex ArchiveCacheMutex;144 145 /// Object entries for objects that are not in a static archive.146 StringMap<std::unique_ptr<ObjectEntry>> ObjectCache;147 StringMap<uint32_t> ObjectRefCounter;148 std::mutex ObjectCacheMutex;149 150 /// Virtual File System instance.151 IntrusiveRefCntPtr<vfs::FileSystem> VFS;152 153 Options Opts;154};155 156} // namespace dsymutil157 158template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> {159 160 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() {161 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();162 }163 164 static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() {165 return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});166 }167 168 static unsigned169 getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) {170 return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename),171 DenseMapInfo<unsigned>::getHashValue(172 K.Timestamp.time_since_epoch().count()));173 }174 175 static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS,176 const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) {177 return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp;178 }179};180 181} // namespace llvm182#endif183