Simpleperf: support --vmlinux option in report command.

Bug: 22179177
Change-Id: I633da55c6bfcb106d69de9bda6b44bce24ffca8e
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index c75537c..ec8fbaa 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -44,13 +44,17 @@
   return nullptr;
 }
 
-bool DsoFactory::demangle = true;
-
-void DsoFactory::SetDemangle(bool demangle) {
-  DsoFactory::demangle = demangle;
+DsoFactory* DsoFactory::GetInstance() {
+  static DsoFactory dso_factory;
+  return &dso_factory;
 }
 
-std::string DsoFactory::symfs_dir;
+DsoFactory::DsoFactory() : demangle_(true) {
+}
+
+void DsoFactory::SetDemangle(bool demangle) {
+  demangle_ = demangle;
+}
 
 bool DsoFactory::SetSymFsDir(const std::string& symfs_dir) {
   std::string dirname = symfs_dir;
@@ -66,11 +70,13 @@
       return false;
     }
   }
-  DsoFactory::symfs_dir = dirname;
+  symfs_dir_ = dirname;
   return true;
 }
 
-std::unordered_map<std::string, BuildId> DsoFactory::build_id_map;
+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;
@@ -78,7 +84,7 @@
     LOG(DEBUG) << "build_id_map: " << pair.first << ", " << pair.second.ToString();
     map.insert(pair);
   }
-  build_id_map = std::move(map);
+  build_id_map_ = std::move(map);
 }
 
 static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
@@ -97,6 +103,17 @@
   return false;
 }
 
+static void VmlinuxSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso) {
+  if (elf_symbol.is_func) {
+    SymbolEntry* symbol = new SymbolEntry{
+        elf_symbol.name,   // name
+        elf_symbol.vaddr,  // addr
+        elf_symbol.len,    // len
+    };
+    dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
+  }
+}
+
 static void FixupSymbolLength(DsoEntry* dso) {
   SymbolEntry* prev_symbol = nullptr;
   for (auto& symbol : dso->symbols) {
@@ -110,19 +127,23 @@
   }
 }
 
-// TODO: Fix the way to get kernel symbols. See b/22179177.
 std::unique_ptr<DsoEntry> DsoFactory::LoadKernel() {
   std::unique_ptr<DsoEntry> dso(new DsoEntry);
   dso->path = "[kernel.kallsyms]";
   BuildId build_id = GetExpectedBuildId(DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID);
-  BuildId real_build_id;
-  GetKernelBuildId(&real_build_id);
-  bool match = (build_id == real_build_id);
-  LOG(DEBUG) << "check kernel build id (" << (match ? "match" : "mismatch") << "): expected "
-             << build_id.ToString() << ", real " << real_build_id.ToString();
-  if (match) {
-    ProcessKernelSymbols("/proc/kallsyms",
-                         std::bind(&KernelSymbolCallback, std::placeholders::_1, dso.get()));
+  if (!vmlinux_.empty()) {
+    ParseSymbolsFromElfFile(vmlinux_, build_id,
+                            std::bind(VmlinuxSymbolCallback, std::placeholders::_1, dso.get()));
+  } else {
+    BuildId real_build_id;
+    GetKernelBuildId(&real_build_id);
+    bool match = (build_id == real_build_id);
+    LOG(DEBUG) << "check kernel build id (" << (match ? "match" : "mismatch") << "): expected "
+               << build_id.ToString() << ", real " << real_build_id.ToString();
+    if (match) {
+      ProcessKernelSymbols("/proc/kallsyms",
+                           std::bind(&KernelSymbolCallback, std::placeholders::_1, dso.get()));
+    }
   }
   FixupSymbolLength(dso.get());
   return dso;
@@ -149,7 +170,7 @@
   std::unique_ptr<DsoEntry> dso(new DsoEntry);
   dso->path = dso_path;
   BuildId build_id = GetExpectedBuildId(dso_path);
-  ParseSymbolsFromElfFile(symfs_dir + dso_path, build_id,
+  ParseSymbolsFromElfFile(symfs_dir_ + dso_path, build_id,
                           std::bind(ParseSymbolCallback, std::placeholders::_1, dso.get(),
                                     SymbolFilterForKernelModule));
   FixupSymbolLength(dso.get());
@@ -188,9 +209,9 @@
   dso->path = dso_path;
   BuildId build_id = GetExpectedBuildId(dso_path);
   ParseSymbolsFromElfFile(
-      symfs_dir + dso_path, build_id,
+      symfs_dir_ + dso_path, build_id,
       std::bind(ParseSymbolCallback, std::placeholders::_1, dso.get(), SymbolFilterForDso));
-  if (demangle) {
+  if (demangle_) {
     for (auto& symbol : dso->symbols) {
       DemangleInPlace(&symbol->name);
     }
@@ -200,8 +221,8 @@
 }
 
 BuildId DsoFactory::GetExpectedBuildId(const std::string& filename) {
-  auto it = build_id_map.find(filename);
-  if (it != build_id_map.end()) {
+  auto it = build_id_map_.find(filename);
+  if (it != build_id_map_.end()) {
     return it->second;
   }
   return BuildId();