diff options
author | Yabin Cui <yabinc@google.com> | 2021-08-17 16:47:32 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-08-17 16:47:32 +0000 |
commit | 34b6e1840f7eea71a4d0ee02dc889d02918a8e80 (patch) | |
tree | 0d0c3a61f0e55492ebc85109b71980cd24f292f8 | |
parent | 84c6227af6f64056bc84b64a1ae314ea23a840c7 (diff) | |
parent | 1e16b20c973bf8ac7fa5207bab3cfff3fc1249c3 (diff) | |
download | extras-34b6e1840f7eea71a4d0ee02dc889d02918a8e80.tar.gz |
Merge "simpleperf: support JIT method name with signature."
-rw-r--r-- | simpleperf/dso.cpp | 14 | ||||
-rw-r--r-- | simpleperf/dso.h | 2 | ||||
-rw-r--r-- | simpleperf/dso_test.cpp | 7 | ||||
-rw-r--r-- | simpleperf/report_utils.cpp | 12 | ||||
-rw-r--r-- | simpleperf/report_utils_test.cpp | 142 |
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); +} |