OSDN Git Service

Simpleperf: support --vmlinux option in report command.
authorYabin Cui <yabinc@google.com>
Mon, 13 Jul 2015 23:23:13 +0000 (16:23 -0700)
committerYabin Cui <yabinc@google.com>
Tue, 14 Jul 2015 02:11:35 +0000 (19:11 -0700)
Bug: 22179177
Change-Id: I633da55c6bfcb106d69de9bda6b44bce24ffca8e

simpleperf/build_id.h
simpleperf/cmd_report.cpp
simpleperf/dso.cpp
simpleperf/dso.h
simpleperf/read_elf.cpp
simpleperf/read_elf.h
simpleperf/sample_tree.cpp

index 8bc0798..a244e7f 100644 (file)
@@ -44,7 +44,7 @@ class BuildId {
   std::string ToString() const {
     std::string s = "0x";
     for (size_t i = 0; i < BUILD_ID_SIZE; ++i) {
-      s += android::base::StringPrintf("0x%02x", data_[i]);
+      s += android::base::StringPrintf("%02x", data_[i]);
     }
     return s;
   }
index 4dc8126..ab5b083 100644 (file)
@@ -248,7 +248,9 @@ class ReportCommand : public Command {
             "                  include pid, tid, comm, dso, symbol, dso_from, dso_to, symbol_from\n"
             "                  symbol_to. dso_from, dso_to, symbol_from, symbol_to can only be\n"
             "                  used with -b option. Default keys are \"comm,pid,tid,dso,symbol\"\n"
-            "    --symfs <dir>  Look for files with symbols relative to this directory.\n"),
+            "    --symfs <dir> Look for files with symbols relative to this directory.\n"
+            "    --vmlinux <file>\n"
+            "                  Parse kernel symbols from <file>.\n"),
         record_filename_("perf.data"),
         use_branch_address_(false),
         accumulate_callchain_(false),
@@ -316,6 +318,7 @@ bool ReportCommand::Run(const std::vector<std::string>& args) {
 bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
   bool demangle = true;
   std::string symfs_dir;
+  std::string vmlinux;
   bool print_sample_count = false;
   std::vector<std::string> sort_keys = {"comm", "pid", "tid", "dso", "symbol"};
   for (size_t i = 0; i < args.size(); ++i) {
@@ -348,16 +351,24 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
         return false;
       }
       symfs_dir = args[i];
+    } else if (args[i] == "--vmlinux") {
+      if (!NextArgumentOrError(args, &i)) {
+        return false;
+      }
+      vmlinux = args[i];
     } else {
       ReportUnknownOption(args, i);
       return false;
     }
   }
 
-  DsoFactory::SetDemangle(demangle);
-  if (!DsoFactory::SetSymFsDir(symfs_dir)) {
+  DsoFactory::GetInstance()->SetDemangle(demangle);
+  if (!DsoFactory::GetInstance()->SetSymFsDir(symfs_dir)) {
     return false;
   }
+  if (!vmlinux.empty()) {
+    DsoFactory::GetInstance()->SetVmlinux(vmlinux);
+  }
 
   if (!accumulate_callchain_) {
     displayable_items_.push_back(
@@ -537,7 +548,7 @@ bool ReportCommand::ReadFeaturesFromRecordFile() {
   for (auto& r : records) {
     build_ids.push_back(std::make_pair(r.filename, r.build_id));
   }
-  DsoFactory::SetBuildIds(build_ids);
+  DsoFactory::GetInstance()->SetBuildIds(build_ids);
 
   std::string arch = record_file_reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH);
   if (!arch.empty()) {
index c75537c..ec8fbaa 100644 (file)
@@ -44,13 +44,17 @@ const SymbolEntry* DsoEntry::FindSymbol(uint64_t offset_in_dso) {
   return nullptr;
 }
 
-bool DsoFactory::demangle = true;
+DsoFactory* DsoFactory::GetInstance() {
+  static DsoFactory dso_factory;
+  return &dso_factory;
+}
 
-void DsoFactory::SetDemangle(bool demangle) {
-  DsoFactory::demangle = demangle;
+DsoFactory::DsoFactory() : demangle_(true) {
 }
 
-std::string DsoFactory::symfs_dir;
+void DsoFactory::SetDemangle(bool demangle) {
+  demangle_ = demangle;
+}
 
 bool DsoFactory::SetSymFsDir(const std::string& symfs_dir) {
   std::string dirname = symfs_dir;
@@ -66,11 +70,13 @@ bool DsoFactory::SetSymFsDir(const std::string& symfs_dir) {
       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 @@ void DsoFactory::SetBuildIds(const std::vector<std::pair<std::string, BuildId>>&
     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 @@ static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol, DsoEntry* ds
   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 @@ static void FixupSymbolLength(DsoEntry* dso) {
   }
 }
 
-// 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> DsoFactory::LoadKernelModule(const std::string& dso_pa
   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 @@ std::unique_ptr<DsoEntry> DsoFactory::LoadDso(const std::string& dso_path) {
   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 @@ std::unique_ptr<DsoEntry> DsoFactory::LoadDso(const std::string& dso_path) {
 }
 
 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();
index ea50a6d..ba105c1 100644 (file)
@@ -45,19 +45,23 @@ struct DsoEntry {
 
 class DsoFactory {
  public:
-  static void SetDemangle(bool demangle);
-  static bool SetSymFsDir(const std::string& symfs_dir);
-  static void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids);
-  static std::unique_ptr<DsoEntry> LoadKernel();
-  static std::unique_ptr<DsoEntry> LoadKernelModule(const std::string& dso_path);
-  static std::unique_ptr<DsoEntry> LoadDso(const std::string& dso_path);
+  static DsoFactory* GetInstance();
+  void SetDemangle(bool demangle);
+  bool SetSymFsDir(const std::string& symfs_dir);
+  void SetVmlinux(const std::string& vmlinux);
+  void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids);
+  std::unique_ptr<DsoEntry> LoadKernel();
+  std::unique_ptr<DsoEntry> LoadKernelModule(const std::string& dso_path);
+  std::unique_ptr<DsoEntry> LoadDso(const std::string& dso_path);
 
  private:
-  static BuildId GetExpectedBuildId(const std::string& filename);
+  DsoFactory();
+  BuildId GetExpectedBuildId(const std::string& filename);
 
-  static bool demangle;
-  static std::string symfs_dir;
-  static std::unordered_map<std::string, BuildId> build_id_map;
+  bool demangle_;
+  std::string symfs_dir_;
+  std::string vmlinux_;
+  std::unordered_map<std::string, BuildId> build_id_map_;
 };
 
 #endif  // SIMPLE_PERF_DSO_H_
index f703795..41120fe 100644 (file)
@@ -167,7 +167,7 @@ void ParseSymbolsFromELFFile(const llvm::object::ELFFile<ELFT>* elf,
     if (symbol.name.empty()) {
       continue;
     }
-
+    symbol.vaddr = elf_symbol.st_value;
     symbol.start_in_file = elf_symbol.st_value - shdr->sh_addr + shdr->sh_offset;
     if ((symbol.start_in_file & 1) != 0 && is_arm) {
       // Arm sets bit 0 to mark it as thumb code, remove the flag.
index c01bda7..439d6bc 100644 (file)
@@ -28,6 +28,7 @@ bool GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id);
 static const std::string linker_prefix = "__dl_";
 
 struct ElfFileSymbol {
+  uint64_t vaddr;
   uint64_t start_in_file;
   uint64_t len;
   bool is_func;
index 3f0e5b3..ce09246 100644 (file)
@@ -88,13 +88,13 @@ void SampleTree::AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff,
 DsoEntry* SampleTree::FindKernelDsoOrNew(const std::string& filename) {
   if (filename == DEFAULT_KERNEL_MMAP_NAME) {
     if (kernel_dso_ == nullptr) {
-      kernel_dso_ = DsoFactory::LoadKernel();
+      kernel_dso_ = DsoFactory::GetInstance()->LoadKernel();
     }
     return kernel_dso_.get();
   }
   auto it = module_dso_tree_.find(filename);
   if (it == module_dso_tree_.end()) {
-    module_dso_tree_[filename] = DsoFactory::LoadKernelModule(filename);
+    module_dso_tree_[filename] = DsoFactory::GetInstance()->LoadKernelModule(filename);
     it = module_dso_tree_.find(filename);
   }
   return it->second.get();
@@ -127,7 +127,7 @@ ThreadEntry* SampleTree::FindThreadOrNew(int pid, int tid) {
 DsoEntry* SampleTree::FindUserDsoOrNew(const std::string& filename) {
   auto it = user_dso_tree_.find(filename);
   if (it == user_dso_tree_.end()) {
-    user_dso_tree_[filename] = DsoFactory::LoadDso(filename);
+    user_dso_tree_[filename] = DsoFactory::GetInstance()->LoadDso(filename);
     it = user_dso_tree_.find(filename);
   }
   return it->second.get();