Simpleperf: refactor dso.

Having DsoEntry and DsoFactory confuses me which part code should belong to.
This change merges the two into class Dso and makes things clear.
It is also a preparation for performance optimization in Dso.

Bug: 23387541
Change-Id: I41e773406a7f1582a11a18859df252ce8ea3acfa
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 55963c2..0ac4464 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -17,102 +17,39 @@
 #include "dso.h"
 
 #include <stdlib.h>
+
+#include <limits>
+
 #include <base/logging.h>
+
 #include "environment.h"
 #include "read_elf.h"
 #include "utils.h"
 
-const std::string& SymbolEntry::GetDemangledName() const {
+const std::string& Symbol::GetDemangledName() const {
   if (demangled_name_.empty()) {
-    demangled_name_ = DsoFactory::GetInstance()->Demangle(name);
+    demangled_name_ = Dso::Demangle(name);
   }
   return demangled_name_;
 }
 
-bool SymbolComparator::operator()(const std::unique_ptr<SymbolEntry>& symbol1,
-                                  const std::unique_ptr<SymbolEntry>& symbol2) {
+bool SymbolComparator::operator()(const std::unique_ptr<Symbol>& symbol1,
+                                  const std::unique_ptr<Symbol>& symbol2) {
   return symbol1->addr < symbol2->addr;
 }
 
-DsoEntry::DsoEntry(DsoType type, const std::string& path)
-    : type(type), path(path), is_loaded(false) {
-}
+bool Dso::demangle_ = true;
+std::string Dso::symfs_dir_;
+std::string Dso::vmlinux_;
+std::unordered_map<std::string, BuildId> Dso::build_id_map_;
 
-const SymbolEntry* DsoEntry::FindSymbol(uint64_t offset_in_dso) {
-  if (!is_loaded) {
-    DsoFactory::GetInstance()->LoadDso(this);
-    is_loaded = true;
-  }
-  std::unique_ptr<SymbolEntry> symbol(new SymbolEntry{
-      "",             // name
-      offset_in_dso,  // addr
-      0,              // len
-  });
-
-  auto it = symbols.upper_bound(symbol);
-  if (it != symbols.begin()) {
-    --it;
-    if ((*it)->addr <= offset_in_dso && (*it)->addr + (*it)->len > offset_in_dso) {
-      return (*it).get();
-    }
-  }
-  return nullptr;
-}
-
-DsoFactory* DsoFactory::GetInstance() {
-  static DsoFactory dso_factory;
-  return &dso_factory;
-}
-
-DsoFactory::DsoFactory() : demangle_(true) {
-}
-
-void DsoFactory::SetDemangle(bool demangle) {
+void Dso::SetDemangle(bool demangle) {
   demangle_ = demangle;
 }
 
-bool DsoFactory::SetSymFsDir(const std::string& symfs_dir) {
-  std::string dirname = symfs_dir;
-  if (!dirname.empty()) {
-    if (dirname.back() != '/') {
-      dirname.push_back('/');
-    }
-    std::vector<std::string> files;
-    std::vector<std::string> subdirs;
-    GetEntriesInDir(symfs_dir, &files, &subdirs);
-    if (files.empty() && subdirs.empty()) {
-      LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir << "'";
-      return false;
-    }
-  }
-  symfs_dir_ = dirname;
-  return true;
-}
-
-void DsoFactory::SetVmlinux(const std::string& vmlinux) {
-  vmlinux_ = vmlinux;
-}
-
-void DsoFactory::SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids) {
-  std::unordered_map<std::string, BuildId> map;
-  for (auto& pair : build_ids) {
-    LOG(DEBUG) << "build_id_map: " << pair.first << ", " << pair.second.ToString();
-    map.insert(pair);
-  }
-  build_id_map_ = std::move(map);
-}
-
-std::unique_ptr<DsoEntry> DsoFactory::CreateDso(DsoType dso_type, const std::string& dso_path) {
-  std::string path = dso_path;
-  if (dso_type == DSO_KERNEL) {
-    path = "[kernel.kallsyms]";
-  }
-  return std::unique_ptr<DsoEntry>(new DsoEntry(dso_type, path));
-}
-
 extern "C" char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status);
 
-std::string DsoFactory::Demangle(const std::string& name) {
+std::string Dso::Demangle(const std::string& name) {
   if (!demangle_) {
     return name;
   }
@@ -137,56 +74,121 @@
   return result;
 }
 
-bool DsoFactory::LoadDso(DsoEntry* dso) {
-  switch (dso->type) {
-    case DSO_KERNEL:
-      return LoadKernel(dso);
-    case DSO_KERNEL_MODULE:
-      return LoadKernelModule(dso);
-    case DSO_ELF_FILE:
-      return LoadElfFile(dso);
-    default:
+bool Dso::SetSymFsDir(const std::string& symfs_dir) {
+  std::string dirname = symfs_dir;
+  if (!dirname.empty()) {
+    if (dirname.back() != '/') {
+      dirname.push_back('/');
+    }
+    std::vector<std::string> files;
+    std::vector<std::string> subdirs;
+    GetEntriesInDir(symfs_dir, &files, &subdirs);
+    if (files.empty() && subdirs.empty()) {
+      LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir << "'";
       return false;
+    }
   }
+  symfs_dir_ = dirname;
+  return true;
+}
+
+void Dso::SetVmlinux(const std::string& vmlinux) {
+  vmlinux_ = vmlinux;
+}
+
+void Dso::SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids) {
+  std::unordered_map<std::string, BuildId> map;
+  for (auto& pair : build_ids) {
+    LOG(DEBUG) << "build_id_map: " << pair.first << ", " << pair.second.ToString();
+    map.insert(pair);
+  }
+  build_id_map_ = std::move(map);
+}
+
+BuildId Dso::GetExpectedBuildId(const std::string& filename) {
+  auto it = build_id_map_.find(filename);
+  if (it != build_id_map_.end()) {
+    return it->second;
+  }
+  return BuildId();
+}
+
+std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_path) {
+  std::string path = dso_path;
+  if (dso_type == DSO_KERNEL) {
+    path = "[kernel.kallsyms]";
+  }
+  return std::unique_ptr<Dso>(new Dso(dso_type, path));
+}
+
+Dso::Dso(DsoType type, const std::string& path) : type_(type), path_(path), is_loaded_(false) {
+}
+
+const Symbol* Dso::FindSymbol(uint64_t offset_in_dso) {
+  if (!is_loaded_) {
+    is_loaded_ = true;
+    if (!Load()) {
+      LOG(DEBUG) << "failed to load dso: " << path_;
+      return nullptr;
+    }
+  }
+  std::unique_ptr<Symbol> symbol(new Symbol{
+      "",             // name
+      offset_in_dso,  // addr
+      0,              // len
+  });
+
+  auto it = symbols_.upper_bound(symbol);
+  if (it != symbols_.begin()) {
+    --it;
+    if ((*it)->addr <= offset_in_dso && (*it)->addr + (*it)->len > offset_in_dso) {
+      return (*it).get();
+    }
+  }
+  return nullptr;
+}
+
+bool Dso::Load() {
+  bool result = false;
+  switch (type_) {
+    case DSO_KERNEL:
+      result = LoadKernel();
+      break;
+    case DSO_KERNEL_MODULE:
+      result = LoadKernelModule();
+      break;
+    case DSO_ELF_FILE:
+      result = LoadElfFile();
+      break;
+  }
+  if (result) {
+    FixupSymbolLength();
+  }
+  return result;
 }
 
 static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
   return (symbol.type == 'T' || symbol.type == 't' || symbol.type == 'W' || symbol.type == 'w');
 }
 
-static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol, DsoEntry* dso) {
+bool Dso::KernelSymbolCallback(const KernelSymbol& kernel_symbol, Dso* dso) {
   if (IsKernelFunctionSymbol(kernel_symbol)) {
-    dso->symbols.insert(
-        std::unique_ptr<SymbolEntry>(new SymbolEntry(kernel_symbol.name, kernel_symbol.addr, 0)));
+    dso->InsertSymbol(Symbol(kernel_symbol.name, kernel_symbol.addr, 0));
   }
   return false;
 }
 
-static void VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso) {
+void Dso::VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol, Dso* dso) {
   if (elf_symbol.is_func) {
-    dso->symbols.insert(std::unique_ptr<SymbolEntry>(
-        new SymbolEntry(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len)));
+    dso->InsertSymbol(Symbol(elf_symbol.name, elf_symbol.vaddr, elf_symbol.len));
   }
 }
 
-static void FixupSymbolLength(DsoEntry* dso) {
-  SymbolEntry* prev_symbol = nullptr;
-  for (auto& symbol : dso->symbols) {
-    if (prev_symbol != nullptr && prev_symbol->len == 0) {
-      prev_symbol->len = symbol->addr - prev_symbol->addr;
-    }
-    prev_symbol = symbol.get();
-  }
-  if (prev_symbol != nullptr && prev_symbol->len == 0) {
-    prev_symbol->len = ULLONG_MAX - prev_symbol->addr;
-  }
-}
-
-bool DsoFactory::LoadKernel(DsoEntry* dso) {
+bool Dso::LoadKernel() {
   BuildId build_id = GetExpectedBuildId(DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID);
   if (!vmlinux_.empty()) {
     ParseSymbolsFromElfFile(vmlinux_, build_id,
-                            std::bind(VmlinuxSymbolCallback, std::placeholders::_1, dso));
+                            std::bind(VmlinuxSymbolCallback, std::placeholders::_1, this));
   } else {
     if (!build_id.IsEmpty()) {
       BuildId real_build_id;
@@ -199,17 +201,15 @@
       }
     }
     ProcessKernelSymbols("/proc/kallsyms",
-                         std::bind(&KernelSymbolCallback, std::placeholders::_1, dso));
+                         std::bind(&KernelSymbolCallback, std::placeholders::_1, this));
   }
-  FixupSymbolLength(dso);
   return true;
 }
 
-static void ParseSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso,
+void Dso::ElfFileSymbolCallback(const ElfFileSymbol& elf_symbol, Dso* dso,
                                 bool (*filter)(const ElfFileSymbol&)) {
   if (filter(elf_symbol)) {
-    dso->symbols.insert(std::unique_ptr<SymbolEntry>(
-        new SymbolEntry(elf_symbol.name, elf_symbol.start_in_file, elf_symbol.len)));
+    dso->InsertSymbol(Symbol(elf_symbol.name, elf_symbol.start_in_file, elf_symbol.len));
   }
 }
 
@@ -218,12 +218,11 @@
   return (elf_symbol.is_func && elf_symbol.is_in_text_section);
 }
 
-bool DsoFactory::LoadKernelModule(DsoEntry* dso) {
-  BuildId build_id = GetExpectedBuildId(dso->path);
+bool Dso::LoadKernelModule() {
+  BuildId build_id = GetExpectedBuildId(path_);
   ParseSymbolsFromElfFile(
-      symfs_dir_ + dso->path, build_id,
-      std::bind(ParseSymbolCallback, std::placeholders::_1, dso, SymbolFilterForKernelModule));
-  FixupSymbolLength(dso);
+      symfs_dir_ + path_, build_id,
+      std::bind(ElfFileSymbolCallback, std::placeholders::_1, this, SymbolFilterForKernelModule));
   return true;
 }
 
@@ -231,19 +230,27 @@
   return elf_symbol.is_func || (elf_symbol.is_label && elf_symbol.is_in_text_section);
 }
 
-bool DsoFactory::LoadElfFile(DsoEntry* dso) {
-  BuildId build_id = GetExpectedBuildId(dso->path);
+bool Dso::LoadElfFile() {
+  BuildId build_id = GetExpectedBuildId(path_);
   ParseSymbolsFromElfFile(
-      symfs_dir_ + dso->path, build_id,
-      std::bind(ParseSymbolCallback, std::placeholders::_1, dso, SymbolFilterForDso));
-  FixupSymbolLength(dso);
+      symfs_dir_ + path_, build_id,
+      std::bind(ElfFileSymbolCallback, std::placeholders::_1, this, SymbolFilterForDso));
   return true;
 }
 
-BuildId DsoFactory::GetExpectedBuildId(const std::string& filename) {
-  auto it = build_id_map_.find(filename);
-  if (it != build_id_map_.end()) {
-    return it->second;
+void Dso::InsertSymbol(const Symbol& symbol) {
+  symbols_.insert(std::unique_ptr<Symbol>(new Symbol(symbol)));
+}
+
+void Dso::FixupSymbolLength() {
+  Symbol* prev_symbol = nullptr;
+  for (auto& symbol : symbols_) {
+    if (prev_symbol != nullptr && prev_symbol->len == 0) {
+      prev_symbol->len = symbol->addr - prev_symbol->addr;
+    }
+    prev_symbol = symbol.get();
   }
-  return BuildId();
+  if (prev_symbol != nullptr && prev_symbol->len == 0) {
+    prev_symbol->len = std::numeric_limits<unsigned long long>::max() - prev_symbol->addr;
+  }
 }