From 15475e6ff1bc0273f666ef1bd6c2f7a50c4b948c Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Thu, 14 Jul 2016 13:26:19 -0700 Subject: [PATCH] simpleperf: show dso[+vaddr_in_file] for unknown symbols. It gives more information than just unknown symbols. Add --no-show-ip option to disable this additional detail. Bug: 29772268 Change-Id: Ie8067f95b5fdc65806044e229ee12095367d115a Test: run simpleperf_unit_test. --- simpleperf/cmd_report.cpp | 8 ++++++++ simpleperf/cmd_report_test.cpp | 9 +++++++++ simpleperf/dso.cpp | 6 ++++++ simpleperf/dso.h | 4 ++++ simpleperf/thread_tree.cpp | 23 ++++++++++++++++++----- simpleperf/thread_tree.h | 5 ++++- 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp index 464c57f9..cbdd14b1 100644 --- a/simpleperf/cmd_report.cpp +++ b/simpleperf/cmd_report.cpp @@ -280,6 +280,7 @@ class ReportCommand : public Command { "-i Specify path of record file, default is perf.data.\n" "-n Print the sample count for each item.\n" "--no-demangle Don't demangle symbol names.\n" +"--no-show-ip Don't show vaddr in file for unknown symbols.\n" "-o report_file_name Set report file name, default is stdout.\n" "--pids pid1,pid2,... Report only for selected pids.\n" "--sort key1,key2,... Select keys used to sort and print the report. The\n" @@ -379,6 +380,7 @@ bool ReportCommand::Run(const std::vector& args) { bool ReportCommand::ParseOptions(const std::vector& args) { bool demangle = true; + bool show_ip_for_unknown_symbol = true; std::string symfs_dir; std::string vmlinux; bool print_sample_count = false; @@ -428,6 +430,8 @@ bool ReportCommand::ParseOptions(const std::vector& args) { } else if (args[i] == "--no-demangle") { demangle = false; + } else if (args[i] == "--no-show-ip") { + show_ip_for_unknown_symbol = false; } else if (args[i] == "-o") { if (!NextArgumentOrError(args, &i)) { return false; @@ -488,6 +492,10 @@ bool ReportCommand::ParseOptions(const std::vector& args) { Dso::SetVmlinux(vmlinux); } + if (show_ip_for_unknown_symbol) { + thread_tree_.ShowIpForUnknownSymbol(); + } + SampleDisplayer displayer; SampleComparator comparator; diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp index 12811376..d6231bf9 100644 --- a/simpleperf/cmd_report_test.cpp +++ b/simpleperf/cmd_report_test.cpp @@ -340,6 +340,15 @@ TEST_F(ReportCommandTest, check_build_id) { testing::ExitedWithCode(0), "build id.*mismatch"); } +TEST_F(ReportCommandTest, no_show_ip_option) { + Report(PERF_DATA); + ASSERT_TRUE(success); + ASSERT_EQ(content.find("unknown"), std::string::npos); + Report(PERF_DATA, {"--no-show-ip"}); + ASSERT_TRUE(success); + ASSERT_NE(content.find("unknown"), std::string::npos); +} + #if defined(__linux__) static std::unique_ptr RecordCmd() { diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp index c10779a1..f31d4c4b 100644 --- a/simpleperf/dso.cpp +++ b/simpleperf/dso.cpp @@ -154,6 +154,12 @@ Dso::Dso(DsoType type, uint64_t id, const std::string& path) debug_file_path_ = path_in_symfs; } } + size_t pos = path.find_last_of("/\\"); + if (pos != std::string::npos) { + file_name_ = path.substr(pos + 1); + } else { + file_name_ = path; + } dso_count_++; } diff --git a/simpleperf/dso.h b/simpleperf/dso.h index a3525701..c381e6d2 100644 --- a/simpleperf/dso.h +++ b/simpleperf/dso.h @@ -86,6 +86,8 @@ struct Dso { const std::string& Path() const { return path_; } // Return the path containing symbol table and debug information. const std::string& GetDebugFilePath() const { return debug_file_path_; } + // Return the file name without directory info. + const std::string& FileName() const { return file_name_; } bool HasDumped() const { return has_dumped_; } @@ -122,6 +124,8 @@ struct Dso { // path of the shared library having symbol table and debug information // It is the same as path_, or has the same build id as path_. std::string debug_file_path_; + // File name of the shared library, got by removing directories in path_. + std::string file_name_; uint64_t min_vaddr_; std::set symbols_; bool is_loaded_; diff --git a/simpleperf/thread_tree.cpp b/simpleperf/thread_tree.cpp index f3291e5d..fafefa01 100644 --- a/simpleperf/thread_tree.cpp +++ b/simpleperf/thread_tree.cpp @@ -16,9 +16,12 @@ #include "thread_tree.h" +#include + #include #include +#include #include "environment.h" #include "perf_event.h" @@ -207,21 +210,31 @@ const MapEntry* ThreadTree::FindMap(const ThreadEntry* thread, uint64_t ip) { const Symbol* ThreadTree::FindSymbol(const MapEntry* map, uint64_t ip, uint64_t* pvaddr_in_file) { uint64_t vaddr_in_file; - if (map->dso == kernel_dso_.get()) { + Dso* dso = map->dso; + if (dso == kernel_dso_.get()) { vaddr_in_file = ip; } else { vaddr_in_file = ip - map->start_addr + map->dso->MinVirtualAddress(); } - const Symbol* symbol = map->dso->FindSymbol(vaddr_in_file); - if (symbol == nullptr && map->in_kernel && map->dso != kernel_dso_.get()) { + const Symbol* symbol = dso->FindSymbol(vaddr_in_file); + if (symbol == nullptr && map->in_kernel && dso != kernel_dso_.get()) { // It is in a kernel module, but we can't find the kernel module file, or // the kernel module file contains no symbol. Try finding the symbol in // /proc/kallsyms. vaddr_in_file = ip; - symbol = kernel_dso_->FindSymbol(vaddr_in_file); + dso = kernel_dso_.get(); + symbol = dso->FindSymbol(vaddr_in_file); } if (symbol == nullptr) { - symbol = &unknown_symbol_; + if (show_ip_for_unknown_symbol_) { + std::string name = android::base::StringPrintf( + "%s[+%" PRIx64 "]", dso->FileName().c_str(), vaddr_in_file); + dso->InsertSymbol(Symbol(name, vaddr_in_file, 1)); + symbol = dso->FindSymbol(vaddr_in_file); + CHECK(symbol != nullptr); + } else { + symbol = &unknown_symbol_; + } } if (pvaddr_in_file != nullptr) { *pvaddr_in_file = vaddr_in_file; diff --git a/simpleperf/thread_tree.h b/simpleperf/thread_tree.h index ae73cc7d..a8d3fa0d 100644 --- a/simpleperf/thread_tree.h +++ b/simpleperf/thread_tree.h @@ -68,7 +68,8 @@ struct ThreadEntry { class ThreadTree { public: ThreadTree() - : unknown_symbol_("unknown", 0, + : show_ip_for_unknown_symbol_(false), + unknown_symbol_("unknown", 0, std::numeric_limits::max()) { unknown_dso_ = Dso::CreateDso(DSO_ELF_FILE, "unknown"); unknown_map_ = MapEntry(0, std::numeric_limits::max(), @@ -92,6 +93,7 @@ class ThreadTree { const Symbol* FindKernelSymbol(uint64_t ip); const Symbol* UnknownSymbol() const { return &unknown_symbol_; } + void ShowIpForUnknownSymbol() { show_ip_for_unknown_symbol_ = true; } // Clear thread and map information, but keep loaded dso information. It saves // the time to reload dso information. void ClearThreadAndMap(); @@ -117,6 +119,7 @@ class ThreadTree { std::unordered_map> module_dso_tree_; std::unordered_map> user_dso_tree_; std::unique_ptr unknown_dso_; + bool show_ip_for_unknown_symbol_; Symbol unknown_symbol_; std::unordered_map dso_id_to_dso_map_; }; -- 2.11.0