OSDN Git Service

Merge "Add __s32 define."
[android-x86/system-extras.git] / simpleperf / thread_tree.cpp
index 9407733..3134874 100644 (file)
 
 #include "thread_tree.h"
 
-#include <base/logging.h>
+#include <limits>
+
+#include <android-base/logging.h>
+
 #include "environment.h"
 #include "perf_event.h"
 #include "record.h"
@@ -25,6 +28,9 @@ bool MapComparator::operator()(const MapEntry* map1, const MapEntry* map2) const
   if (map1->start_addr != map2->start_addr) {
     return map1->start_addr < map2->start_addr;
   }
+  // Compare map->len instead of map->get_end_addr() here. Because we set map's len
+  // to std::numeric_limits<uint64_t>::max() in FindMapByAddr(), which makes
+  // map->get_end_addr() overflow.
   if (map1->len != map2->len) {
     return map1->len < map2->len;
   }
@@ -72,45 +78,29 @@ ThreadEntry* ThreadTree::FindThreadOrNew(int pid, int tid) {
   return it->second.get();
 }
 
-static void RemoveOverlappedMap(std::set<MapEntry*, MapComparator>* map_set, const MapEntry* map) {
-  for (auto it = map_set->begin(); it != map_set->end();) {
-    if ((*it)->start_addr >= map->start_addr + map->len) {
-      break;
-    }
-    if ((*it)->start_addr + (*it)->len <= map->start_addr) {
-      ++it;
-    } else {
-      it = map_set->erase(it);
-    }
-  }
-}
-
 void ThreadTree::AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff, uint64_t time,
                               const std::string& filename) {
   // kernel map len can be 0 when record command is not run in supervisor mode.
   if (len == 0) {
     return;
   }
-  DsoEntry* dso = FindKernelDsoOrNew(filename);
-  MapEntry* map = new MapEntry{
-      start_addr, len, pgoff, time, dso,
-  };
-  map_storage_.push_back(std::unique_ptr<MapEntry>(map));
-  RemoveOverlappedMap(&kernel_map_tree_, map);
+  Dso* dso = FindKernelDsoOrNew(filename);
+  MapEntry* map = AllocateMap(MapEntry(start_addr, len, pgoff, time, dso));
+  FixOverlappedMap(&kernel_map_tree_, map);
   auto pair = kernel_map_tree_.insert(map);
   CHECK(pair.second);
 }
 
-DsoEntry* ThreadTree::FindKernelDsoOrNew(const std::string& filename) {
+Dso* ThreadTree::FindKernelDsoOrNew(const std::string& filename) {
   if (filename == DEFAULT_KERNEL_MMAP_NAME) {
     if (kernel_dso_ == nullptr) {
-      kernel_dso_ = DsoFactory::GetInstance()->CreateDso(DSO_KERNEL);
+      kernel_dso_ = Dso::CreateDso(DSO_KERNEL);
     }
     return kernel_dso_.get();
   }
   auto it = module_dso_tree_.find(filename);
   if (it == module_dso_tree_.end()) {
-    module_dso_tree_[filename] = DsoFactory::GetInstance()->CreateDso(DSO_KERNEL_MODULE, filename);
+    module_dso_tree_[filename] = Dso::CreateDso(DSO_KERNEL_MODULE, filename);
     it = module_dso_tree_.find(filename);
   }
   return it->second.get();
@@ -119,38 +109,63 @@ DsoEntry* ThreadTree::FindKernelDsoOrNew(const std::string& filename) {
 void ThreadTree::AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff,
                               uint64_t time, const std::string& filename) {
   ThreadEntry* thread = FindThreadOrNew(pid, tid);
-  DsoEntry* dso = FindUserDsoOrNew(filename);
-  MapEntry* map = new MapEntry{
-      start_addr, len, pgoff, time, dso,
-  };
-  map_storage_.push_back(std::unique_ptr<MapEntry>(map));
-  RemoveOverlappedMap(&thread->maps, map);
+  Dso* dso = FindUserDsoOrNew(filename);
+  MapEntry* map = AllocateMap(MapEntry(start_addr, len, pgoff, time, dso));
+  FixOverlappedMap(&thread->maps, map);
   auto pair = thread->maps.insert(map);
   CHECK(pair.second);
 }
 
-DsoEntry* ThreadTree::FindUserDsoOrNew(const std::string& filename) {
+Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename) {
   auto it = user_dso_tree_.find(filename);
   if (it == user_dso_tree_.end()) {
-    user_dso_tree_[filename] = DsoFactory::GetInstance()->CreateDso(DSO_ELF_FILE, filename);
+    user_dso_tree_[filename] = Dso::CreateDso(DSO_ELF_FILE, filename);
     it = user_dso_tree_.find(filename);
   }
   return it->second.get();
 }
 
+MapEntry* ThreadTree::AllocateMap(const MapEntry& value) {
+  MapEntry* map = new MapEntry(value);
+  map_storage_.push_back(std::unique_ptr<MapEntry>(map));
+  return map;
+}
+
+void ThreadTree::FixOverlappedMap(std::set<MapEntry*, MapComparator>* map_set, const MapEntry* map) {
+  for (auto it = map_set->begin(); it != map_set->end();) {
+    if ((*it)->start_addr >= map->get_end_addr()) {
+      // No more overlapped maps.
+      break;
+    }
+    if ((*it)->get_end_addr() <= map->start_addr) {
+      ++it;
+    } else {
+      MapEntry* old = *it;
+      if (old->start_addr < map->start_addr) {
+        MapEntry* before = AllocateMap(MapEntry(old->start_addr, map->start_addr - old->start_addr,
+                                                old->pgoff, old->time, old->dso));
+        map_set->insert(before);
+      }
+      if (old->get_end_addr() > map->get_end_addr()) {
+        MapEntry* after = AllocateMap(
+            MapEntry(map->get_end_addr(), old->get_end_addr() - map->get_end_addr(),
+                     map->get_end_addr() - old->start_addr + old->pgoff, old->time, old->dso));
+        map_set->insert(after);
+      }
+
+      it = map_set->erase(it);
+    }
+  }
+}
+
 static bool IsAddrInMap(uint64_t addr, const MapEntry* map) {
-  return (addr >= map->start_addr && addr < map->start_addr + map->len);
+  return (addr >= map->start_addr && addr < map->get_end_addr());
 }
 
 static MapEntry* FindMapByAddr(const std::set<MapEntry*, MapComparator>& maps, uint64_t addr) {
   // Construct a map_entry which is strictly after the searched map_entry, based on MapComparator.
-  MapEntry find_map = {
-      addr,        // start_addr
-      ULLONG_MAX,  // len
-      0,           // pgoff
-      ULLONG_MAX,  // time
-      nullptr,     // dso
-  };
+  MapEntry find_map(addr, std::numeric_limits<uint64_t>::max(), 0,
+                    std::numeric_limits<uint64_t>::max(), nullptr);
   auto it = maps.upper_bound(&find_map);
   if (it != maps.begin() && IsAddrInMap(addr, *--it)) {
     return *it;
@@ -168,20 +183,30 @@ const MapEntry* ThreadTree::FindMap(const ThreadEntry* thread, uint64_t ip, bool
   return result != nullptr ? result : &unknown_map_;
 }
 
-const SymbolEntry* ThreadTree::FindSymbol(const MapEntry* map, uint64_t ip) {
-  uint64_t offset_in_file;
+const Symbol* ThreadTree::FindSymbol(const MapEntry* map, uint64_t ip) {
+  uint64_t vaddr_in_file;
   if (map->dso == kernel_dso_.get()) {
-    offset_in_file = ip;
+    vaddr_in_file = ip;
   } else {
-    offset_in_file = ip - map->start_addr + map->pgoff;
+    vaddr_in_file = ip - map->start_addr + map->dso->MinVirtualAddress();
   }
-  const SymbolEntry* symbol = map->dso->FindSymbol(offset_in_file);
+  const Symbol* symbol = map->dso->FindSymbol(vaddr_in_file);
   if (symbol == nullptr) {
     symbol = &unknown_symbol_;
   }
   return symbol;
 }
 
+void ThreadTree::Clear() {
+  thread_tree_.clear();
+  thread_comm_storage_.clear();
+  kernel_map_tree_.clear();
+  map_storage_.clear();
+  kernel_dso_.reset();
+  module_dso_tree_.clear();
+  user_dso_tree_.clear();
+}
+
 void BuildThreadTree(const Record& record, ThreadTree* thread_tree) {
   if (record.header.type == PERF_RECORD_MMAP) {
     const MmapRecord& r = *static_cast<const MmapRecord*>(&record);