//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that aims to be a dropin replacement for
// Darwin's dsymutil.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
#include "llvm/ADT/DenseMap.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 <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 {
public:
using TimestampTy = sys::TimePoint<std::chrono::seconds>;
BinaryHolder(bool Verbose = false) : Verbose(Verbose) {}
// Forward declarations for friend declaration.
class ObjectEntry;
class ArchiveEntry;
/// Base class shared by cached entries, representing objects and archives.
class EntryBase {
protected:
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 {
public:
/// Load the given object binary in memory.
Error load(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;
Result.reserve(Objects.size());
for (auto &Object : Objects) {
const auto *Derived = dyn_cast<ObjectFileType>(Object.get());
if (!Derived)
return errorCodeToError(object::object_error::invalid_file_type);
Result.push_back(Derived);
}
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);
}
private:
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 {
public:
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(StringRef Filename, TimestampTy Timestamp, bool Verbose = false);
Expected<const ObjectEntry &> getObjectEntry(StringRef Filename,
TimestampTy Timestamp,
bool Verbose = false);
private:
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();
private:
/// 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;
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),
DenseMapInfo<unsigned>::getHashValue(
K.Timestamp.time_since_epoch().count()));
}
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
#endif