proxygen
ElfCache.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <link.h>
20 
21 /*
22  * This is declared in `link.h' on Linux platforms, but apparently not on the
23  * Mac version of the file. It's harmless to declare again, in any case.
24  *
25  * Note that declaring it with `extern "C"` results in linkage conflicts.
26  */
27 extern struct r_debug _r_debug;
28 
29 namespace folly {
30 namespace symbolizer {
31 
33  // _r_debug synchronization is... lacking to say the least. It's
34  // meant as an aid for debuggers and synchronization is done by
35  // calling dl_debug_state() which debuggers are supposed to
36  // intercept by setting a breakpoint on.
37 
38  // Can't really do that here, so we apply the hope-and-pray strategy.
39  if (_r_debug.r_version != 1 || _r_debug.r_state != r_debug::RT_CONSISTENT) {
40  // computo ergo sum
41  return 1;
42  }
43 
44  // r_map -> head of a linked list of 'link_map_t' entries,
45  // one per ELF 'binary' in the process address space.
46  size_t count = 0;
47  for (auto lmap = _r_debug.r_map; lmap != nullptr; lmap = lmap->l_next) {
48  ++count;
49  }
50  return count;
51 }
52 
54  map_.reserve(capacity);
55  slots_.reserve(capacity);
56 
57  // Preallocate
58  for (size_t i = 0; i < capacity; ++i) {
59  slots_.push_back(std::make_shared<ElfFile>());
60  }
61 }
62 
63 std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
64  if (p.size() > Path::kMaxSize) {
65  return nullptr;
66  }
67 
69  auto pos = map_.find(scratchpad_);
70  if (pos != map_.end()) {
71  return slots_[pos->second];
72  }
73 
74  size_t n = map_.size();
75  if (n >= slots_.size()) {
76  DCHECK_EQ(map_.size(), slots_.size());
77  return nullptr;
78  }
79 
80  auto& f = slots_[n];
81 
82  const char* msg = "";
83  int r = f->openAndFollow(scratchpad_.data(), true, &msg);
84  if (r != ElfFile::kSuccess) {
85  return nullptr;
86  }
87 
88  map_[scratchpad_] = n;
89  return f;
90 }
91 
92 ElfCache::ElfCache(size_t capacity) : capacity_(capacity) {}
93 
94 std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
95  std::lock_guard<std::mutex> lock(mutex_);
96 
97  auto pos = files_.find(p);
98  if (pos != files_.end()) {
99  // Found, move to back (MRU)
100  auto& entry = pos->second;
101  lruList_.erase(lruList_.iterator_to(*entry));
102  lruList_.push_back(*entry);
103  return filePtr(entry);
104  }
105 
106  auto entry = std::make_shared<Entry>();
107  entry->path = p.str();
108  auto& path = entry->path;
109 
110  // No negative caching
111  const char* msg = "";
112  int r = entry->file.openAndFollow(path.c_str(), true, &msg);
113  if (r != ElfFile::kSuccess) {
114  return nullptr;
115  }
116 
117  if (files_.size() == capacity_) {
118  auto& e = lruList_.front();
119  lruList_.pop_front();
120  files_.erase(e.path);
121  }
122 
123  files_.emplace(entry->path, entry);
124  lruList_.push_back(*entry);
125 
126  return filePtr(entry);
127 }
128 
129 std::shared_ptr<ElfFile> ElfCache::filePtr(const std::shared_ptr<Entry>& e) {
130  // share ownership
131  return std::shared_ptr<ElfFile>(e, &e->file);
132 }
133 } // namespace symbolizer
134 } // namespace folly
auto f
std::string str() const
Definition: Range.h:591
struct r_debug _r_debug
std::shared_ptr< ElfFile > getFile(StringPiece path) override
Definition: ElfCache.cpp:63
constexpr size_type size() const
Definition: Range.h:431
std::unordered_map< StringPiece, std::shared_ptr< Entry >, Hash > files_
Definition: ElfCache.h:138
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::shared_ptr< ElfFile > getFile(StringPiece path) override
Definition: ElfCache.cpp:94
static std::shared_ptr< ElfFile > filePtr(const std::shared_ptr< Entry > &e)
Definition: ElfCache.cpp:129
boost::container::flat_map< Path, int > map_
Definition: ElfCache.h:109
size_t countLoadedElfFiles()
Definition: ElfCache.cpp:32
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
std::vector< std::shared_ptr< ElfFile > > slots_
Definition: ElfCache.h:110
int * count
ElfCache(size_t capacity)
Definition: ElfCache.cpp:92