summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2021-08-17 16:47:32 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-08-17 16:47:32 +0000
commit34b6e1840f7eea71a4d0ee02dc889d02918a8e80 (patch)
tree0d0c3a61f0e55492ebc85109b71980cd24f292f8
parent84c6227af6f64056bc84b64a1ae314ea23a840c7 (diff)
parent1e16b20c973bf8ac7fa5207bab3cfff3fc1249c3 (diff)
downloadextras-34b6e1840f7eea71a4d0ee02dc889d02918a8e80.tar.gz
Merge "simpleperf: support JIT method name with signature."
-rw-r--r--simpleperf/dso.cpp14
-rw-r--r--simpleperf/dso.h2
-rw-r--r--simpleperf/dso_test.cpp7
-rw-r--r--simpleperf/report_utils.cpp12
-rw-r--r--simpleperf/report_utils_test.cpp142
5 files changed, 138 insertions, 39 deletions
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 8d002388..db70a879 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -229,6 +229,20 @@ void Symbol::SetDemangledName(std::string_view name) const {
}
}
+std::string_view Symbol::FunctionNameForJITSymbol() const {
+ // Name with signature is like "void ctep.v(cteo, ctgc, ctbn)".
+ std::string_view name = DemangledName();
+ auto brace_pos = name.find('(');
+ if (brace_pos != name.npos) {
+ name = name.substr(0, brace_pos);
+ auto space_pos = name.rfind(' ');
+ if (space_pos != name.npos) {
+ name = name.substr(space_pos + 1);
+ }
+ }
+ return name;
+}
+
static bool CompareSymbolToAddr(const Symbol& s, uint64_t addr) {
return s.addr < addr;
}
diff --git a/simpleperf/dso.h b/simpleperf/dso.h
index 4bac3e0d..00a08040 100644
--- a/simpleperf/dso.h
+++ b/simpleperf/dso.h
@@ -66,6 +66,8 @@ struct Symbol {
const char* DemangledName() const;
void SetDemangledName(std::string_view name) const;
+ // Return function name without signature.
+ std::string_view FunctionNameForJITSymbol() const;
bool HasDumpId() const { return dump_id_ != UINT_MAX; }
diff --git a/simpleperf/dso_test.cpp b/simpleperf/dso_test.cpp
index 02958ce6..9d1cc3fd 100644
--- a/simpleperf/dso_test.cpp
+++ b/simpleperf/dso_test.cpp
@@ -301,3 +301,10 @@ TEST(dso, symbol_map_file) {
ASSERT_EQ(0x12345678, dso->IpToVaddrInFile(0x12345678, 0x0, 0x0));
ASSERT_EQ(0x12345678, dso->IpToVaddrInFile(0x12345678, 0xe9201000, 0xa5000));
}
+
+TEST(dso, FunctionNameForJITSymbol) {
+ Symbol symbol = Symbol("void ctep.v(cteo, ctgc, ctbn)", 0x0, 0x1);
+ ASSERT_EQ(symbol.FunctionNameForJITSymbol(), "ctep.v");
+ symbol = Symbol("ctep.v", 0x0, 0x1);
+ ASSERT_EQ(symbol.FunctionNameForJITSymbol(), "ctep.v");
+}
diff --git a/simpleperf/report_utils.cpp b/simpleperf/report_utils.cpp
index a9468006..ccaaa69b 100644
--- a/simpleperf/report_utils.cpp
+++ b/simpleperf/report_utils.cpp
@@ -172,11 +172,12 @@ void CallChainReportBuilder::ConvertJITFrame(std::vector<CallChainReportEntry>&
CollectJavaMethods();
for (size_t i = 0; i < callchain.size();) {
auto& entry = callchain[i];
- if (entry.dso->IsForJavaMethod() && entry.dso->type() == DSO_ELF_FILE) {
+ if (entry.execution_type == CallChainExecutionType::JIT_JVM_METHOD) {
// This is a JIT java method, merge it with the interpreted java method having the same
// name if possible. Otherwise, merge it with other JIT java methods having the same name
// by assigning a common dso_name.
- if (auto it = java_method_map_.find(entry.symbol->Name()); it != java_method_map_.end()) {
+ if (auto it = java_method_map_.find(std::string(entry.symbol->FunctionNameForJITSymbol()));
+ it != java_method_map_.end()) {
entry.dso = it->second.dso;
entry.symbol = it->second.symbol;
// Not enough info to map an offset in a JIT method to an offset in a dex file. So just
@@ -220,7 +221,12 @@ void CallChainReportBuilder::DeObfuscateJavaMethods(std::vector<CallChainReportE
entry.execution_type != CallChainExecutionType::INTERPRETED_JVM_METHOD) {
continue;
}
- std::string_view name = entry.symbol->DemangledName();
+ std::string_view name;
+ if (entry.execution_type == CallChainExecutionType::JIT_JVM_METHOD) {
+ name = entry.symbol->FunctionNameForJITSymbol();
+ } else {
+ name = entry.symbol->DemangledName();
+ }
if (auto split_pos = name.rfind('.'); split_pos != name.npos) {
std::string obfuscated_classname(name.substr(0, split_pos));
if (auto it = proguard_class_map_.find(obfuscated_classname);
diff --git a/simpleperf/report_utils_test.cpp b/simpleperf/report_utils_test.cpp
index cc246357..8def39ee 100644
--- a/simpleperf/report_utils_test.cpp
+++ b/simpleperf/report_utils_test.cpp
@@ -35,48 +35,36 @@ class CallChainReportBuilderTest : public testing::Test {
thread = thread_tree.FindThread(1);
// Add symbol info for the native library.
- FileFeature file;
- file.path = fake_native_lib_path;
- file.type = DSO_ELF_FILE;
- file.min_vaddr = file.file_offset_of_min_vaddr = 0;
- file.symbols = {
- Symbol("native_func1", 0x0, 0x100),
- Symbol("art_jni_trampoline", 0x100, 0x100),
- };
- thread_tree.AddDsoInfo(file);
+ SetSymbols(fake_native_lib_path, DSO_ELF_FILE,
+ {
+ Symbol("native_func1", 0x0, 0x100),
+ Symbol("art_jni_trampoline", 0x100, 0x100),
+ });
// Add symbol info for the interpreter library.
- file.path = fake_interpreter_path;
- file.type = DSO_ELF_FILE;
- file.min_vaddr = file.file_offset_of_min_vaddr = 0;
- file.symbols = {
- Symbol("art_func1", 0x0, 0x100),
- Symbol("art_func2", 0x100, 0x100),
- Symbol("_ZN3artL13Method_invokeEP7_JNIEnvP8_jobjectS3_P13_jobjectArray", 0x200, 0x100),
- };
- thread_tree.AddDsoInfo(file);
+ SetSymbols(
+ fake_interpreter_path, DSO_ELF_FILE,
+ {
+ Symbol("art_func1", 0x0, 0x100),
+ Symbol("art_func2", 0x100, 0x100),
+ Symbol("_ZN3artL13Method_invokeEP7_JNIEnvP8_jobjectS3_P13_jobjectArray", 0x200, 0x100),
+ });
// Add symbol info for the dex file.
- file.path = fake_dex_file_path;
- file.type = DSO_DEX_FILE;
- file.min_vaddr = file.file_offset_of_min_vaddr = 0;
- file.symbols = {
- Symbol("java_method1", 0x0, 0x100),
- Symbol("java_method2", 0x100, 0x100),
- Symbol("obfuscated_class.obfuscated_java_method", 0x200, 0x100),
- };
- thread_tree.AddDsoInfo(file);
+ SetSymbols(fake_dex_file_path, DSO_DEX_FILE,
+ {
+ Symbol("java_method1", 0x0, 0x100),
+ Symbol("java_method2", 0x100, 0x100),
+ Symbol("obfuscated_class.obfuscated_java_method", 0x200, 0x100),
+ });
// Add symbol info for the jit cache.
- file.path = fake_jit_cache_path;
- file.type = DSO_ELF_FILE;
- file.min_vaddr = file.file_offset_of_min_vaddr = 0;
- file.symbols = {
- Symbol("java_method2", 0x3000, 0x100),
- Symbol("java_method3", 0x3100, 0x100),
- Symbol("obfuscated_class.obfuscated_java_method2", 0x3200, 0x100),
- };
- thread_tree.AddDsoInfo(file);
+ SetSymbols(fake_jit_cache_path, DSO_ELF_FILE,
+ {
+ Symbol("java_method2", 0x3000, 0x100),
+ Symbol("java_method3", 0x3100, 0x100),
+ Symbol("obfuscated_class.obfuscated_java_method2", 0x3200, 0x100),
+ });
// Add map layout for libraries used in the thread:
// 0x0000 - 0x1000 is mapped to the native library.
@@ -90,6 +78,15 @@ class CallChainReportBuilderTest : public testing::Test {
map_flags::PROT_JIT_SYMFILE_MAP);
}
+ void SetSymbols(const std::string& path, DsoType dso_type, const std::vector<Symbol>& symbols) {
+ FileFeature file;
+ file.path = path;
+ file.type = dso_type;
+ file.min_vaddr = file.file_offset_of_min_vaddr = 0;
+ file.symbols = symbols;
+ thread_tree.AddDsoInfo(file);
+ }
+
ThreadTree thread_tree;
const ThreadEntry* thread;
const std::string fake_native_lib_path = "fake_dir/fake_native_lib.so";
@@ -310,3 +307,76 @@ TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file) {
ASSERT_EQ(entries[1].vaddr_in_file, 0x3200);
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+
+TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file_for_jit_method_with_signature) {
+ std::vector<uint64_t> fake_ips = {
+ 0x3200, // 3200, // void ctep.v(cteo, ctgc, ctbn)
+ };
+ SetSymbols(fake_jit_cache_path, DSO_ELF_FILE,
+ {Symbol("void ctep.v(cteo, ctgc, ctbn)", 0x3200, 0x100)});
+ CallChainReportBuilder builder(thread_tree);
+ TemporaryFile tmpfile;
+ close(tmpfile.release());
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "android.support.v4.app.RemoteActionCompatParcelizer -> ctep:\n"
+ " 13:13:androidx.core.app.RemoteActionCompat read(androidx.versionedparcelable.Versioned"
+ "Parcel) -> v\n",
+ tmpfile.path));
+ builder.AddProguardMappingFile(tmpfile.path);
+ std::vector<CallChainReportEntry> entries = builder.Build(thread, fake_ips, 0);
+ ASSERT_EQ(entries.size(), 1);
+ ASSERT_EQ(entries[0].ip, 0x3200);
+ ASSERT_STREQ(entries[0].symbol->DemangledName(),
+ "android.support.v4.app.RemoteActionCompatParcelizer.read");
+ ASSERT_EQ(entries[0].dso->Path(), fake_jit_cache_path);
+ ASSERT_EQ(entries[0].vaddr_in_file, 0x3200);
+ ASSERT_EQ(entries[0].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
+}
+
+TEST_F(CallChainReportBuilderTest, convert_jit_frame_for_jit_method_with_signature) {
+ std::vector<uint64_t> fake_ips = {
+ 0x2200, // 2200, // ctep.v
+ 0x3200, // 3200, // void ctep.v(cteo, ctgc, ctbn)
+ };
+ SetSymbols(fake_dex_file_path, DSO_DEX_FILE, {Symbol("ctep.v", 0x200, 0x100)});
+ SetSymbols(fake_jit_cache_path, DSO_ELF_FILE,
+ {Symbol("void ctep.v(cteo, ctgc, ctbn)", 0x3200, 0x100)});
+ CallChainReportBuilder builder(thread_tree);
+ // Test if we can convert jit method with signature.
+ std::vector<CallChainReportEntry> entries = builder.Build(thread, fake_ips, 0);
+ ASSERT_EQ(entries.size(), 2);
+ ASSERT_EQ(entries[0].ip, 0x2200);
+ ASSERT_STREQ(entries[0].symbol->DemangledName(), "ctep.v");
+ ASSERT_EQ(entries[0].dso->Path(), fake_dex_file_path);
+ ASSERT_EQ(entries[0].vaddr_in_file, 0x200);
+ ASSERT_EQ(entries[0].execution_type, CallChainExecutionType::INTERPRETED_JVM_METHOD);
+ ASSERT_EQ(entries[1].ip, 0x3200);
+ ASSERT_STREQ(entries[1].symbol->DemangledName(), "ctep.v");
+ ASSERT_EQ(entries[1].dso->Path(), fake_dex_file_path);
+ ASSERT_EQ(entries[1].vaddr_in_file, 0x200);
+ ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
+
+ // Test adding proguard mapping file.
+ TemporaryFile tmpfile;
+ close(tmpfile.release());
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "android.support.v4.app.RemoteActionCompatParcelizer -> ctep:\n"
+ " 13:13:androidx.core.app.RemoteActionCompat read(androidx.versionedparcelable.Versioned"
+ "Parcel) -> v\n",
+ tmpfile.path));
+ builder.AddProguardMappingFile(tmpfile.path);
+ entries = builder.Build(thread, fake_ips, 0);
+ ASSERT_EQ(entries.size(), 2);
+ ASSERT_EQ(entries[0].ip, 0x2200);
+ ASSERT_STREQ(entries[0].symbol->DemangledName(),
+ "android.support.v4.app.RemoteActionCompatParcelizer.read");
+ ASSERT_EQ(entries[0].dso->Path(), fake_dex_file_path);
+ ASSERT_EQ(entries[0].vaddr_in_file, 0x200);
+ ASSERT_EQ(entries[0].execution_type, CallChainExecutionType::INTERPRETED_JVM_METHOD);
+ ASSERT_EQ(entries[1].ip, 0x3200);
+ ASSERT_STREQ(entries[1].symbol->DemangledName(),
+ "android.support.v4.app.RemoteActionCompatParcelizer.read");
+ ASSERT_EQ(entries[1].dso->Path(), fake_dex_file_path);
+ ASSERT_EQ(entries[1].vaddr_in_file, 0x200);
+ ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
+}