blob: dee944d826a10a6352f25b064a2b38acb2cdb741 [file] [log] [blame]
//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// This program is a utility that aims to be a dropin replacement for
// Darwin's dsymutil.
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/Error.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <mutex>
namespace llvm {
namespace dsymutil {
/// The BinaryHolder class is responsible for creating and owning
/// ObjectFiles and their underlying MemoryBuffers. It differs from a simple
/// OwningBinary in that it handles accessing and caching of archives and its
/// members.
class BinaryHolder {
using TimestampTy = sys::TimePoint<std::chrono::seconds>;
BinaryHolder(IntrusiveRefCntPtr<vfs::FileSystem> VFS, bool Verbose = false)
: VFS(VFS), Verbose(Verbose) {}
// Forward declarations for friend declaration.
class ObjectEntry;
class ArchiveEntry;
/// Base class shared by cached entries, representing objects and archives.
class EntryBase {
std::unique_ptr<MemoryBuffer> MemBuffer;
std::unique_ptr<object::MachOUniversalBinary> FatBinary;
std::string FatBinaryName;
/// Cached entry holding one or more (in case of a fat binary) object files.
class ObjectEntry : public EntryBase {
/// Load the given object binary in memory.
Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
bool Verbose = false);
/// Access all owned ObjectFiles.
std::vector<const object::ObjectFile *> getObjects() const;
/// Access to a derived version of all the currently owned ObjectFiles. The
/// conversion might be invalid, in which case an Error is returned.
template <typename ObjectFileType>
Expected<std::vector<const ObjectFileType *>> getObjectsAs() const {
std::vector<const ObjectFileType *> Result;
for (auto &Object : Objects) {
const auto *Derived = dyn_cast<ObjectFileType>(Object.get());
if (!Derived)
return errorCodeToError(object::object_error::invalid_file_type);
return Result;
/// Access the owned ObjectFile with architecture \p T.
Expected<const object::ObjectFile &> getObject(const Triple &T) const;
/// Access to a derived version of the currently owned ObjectFile with
/// architecture \p T. The conversion must be known to be valid.
template <typename ObjectFileType>
Expected<const ObjectFileType &> getObjectAs(const Triple &T) const {
auto Object = getObject(T);
if (!Object)
return Object.takeError();
return cast<ObjectFileType>(*Object);
std::vector<std::unique_ptr<object::ObjectFile>> Objects;
friend ArchiveEntry;
/// Cached entry holding one or more (in the of a fat binary) archive files.
class ArchiveEntry : public EntryBase {
struct KeyTy {
std::string Filename;
TimestampTy Timestamp;
KeyTy() : Filename(), Timestamp() {}
KeyTy(StringRef Filename, TimestampTy Timestamp)
: Filename(Filename.str()), Timestamp(Timestamp) {}
/// Load the given object binary in memory.
Error load(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
TimestampTy Timestamp, bool Verbose = false);
Expected<const ObjectEntry &> getObjectEntry(StringRef Filename,
TimestampTy Timestamp,
bool Verbose = false);
std::vector<std::unique_ptr<object::Archive>> Archives;
DenseMap<KeyTy, ObjectEntry> MemberCache;
std::mutex MemberCacheMutex;
Expected<const ObjectEntry &>
getObjectEntry(StringRef Filename, TimestampTy Timestamp = TimestampTy());
void clear();
/// Cache of static archives. Objects that are part of a static archive are
/// stored under this object, rather than in the map below.
StringMap<ArchiveEntry> ArchiveCache;
std::mutex ArchiveCacheMutex;
/// Object entries for objects that are not in a static archive.
StringMap<ObjectEntry> ObjectCache;
std::mutex ObjectCacheMutex;
/// Virtual File System instance.
IntrusiveRefCntPtr<vfs::FileSystem> VFS;
bool Verbose;
} // namespace dsymutil
template <> struct DenseMapInfo<dsymutil::BinaryHolder::ArchiveEntry::KeyTy> {
static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getEmptyKey() {
return dsymutil::BinaryHolder::ArchiveEntry::KeyTy();
static inline dsymutil::BinaryHolder::ArchiveEntry::KeyTy getTombstoneKey() {
return dsymutil::BinaryHolder::ArchiveEntry::KeyTy("/", {});
static unsigned
getHashValue(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &K) {
return hash_combine(DenseMapInfo<StringRef>::getHashValue(K.Filename),
static bool isEqual(const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &LHS,
const dsymutil::BinaryHolder::ArchiveEntry::KeyTy &RHS) {
return LHS.Filename == RHS.Filename && LHS.Timestamp == RHS.Timestamp;
} // namespace llvm