139 lines
3.8 KiB
C++
139 lines
3.8 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <forward_list>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include <boost/intrusive/avl_set.hpp>
|
|
|
|
#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() {}
|
|
};
|
|
|
|
/**
|
|
* Cache ELF files. Async-signal-safe: does memory allocation via mmap.
|
|
*
|
|
* Not MT-safe. May not be used concurrently from multiple threads.
|
|
*/
|
|
class SignalSafeElfCache : public ElfCacheBase {
|
|
public:
|
|
std::shared_ptr<ElfFile> getFile(StringPiece path) override;
|
|
|
|
// Path
|
|
//
|
|
// A minimal implementation of the subset of std::string used below, as if:
|
|
//
|
|
// using Path = std::basic_string<
|
|
// char, std::char_traits<char>, reentrant_allocator<char>>;
|
|
//
|
|
// Since some library implementations of std::basic_string, as on CentOS 7,
|
|
// do not build when instantiated with a non-default-constructible allocator,
|
|
// and since other library replacements, such as folly::basic_fbstring, just
|
|
// ignore the allocator parameter.
|
|
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;
|
|
|
|
/* implicit */ 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};
|
|
// note: map entry dtors check that they have already been unlinked
|
|
boost::intrusive::avl_set<Entry> map; // must follow list
|
|
};
|
|
Optional<State> state_;
|
|
};
|
|
|
|
/**
|
|
* General-purpose ELF file cache.
|
|
*
|
|
* LRU of given capacity. MT-safe (uses locking). Not async-signal-safe.
|
|
*/
|
|
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 // FOLLY_HAVE_ELF
|
|
|
|
} // namespace symbolizer
|
|
} // namespace folly
|