173 lines
5.9 KiB
C
173 lines
5.9 KiB
C
|
//===-- BinaryHolder.h - Utility class for accessing binaries -------------===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt 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.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
|
||
|
#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H
|
||
|
|
||
|
#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 {
|
||
|
public:
|
||
|
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 {
|
||
|
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(IntrusiveRefCntPtr<vfs::FileSystem> VFS, StringRef Filename,
|
||
|
TimestampTy Timestamp, 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(IntrusiveRefCntPtr<vfs::FileSystem> VFS, 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;
|
||
|
|
||
|
/// 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),
|
||
|
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
|