1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <inttypes.h> 20 21 #include <string> 22 #include <string_view> 23 #include <unordered_map> 24 #include <vector> 25 26 #include "RegEx.h" 27 #include "dso.h" 28 #include "thread_tree.h" 29 #include "utils.h" 30 31 namespace simpleperf { 32 33 class ProguardMappingRetrace { 34 public: 35 // Add proguard mapping.txt to de-obfuscate minified symbols. 36 bool AddProguardMappingFile(std::string_view mapping_file); 37 38 bool DeObfuscateJavaMethods(std::string_view obfuscated_name, std::string* original_name, 39 bool* synthesized); 40 41 private: 42 struct MappingMethod { 43 std::string original_name; 44 bool contains_classname; 45 bool synthesized; 46 }; 47 48 struct MappingClass { 49 std::string original_classname; 50 bool synthesized = false; 51 // Map from obfuscated method names to MappingMethod. 52 std::unordered_map<std::string, MappingMethod> method_map; 53 }; 54 55 enum LineType { 56 SYNTHESIZED_COMMENT, 57 CLASS_LINE, 58 METHOD_LINE, 59 LINE_EOF, 60 }; 61 62 struct LineInfo { 63 LineType type; 64 std::string_view data; 65 }; 66 67 void ParseMethod(MappingClass& mapping_class); 68 void MoveToNextLine(); 69 70 // Map from obfuscated class names to ProguardMappingClass. 71 std::unordered_map<std::string, MappingClass> class_map_; 72 std::unique_ptr<LineReader> line_reader_; 73 LineInfo cur_line_; 74 }; 75 76 enum class CallChainExecutionType { 77 NATIVE_METHOD, 78 INTERPRETED_JVM_METHOD, 79 JIT_JVM_METHOD, 80 // ART methods near interpreted/JIT JVM methods. They're shown only when RemoveArtFrame = false. 81 ART_METHOD, 82 }; 83 84 struct CallChainReportEntry { 85 uint64_t ip = 0; 86 const Symbol* symbol = nullptr; 87 Dso* dso = nullptr; 88 const char* dso_name = nullptr; 89 uint64_t vaddr_in_file = 0; 90 const MapEntry* map = nullptr; 91 CallChainExecutionType execution_type = CallChainExecutionType::NATIVE_METHOD; 92 }; 93 94 class CallChainReportBuilder { 95 public: 96 CallChainReportBuilder(ThreadTree& thread_tree); 97 // If true, remove interpreter frames both before and after a Java frame. 98 // Default is true. SetRemoveArtFrame(bool enable)99 void SetRemoveArtFrame(bool enable) { remove_art_frame_ = enable; } 100 // If true, convert a JIT method into its corresponding interpreted Java method. So they can be 101 // merged in reports like flamegraph. Default is true. SetConvertJITFrame(bool enable)102 void SetConvertJITFrame(bool enable) { convert_jit_frame_ = enable; } 103 // Add proguard mapping.txt to de-obfuscate minified symbols. 104 bool AddProguardMappingFile(std::string_view mapping_file); 105 std::vector<CallChainReportEntry> Build(const ThreadEntry* thread, 106 const std::vector<uint64_t>& ips, size_t kernel_ip_count); 107 108 private: 109 struct JavaMethod { 110 Dso* dso; 111 const Symbol* symbol; JavaMethodJavaMethod112 JavaMethod(Dso* dso, const Symbol* symbol) : dso(dso), symbol(symbol) {} 113 }; 114 115 void MarkArtFrame(std::vector<CallChainReportEntry>& callchain); 116 void ConvertJITFrame(std::vector<CallChainReportEntry>& callchain); 117 void CollectJavaMethods(); 118 void DeObfuscateJavaMethods(std::vector<CallChainReportEntry>& callchain); 119 120 ThreadTree& thread_tree_; 121 bool remove_art_frame_ = true; 122 bool remove_r8_synthesized_frame_ = false; 123 bool convert_jit_frame_ = true; 124 bool java_method_initialized_ = false; 125 std::unordered_map<std::string, JavaMethod> java_method_map_; 126 std::unique_ptr<ProguardMappingRetrace> retrace_; 127 }; 128 129 struct ThreadReport { 130 int pid; 131 int tid; 132 const char* thread_name; 133 134 ThreadReport(int pid = 0, int tid = 0, const char* thread_name = nullptr) pidThreadReport135 : pid(pid), tid(tid), thread_name(thread_name) {} 136 }; 137 138 // Report thread info of a sample. 139 class ThreadReportBuilder { 140 public: 141 // Aggregate threads with names matching the same regex. 142 bool AggregateThreads(const std::vector<std::string>& thread_name_regex); 143 ThreadReport Build(const ThreadEntry& thread); 144 145 private: 146 void ModifyReportToAggregateThreads(ThreadReport& report); 147 148 struct ThreadNameRegInfo { 149 std::unique_ptr<RegEx> re; 150 ThreadReport report; 151 }; 152 153 std::vector<ThreadNameRegInfo> thread_regs_; 154 // Map from thread name to the corresponding index in thread_regs_. 155 // Return -1 if the thread name doesn't match any regular expression. 156 std::unordered_map<std::string, int> thread_map_; 157 }; 158 159 } // namespace simpleperf 160