/* * Copyright (c) Meta Platforms, Inc. and 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 #include #include #include #include #include #include #include #include #include #include #include namespace folly { namespace symbolizer { #if FOLLY_HAVE_ELF class ElfCacheBase { public: virtual std::shared_ptr 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 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, reentrant_allocator>; // // 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 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> data_; }; struct Entry : boost::intrusive::avl_set_base_hook<> { Path path; std::shared_ptr file; bool init = false; explicit Entry(StringPiece p, reentrant_allocator alloc) noexcept : path{p.data(), p.size(), alloc}, file{std::allocate_shared(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 alloc{ reentrant_allocator_options().block_size_lg(16).large_size_lg(12)}; std::forward_list> list{alloc}; // note: map entry dtors check that they have already been unlinked boost::intrusive::avl_set map; // must follow list }; Optional 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 getFile(StringPiece path) override; private: std::mutex mutex_; struct Entry { std::string path; ElfFile file; }; static std::shared_ptr filePtr(const std::shared_ptr& e); std::unordered_map, Hash> files_; }; #endif // FOLLY_HAVE_ELF } // namespace symbolizer } // namespace folly