summaryrefslogtreecommitdiff
path: root/simpleperf/dso.cpp
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2018-04-09 14:06:08 -0700
committerYabin Cui <yabinc@google.com>2018-04-10 17:19:36 -0700
commit40b70ffb58d830edefad2c82a9d33e1c7ce91138 (patch)
treed71c951e6f27018db90a0b0edafdb1632e039aab /simpleperf/dso.cpp
parent5eb57e19b83b467784d0bcae4f7ff1fe14ce4a7b (diff)
downloadextras-40b70ffb58d830edefad2c82a9d33e1c7ce91138.tar.gz
simpleperf: Improve the way downloading native libs on device.
Apks are usually built with stripped native libs, so app_profiler.py supports downloading native libs on device, and pass the native lib directory to simpleperf via --symfs option. However, it has below problems: 1. It needs to download native libs each time profiling. 2. It needs to wait until the app starts and read the /proc/pid/maps to know which native libs are needed. This patch solves the problems as below: 1. When app_profiler.py downloads native libs, it will write a build_id_list file in the native lib directory, which is a map from build_id to debug library path. 2. Simpleperf searchs build_id_list in the native lib directory, and uses build_id to find the debug files it needs. 3. Before downloading libs, app_profiler.py checks build_id_list to find libs available on device, thus avoids downloading libs more than once. Add tests in simpleperf_unit_test and test.py. Update demos to Android Studio 3.2. In profiling.gradle, remove the logic preventing stripping native libs in apk to test this patch. Another reason to remove it is because I found it affects release builds. Bug: http://b/69165587 Test: run simpleperf_unit_test && python test.py. Change-Id: I8ecf7ba2c0f58c131c261c1b4546f4916aea1f82
Diffstat (limited to 'simpleperf/dso.cpp')
-rw-r--r--simpleperf/dso.cpp159
1 files changed, 108 insertions, 51 deletions
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index f3e9b2ce..396bb352 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -25,6 +25,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include "environment.h"
#include "read_apk.h"
@@ -32,6 +33,91 @@
#include "read_elf.h"
#include "utils.h"
+namespace simpleperf_dso_impl {
+
+void DebugElfFileFinder::Reset() {
+ vdso_64bit_.clear();
+ vdso_32bit_.clear();
+ symfs_dir_.clear();
+ build_id_to_file_map_.clear();
+}
+
+bool DebugElfFileFinder::SetSymFsDir(const std::string& symfs_dir) {
+ std::string dirname = symfs_dir;
+ if (!dirname.empty()) {
+ if (dirname.back() != '/') {
+ dirname.push_back('/');
+ }
+ if (!IsDir(symfs_dir)) {
+ LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir << "'";
+ return false;
+ }
+ }
+ symfs_dir_ = dirname;
+ build_id_to_file_map_.clear();
+ std::string build_id_list_file = symfs_dir_ + "build_id_list";
+ std::string build_id_list;
+ if (android::base::ReadFileToString(build_id_list_file, &build_id_list)) {
+ for (auto& line : android::base::Split(build_id_list, "\n")) {
+ std::vector<std::string> items = android::base::Split(line, "=");
+ if (items.size() == 2u) {
+ build_id_to_file_map_[items[0]] = items[1];
+ }
+ }
+ }
+ return true;
+}
+
+void DebugElfFileFinder::SetVdsoFile(const std::string& vdso_file, bool is_64bit) {
+ if (is_64bit) {
+ vdso_64bit_ = vdso_file;
+ } else {
+ vdso_32bit_ = vdso_file;
+ }
+}
+
+std::string DebugElfFileFinder::FindDebugFile(const std::string& dso_path, bool force_64bit,
+ BuildId& build_id) {
+ if (dso_path == "[vdso]") {
+ if (force_64bit && !vdso_64bit_.empty()) {
+ return vdso_64bit_;
+ } else if (!force_64bit && !vdso_32bit_.empty()) {
+ return vdso_32bit_;
+ }
+ } else if (!symfs_dir_.empty()) {
+ if (!build_id.IsEmpty() || GetBuildIdFromDsoPath(dso_path, &build_id)) {
+ std::string result;
+ auto check_path = [&](const std::string& path) {
+ BuildId debug_build_id;
+ if (GetBuildIdFromDsoPath(path, &debug_build_id) && debug_build_id == build_id) {
+ result = path;
+ return true;
+ }
+ return false;
+ };
+
+ // 1. Try build_id_to_file_map.
+ auto it = build_id_to_file_map_.find(build_id.ToString());
+ if (it != build_id_to_file_map_.end()) {
+ if (check_path(symfs_dir_ + it->second)) {
+ return result;
+ }
+ }
+ // 2. Try concatenating symfs_dir and dso_path.
+ if (check_path(symfs_dir_ + dso_path)) {
+ return result;
+ }
+ // 3. Try concatenating /usr/lib/debug and dso_path.
+ // Linux host can store debug shared libraries in /usr/lib/debug.
+ if (check_path("/usr/lib/debug" + dso_path)) {
+ return result;
+ }
+ }
+ }
+ return dso_path;
+}
+} // namespace simpleperf_dso_imp
+
static OneTimeFreeAllocator symbol_name_allocator;
Symbol::Symbol(const std::string& name, uint64_t addr, uint64_t len)
@@ -55,15 +141,13 @@ const char* Symbol::DemangledName() const {
}
bool Dso::demangle_ = true;
-std::string Dso::symfs_dir_;
std::string Dso::vmlinux_;
std::string Dso::kallsyms_;
bool Dso::read_kernel_symbols_from_proc_;
std::unordered_map<std::string, BuildId> Dso::build_id_map_;
size_t Dso::dso_count_;
uint32_t Dso::g_dump_id_;
-std::string Dso::vdso_64bit_;
-std::string Dso::vdso_32bit_;
+simpleperf_dso_impl::DebugElfFileFinder Dso::debug_elf_file_finder_;
void Dso::SetDemangle(bool demangle) { demangle_ = demangle; }
@@ -96,18 +180,7 @@ std::string Dso::Demangle(const std::string& name) {
}
bool Dso::SetSymFsDir(const std::string& symfs_dir) {
- std::string dirname = symfs_dir;
- if (!dirname.empty()) {
- if (dirname.back() != '/') {
- dirname.push_back('/');
- }
- if (!IsDir(symfs_dir)) {
- LOG(ERROR) << "Invalid symfs_dir '" << symfs_dir << "'";
- return false;
- }
- }
- symfs_dir_ = dirname;
- return true;
+ return debug_elf_file_finder_.SetSymFsDir(symfs_dir);
}
void Dso::SetVmlinux(const std::string& vmlinux) { vmlinux_ = vmlinux; }
@@ -124,11 +197,7 @@ void Dso::SetBuildIds(
}
void Dso::SetVdsoFile(const std::string& vdso_file, bool is_64bit) {
- if (is_64bit) {
- vdso_64bit_ = vdso_file;
- } else {
- vdso_32bit_ = vdso_file;
- }
+ debug_elf_file_finder_.SetVdsoFile(vdso_file, is_64bit);
}
BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) {
@@ -165,12 +234,12 @@ Dso::~Dso() {
// Clean up global variables when no longer used.
symbol_name_allocator.Clear();
demangle_ = true;
- symfs_dir_.clear();
vmlinux_.clear();
kallsyms_.clear();
read_kernel_symbols_from_proc_ = false;
build_id_map_.clear();
g_dump_id_ = 0;
+ debug_elf_file_finder_.Reset();
}
}
@@ -402,41 +471,18 @@ class KernelModuleDso : public Dso {
std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_path,
bool force_64bit) {
- auto find_debug_file = [&]() {
- // Check if file matching path_ exists in symfs directory before using it as
- // debug_file_path_.
- if (!symfs_dir_.empty()) {
- std::string path_in_symfs = symfs_dir_ + dso_path;
- std::tuple<bool, std::string, std::string> tuple = SplitUrlInApk(path_in_symfs);
- std::string file_path = std::get<0>(tuple) ? std::get<1>(tuple) : path_in_symfs;
- if (IsRegularFile(file_path)) {
- return path_in_symfs;
- }
- } else if (dso_path == "[vdso]") {
- if (force_64bit && !vdso_64bit_.empty()) {
- return vdso_64bit_;
- } else if (!force_64bit && !vdso_32bit_.empty()) {
- return vdso_32bit_;
- }
- } else if (dso_type == DSO_ELF_FILE) {
- // Linux host can store debug shared libraries in /usr/lib/debug.
- std::string path = "/usr/lib/debug" + dso_path;
- if (IsRegularFile(path)) {
- return path;
- }
- }
- return dso_path;
- };
-
switch (dso_type) {
- case DSO_ELF_FILE:
- return std::unique_ptr<Dso>(new ElfDso(dso_path, find_debug_file()));
+ case DSO_ELF_FILE: {
+ BuildId build_id = FindExpectedBuildIdForPath(dso_path);
+ return std::unique_ptr<Dso>(new ElfDso(dso_path,
+ debug_elf_file_finder_.FindDebugFile(dso_path, force_64bit, build_id)));
+ }
case DSO_KERNEL:
return std::unique_ptr<Dso>(new KernelDso(dso_path, dso_path));
case DSO_KERNEL_MODULE:
- return std::unique_ptr<Dso>(new KernelModuleDso(dso_path, find_debug_file()));
+ return std::unique_ptr<Dso>(new KernelModuleDso(dso_path, dso_path));
case DSO_DEX_FILE:
- return std::unique_ptr<Dso>(new DexFileDso(dso_path, find_debug_file()));
+ return std::unique_ptr<Dso>(new DexFileDso(dso_path, dso_path));
default:
LOG(FATAL) << "Unexpected dso_type " << static_cast<int>(dso_type);
}
@@ -474,3 +520,14 @@ const char* DsoTypeToString(DsoType dso_type) {
return "unknown";
}
}
+
+bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id) {
+ auto tuple = SplitUrlInApk(dso_path);
+ ElfStatus result;
+ if (std::get<0>(tuple)) {
+ result = GetBuildIdFromApkFile(std::get<1>(tuple), std::get<2>(tuple), build_id);
+ } else {
+ result = GetBuildIdFromElfFile(dso_path, build_id);
+ }
+ return result == ElfStatus::NO_ERROR;
+}