#pragma once
#include <forward_list>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <boost/intrusive/avl_set.hpp>
#include <folly/Optional.h>
#include <folly/Range.h>
#include <folly/experimental/symbolizer/Elf.h>
#include <folly/hash/Hash.h>
#include <folly/memory/ReentrantAllocator.h>
#include <folly/portability/Config.h>
namespace folly {
namespace symbolizer {
#if FOLLY_HAVE_ELF
class ElfCacheBase {
public:
virtual std::shared_ptr<ElfFile> getFile(StringPiece path) = 0;
virtual ~ElfCacheBase() {}
};
class SignalSafeElfCache : public ElfCacheBase {
public:
std::shared_ptr<ElfFile> getFile(StringPiece path) override;
class Path {
public:
Path(
char const* data,
std::size_t size,
reentrant_allocator<char> const& alloc) noexcept;
Path() = delete;
Path(Path const&) = delete;
void operator=(Path const&) = delete;
operator StringPiece() const noexcept { return data_; }
char const* c_str() const noexcept { return data_.data(); }
friend bool operator<(Path const& a, Path const& b) noexcept {
return a.data_ < b.data_;
}
private:
std::vector<char, reentrant_allocator<char>> data_;
};
struct Entry : boost::intrusive::avl_set_base_hook<> {
Path path;
std::shared_ptr<ElfFile> file;
bool init = false;
explicit Entry(StringPiece p, reentrant_allocator<char> alloc) noexcept
: path{p.data(), p.size(), alloc},
file{std::allocate_shared<ElfFile>(alloc)} {}
Entry(Entry const&) = delete;
Entry& operator=(Entry const& that) = delete;
friend bool operator<(Entry const& a, Entry const& b) noexcept {
return a.path < b.path;
}
};
struct State {
reentrant_allocator<void> alloc{
reentrant_allocator_options().block_size_lg(16).large_size_lg(12)};
std::forward_list<Entry, reentrant_allocator<Entry>> list{alloc};
boost::intrusive::avl_set<Entry> map;
};
Optional<State> state_;
};
class ElfCache : public ElfCacheBase {
public:
std::shared_ptr<ElfFile> getFile(StringPiece path) override;
private:
std::mutex mutex_;
struct Entry {
std::string path;
ElfFile file;
};
static std::shared_ptr<ElfFile> filePtr(const std::shared_ptr<Entry>& e);
std::unordered_map<StringPiece, std::shared_ptr<Entry>, Hash> files_;
};
#endif
}
}