/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#include "folly/experimental/symbolizer/ElfCache.h"
+#include <folly/experimental/symbolizer/ElfCache.h>
+
+#include <link.h>
+
+/*
+ * This is declared in `link.h' on Linux platforms, but apparently not on the
+ * Mac version of the file. It's harmless to declare again, in any case.
+ *
+ * Note that declaring it with `extern "C"` results in linkage conflicts.
+ */
+extern struct r_debug _r_debug;
namespace folly { namespace symbolizer {
+size_t countLoadedElfFiles() {
+ // _r_debug synchronization is... lacking to say the least. It's
+ // meant as an aid for debuggers and synchrnization is done by
+ // calling dl_debug_state() which debuggers are supposed to
+ // intercept by setting a breakpoint on.
+
+ // Can't really do that here, so we apply the hope-and-pray strategy.
+ if (_r_debug.r_version != 1 || _r_debug.r_state != r_debug::RT_CONSISTENT) {
+ // computo ergo sum
+ return 1;
+ }
+
+ // r_map -> head of a linked list of 'link_map_t' entries,
+ // one per ELF 'binary' in the process address space.
+ size_t count = 0;
+ for (auto lmap = _r_debug.r_map; lmap != nullptr; lmap = lmap->l_next) {
+ ++count;
+ }
+ return count;
+}
+
SignalSafeElfCache::SignalSafeElfCache(size_t capacity) {
map_.reserve(capacity);
slots_.reserve(capacity);
}
auto& f = slots_[n];
- if (f->openNoThrow(path.data()) == -1) {
+
+ const char* msg = "";
+ int r = f->openAndFollow(path.data(), true, &msg);
+ if (r != ElfFile::kSuccess) {
return nullptr;
}
ElfCache::ElfCache(size_t capacity) : capacity_(capacity) { }
std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
- auto path = p.str();
-
std::lock_guard<std::mutex> lock(mutex_);
- auto pos = files_.find(path);
+ auto pos = files_.find(p);
if (pos != files_.end()) {
// Found, move to back (MRU)
auto& entry = pos->second;
}
auto entry = std::make_shared<Entry>();
+ entry->path = p.str();
+ auto& path = entry->path;
// No negative caching
- if (entry->file.openNoThrow(path.c_str()) == -1) {
+ const char* msg = "";
+ int r = entry->file.openAndFollow(path.c_str(), true, &msg);
+ if (r != ElfFile::kSuccess) {
return nullptr;
}
if (files_.size() == capacity_) {
- // Evict LRU
+ auto& e = lruList_.front();
lruList_.pop_front();
+ files_.erase(e.path);
}
- files_.emplace(std::move(path), entry);
+ files_.emplace(entry->path, entry);
lruList_.push_back(*entry);
return filePtr(entry);
}
}} // namespaces
-