summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2020-08-27 19:54:44 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-08-27 19:54:44 +0000
commit3b2fa33a196f41991f55f2f54e0a2de704e1e734 (patch)
tree453a6513547cb9eb5d3d428fdb91ab737c63ea74
parent416ff0a479ba926c72bc19a393ca14f3e8ead909 (diff)
parentfc7c7d73f38d2008ef4e7a0ef63aaa33a905a3d3 (diff)
downloadextras-3b2fa33a196f41991f55f2f54e0a2de704e1e734.tar.gz
Merge "simpleperf: add perf symbol map dso + test" am: fc7c7d73f3
Original change: https://android-review.googlesource.com/c/platform/system/extras/+/1413508 Change-Id: I0a99dd584acc4bd34689e16f1f6d37f244c50d8c
-rw-r--r--simpleperf/dso.cpp14
-rw-r--r--simpleperf/dso.h1
-rw-r--r--simpleperf/dso_test.cpp8
-rw-r--r--simpleperf/thread_tree.cpp51
-rw-r--r--simpleperf/thread_tree.h8
-rw-r--r--simpleperf/thread_tree_test.cpp22
-rw-r--r--simpleperf/utils.h6
7 files changed, 109 insertions, 1 deletions
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index f4239a60..efe65721 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -691,6 +691,16 @@ class KernelModuleDso : public Dso {
}
};
+class SymbolMapFileDso : public Dso {
+ public:
+ SymbolMapFileDso(const std::string& path) : Dso(DSO_SYMBOL_MAP_FILE, path, path) {}
+
+ uint64_t IpToVaddrInFile(uint64_t ip, uint64_t, uint64_t) override { return ip; }
+
+ protected:
+ std::vector<Symbol> LoadSymbols() override { return {}; }
+};
+
class UnknownDso : public Dso {
public:
UnknownDso(const std::string& path) : Dso(DSO_UNKNOWN_FILE, path, path) {}
@@ -722,6 +732,8 @@ std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_pat
}
case DSO_DEX_FILE:
return std::unique_ptr<Dso>(new DexFileDso(dso_path, dso_path));
+ case DSO_SYMBOL_MAP_FILE:
+ return std::unique_ptr<Dso>(new SymbolMapFileDso(dso_path));
case DSO_UNKNOWN_FILE:
return std::unique_ptr<Dso>(new UnknownDso(dso_path));
default:
@@ -745,6 +757,8 @@ const char* DsoTypeToString(DsoType dso_type) {
return "dso_elf_file";
case DSO_DEX_FILE:
return "dso_dex_file";
+ case DSO_SYMBOL_MAP_FILE:
+ return "dso_symbol_map_file";
default:
return "unknown";
}
diff --git a/simpleperf/dso.h b/simpleperf/dso.h
index 6afeff41..aa7ca048 100644
--- a/simpleperf/dso.h
+++ b/simpleperf/dso.h
@@ -106,6 +106,7 @@ enum DsoType {
DSO_KERNEL_MODULE,
DSO_ELF_FILE,
DSO_DEX_FILE, // For files containing dex files, like .vdex files.
+ DSO_SYMBOL_MAP_FILE,
DSO_UNKNOWN_FILE,
};
diff --git a/simpleperf/dso_test.cpp b/simpleperf/dso_test.cpp
index 5d405622..566d76b9 100644
--- a/simpleperf/dso_test.cpp
+++ b/simpleperf/dso_test.cpp
@@ -219,3 +219,11 @@ TEST(dso, kernel_module) {
std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_KERNEL_MODULE, ELF_FILE, false);
ASSERT_EQ(dso->GetDebugFilePath(), GetTestData(ELF_FILE));
}
+
+TEST(dso, symbol_map_file) {
+ auto dso = Dso::CreateDso(DSO_SYMBOL_MAP_FILE, "perf-123.map");
+ ASSERT_TRUE(dso);
+ ASSERT_EQ(DSO_SYMBOL_MAP_FILE, dso->type());
+ ASSERT_EQ(0x12345678, dso->IpToVaddrInFile(0x12345678, 0x0, 0x0));
+ ASSERT_EQ(0x12345678, dso->IpToVaddrInFile(0x12345678, 0xe9201000, 0xa5000));
+}
diff --git a/simpleperf/thread_tree.cpp b/simpleperf/thread_tree.cpp
index 6babf8cc..10cc018b 100644
--- a/simpleperf/thread_tree.cpp
+++ b/simpleperf/thread_tree.cpp
@@ -25,6 +25,7 @@
#include "perf_event.h"
#include "record.h"
+#include "utils.h"
namespace simpleperf {
@@ -131,6 +132,35 @@ void ThreadTree::AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t le
InsertMap(*thread->maps, MapEntry(start_addr, len, pgoff, dso, false, flags));
}
+void ThreadTree::AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso) {
+ const uint64_t page_size = GetPageSize();
+
+ auto maps = thread->maps;
+
+ uint64_t map_start = 0;
+ uint64_t map_end = 0;
+
+ // Dso symbols are sorted by address. Walk and calculate containing pages.
+ for (const auto& sym : dso->GetSymbols()) {
+ uint64_t sym_map_start = AlignDown(sym.addr, page_size);
+ uint64_t sym_map_end = Align(sym.addr + sym.len, page_size);
+
+ if (map_end < sym_map_start) {
+ if (map_start < map_end) {
+ InsertMap(*maps, MapEntry(map_start, map_end - map_start, map_start, dso, false, 0));
+ }
+ map_start = sym_map_start;
+ }
+ if (map_end < sym_map_end) {
+ map_end = sym_map_end;
+ }
+ }
+
+ if (map_start < map_end) {
+ InsertMap(*maps, MapEntry(map_start, map_end - map_start, map_start, dso, false, 0));
+ }
+}
+
Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename, uint64_t start_addr,
DsoType dso_type) {
auto it = user_dso_tree_.find(filename);
@@ -144,6 +174,27 @@ Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename, uint64_t start_ad
return it->second.get();
}
+namespace {
+
+// Real map file path depends on where the process can create files.
+// For example, app can create files only in its data directory.
+// Use normalized name inherited from pid instead.
+std::string GetSymbolMapDsoName(int pid) {
+ return android::base::StringPrintf("perf-%d.map", pid);
+}
+
+} // namespace
+
+void ThreadTree::AddSymbolsForProcess(int pid, std::vector<Symbol>* symbols) {
+ auto name = GetSymbolMapDsoName(pid);
+
+ auto dso = FindUserDsoOrNew(name, 0, DSO_SYMBOL_MAP_FILE);
+ dso->SetSymbols(symbols);
+
+ auto thread = FindThreadOrNew(pid, pid);
+ AddThreadMapsForDsoSymbols(thread, dso);
+}
+
const MapEntry* ThreadTree::AllocateMap(const MapEntry& entry) {
map_storage_.emplace_back(new MapEntry(entry));
return map_storage_.back().get();
diff --git a/simpleperf/thread_tree.h b/simpleperf/thread_tree.h
index 76d3403d..a90c4951 100644
--- a/simpleperf/thread_tree.h
+++ b/simpleperf/thread_tree.h
@@ -113,6 +113,11 @@ class ThreadTree {
const MapSet& GetKernelMaps() { return kernel_maps_; }
void AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len,
uint64_t pgoff, const std::string& filename, uint32_t flags = 0);
+
+ // Add process symbols that do not correspond to any real dso.
+ // For example, these might be symbols generated by a JIT.
+ void AddSymbolsForProcess(int pid, std::vector<Symbol>* symbols);
+
const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip,
bool in_kernel);
// Find map for an ip address when we don't know whether it is in kernel.
@@ -150,6 +155,9 @@ class ThreadTree {
const MapEntry* AllocateMap(const MapEntry& entry);
void InsertMap(MapSet& maps, const MapEntry& entry);
+ // Add thread maps to cover symbols in dso.
+ void AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso);
+
std::unordered_map<int, std::unique_ptr<ThreadEntry>> thread_tree_;
std::vector<std::unique_ptr<std::string>> thread_comm_storage_;
diff --git a/simpleperf/thread_tree_test.cpp b/simpleperf/thread_tree_test.cpp
index d00ebcb9..c75e98c4 100644
--- a/simpleperf/thread_tree_test.cpp
+++ b/simpleperf/thread_tree_test.cpp
@@ -18,6 +18,8 @@
#include <gtest/gtest.h>
+#include "read_symbol_map.h"
+
using namespace simpleperf;
class ThreadTreeTest : public ::testing::Test {
@@ -64,6 +66,12 @@ class ThreadTreeTest : public ::testing::Test {
}
}
+ const Symbol* FindSymbol(int pid, int tid, uint64_t ip, bool in_kernel = false) {
+ auto thread = thread_tree_.FindThreadOrNew(pid, tid);
+ auto map = thread_tree_.FindMap(thread, ip, in_kernel);
+ return thread_tree_.FindSymbol(map, ip, nullptr, nullptr);
+ }
+
std::vector<std::string> expected_names_;
ThreadTree thread_tree_;
};
@@ -120,3 +128,17 @@ TEST_F(ThreadTreeTest, reused_tid_without_thread_exit) {
thread_tree_.ForkThread(1, 2, 1, 1);
thread_tree_.ForkThread(2, 2, 1, 1);
}
+
+TEST_F(ThreadTreeTest, add_symbols_for_process) {
+ std::string symbol_map("0x2000 0x20 two\n"
+ "0x1000 0x10 one\n"
+ "0x3000 0x30 three\n");
+
+ auto symbols = ReadSymbolMapFromString(symbol_map);
+
+ thread_tree_.AddSymbolsForProcess(1, &symbols);
+
+ ASSERT_STREQ("one", FindSymbol(1, 1, 0x1000)->Name());
+ ASSERT_STREQ("two", FindSymbol(1, 1, 0x2010)->Name());
+ ASSERT_STREQ("three", FindSymbol(1, 1, 0x302f)->Name());
+}
diff --git a/simpleperf/utils.h b/simpleperf/utils.h
index 6bb51d3c..db00d23a 100644
--- a/simpleperf/utils.h
+++ b/simpleperf/utils.h
@@ -30,8 +30,12 @@
#include <android-base/unique_fd.h>
#include <ziparchive/zip_archive.h>
+static inline uint64_t AlignDown(uint64_t value, uint64_t alignment) {
+ return value & ~(alignment - 1);
+}
+
static inline uint64_t Align(uint64_t value, uint64_t alignment) {
- return (value + alignment - 1) & ~(alignment - 1);
+ return AlignDown(value + alignment - 1, alignment);
}
#ifdef _WIN32