Fix copyright lines
[folly.git] / folly / experimental / symbolizer / ElfCache.cpp
index 79652a49f015b00773db96e68075bde56d315619..9f95ebd926609c6dd3437755b781c8c418240815 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2014-present 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>
 
-namespace folly { namespace symbolizer {
+#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 synchronization 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);
@@ -33,8 +65,8 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
     return nullptr;
   }
 
-  Path path(p);
-  auto pos = map_.find(path);
+  scratchpad_.assign(p);
+  auto pos = map_.find(scratchpad_);
   if (pos != map_.end()) {
     return slots_[pos->second];
   }
@@ -46,22 +78,23 @@ std::shared_ptr<ElfFile> SignalSafeElfCache::getFile(StringPiece p) {
   }
 
   auto& f = slots_[n];
-  if (f->openNoThrow(path.data()) == -1) {
+
+  const char* msg = "";
+  int r = f->openAndFollow(scratchpad_.data(), true, &msg);
+  if (r != ElfFile::kSuccess) {
     return nullptr;
   }
 
-  map_[path] = n;
+  map_[scratchpad_] = n;
   return f;
 }
 
-ElfCache::ElfCache(size_t capacity) : capacity_(capacity) { }
+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;
@@ -71,18 +104,23 @@ std::shared_ptr<ElfFile> ElfCache::getFile(StringPiece p) {
   }
 
   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);
@@ -92,6 +130,5 @@ std::shared_ptr<ElfFile> ElfCache::filePtr(const std::shared_ptr<Entry>& e) {
   // share ownership
   return std::shared_ptr<ElfFile>(e, &e->file);
 }
-
-}}  // namespaces
-
+} // namespace symbolizer
+} // namespace folly