1 /* 2 * Copyright (C) 2018 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 #ifndef SIMPLE_PERF_JIT_DEBUG_READER_H_ 18 #define SIMPLE_PERF_JIT_DEBUG_READER_H_ 19 20 #include <unistd.h> 21 22 #include <functional> 23 #include <memory> 24 #include <queue> 25 #include <stack> 26 #include <unordered_map> 27 #include <unordered_set> 28 #include <vector> 29 30 #include <android-base/file.h> 31 #include <android-base/logging.h> 32 33 #include "IOEventLoop.h" 34 #include "environment.h" 35 #include "record.h" 36 37 namespace simpleperf { 38 39 inline constexpr const char* kJITAppCacheFile = "jit_app_cache"; 40 inline constexpr const char* kJITZygoteCacheFile = "jit_zygote_cache"; 41 inline constexpr const char* kDexFileInMemoryPrefix = "dexfile_in_memory"; 42 43 namespace JITDebugReader_impl { 44 45 enum class DescriptorType { 46 kDEX, 47 kJIT, 48 }; 49 50 // An arch-independent representation of JIT/dex debug descriptor. 51 struct Descriptor { 52 DescriptorType type; 53 int version = 0; 54 uint32_t action_seqlock = 0; // incremented before and after any modification 55 uint64_t action_timestamp = 0; // CLOCK_MONOTONIC time of last action 56 uint64_t first_entry_addr = 0; 57 }; 58 59 // An arch-independent representation of JIT/dex code entry. 60 struct CodeEntry { 61 uint64_t addr; 62 uint64_t symfile_addr; 63 uint64_t symfile_size; 64 uint64_t timestamp; // CLOCK_MONOTONIC time of last action 65 }; 66 67 struct Process { 68 pid_t pid = -1; 69 bool initialized = false; 70 bool died = false; 71 bool is_64bit = false; 72 // remote addr of jit descriptor 73 uint64_t jit_descriptor_addr = 0; 74 // remote addr of dex descriptor 75 uint64_t dex_descriptor_addr = 0; 76 77 // The state we know about the remote jit debug descriptor. 78 Descriptor last_jit_descriptor; 79 // The state we know about the remote dex debug descriptor. 80 Descriptor last_dex_descriptor; 81 82 // memory space for /memfd:jit-zygote-cache 83 std::vector<std::pair<uint64_t, uint64_t>> jit_zygote_cache_ranges_; 84 }; 85 86 } // namespace JITDebugReader_impl 87 88 // JITDebugInfo represents the debug info of a JITed Java method or a dex file. 89 struct JITDebugInfo { 90 enum { 91 JIT_DEBUG_JIT_CODE, 92 JIT_DEBUG_DEX_FILE, 93 } type; 94 pid_t pid; // Process of the debug info 95 uint64_t timestamp; // Monotonic timestamp for the creation of the debug info 96 97 union { 98 struct { 99 uint64_t jit_code_addr; // The start addr of the JITed code 100 uint64_t jit_code_len; // The end addr of the JITed code 101 }; 102 uint64_t dex_file_offset; // The offset of the dex file in the file containing it 103 }; 104 // For JITed code, it is the path of a temporary ELF file storing its debug info. 105 // For dex file, it is the path of the file containing the dex file. 106 std::string file_path; 107 uint64_t file_offset; 108 109 // dex_file_map may be a dex file extracted in memory. On Android >= Q, ART may extract dex files 110 // in apk files directly into memory, and name it using prctl(). The kernel doesn't generate a 111 // new mmap record for it. So we need to dump it manually. 112 // Or dex_file_map may be a dex file created in memory. In that case, symbols are read from the 113 // dex file. 114 std::shared_ptr<ThreadMmap> dex_file_map; 115 std::vector<Symbol> symbols; 116 JITDebugInfoJITDebugInfo117 JITDebugInfo(pid_t pid, uint64_t timestamp, uint64_t jit_code_addr, uint64_t jit_code_len, 118 const std::string& file_path, uint64_t file_offset) 119 : type(JIT_DEBUG_JIT_CODE), 120 pid(pid), 121 timestamp(timestamp), 122 jit_code_addr(jit_code_addr), 123 jit_code_len(jit_code_len), 124 file_path(file_path), 125 file_offset(file_offset) {} 126 JITDebugInfoJITDebugInfo127 JITDebugInfo(pid_t pid, uint64_t timestamp, uint64_t dex_file_offset, 128 const std::string& file_path, const std::shared_ptr<ThreadMmap>& dex_file_map, 129 std::vector<Symbol> symbols) 130 : type(JIT_DEBUG_DEX_FILE), 131 pid(pid), 132 timestamp(timestamp), 133 dex_file_offset(dex_file_offset), 134 file_path(file_path), 135 file_offset(0), 136 dex_file_map(dex_file_map), 137 symbols(std::move(symbols)) {} 138 139 bool operator>(const JITDebugInfo& other) const { return timestamp > other.timestamp; } 140 }; 141 142 class TempSymFile; 143 144 // JITDebugReader reads debug info of JIT code and dex files of processes using ART. The 145 // corresponding debug interface in ART is at art/runtime/jit/debugger_interface.cc. 146 class JITDebugReader { 147 public: 148 using Descriptor = JITDebugReader_impl::Descriptor; 149 using CodeEntry = JITDebugReader_impl::CodeEntry; 150 using Process = JITDebugReader_impl::Process; 151 152 enum class SymFileOption { 153 kDropSymFiles, // JIT symfiles are dropped after recording. 154 kKeepSymFiles, // JIT symfiles are kept after recording, usually for debug unwinding. 155 }; 156 157 enum class SyncOption { 158 kNoSync, // Don't sync debug info with records. 159 kSyncWithRecords, // Sync debug info with records based on monotonic timestamp. 160 }; 161 162 // symfile_prefix: JITDebugReader creates temporary file to store symfiles for JIT code. Add this 163 // prefix to avoid conflicts. 164 JITDebugReader(const std::string& symfile_prefix, SymFileOption symfile_option, 165 SyncOption sync_option); 166 167 ~JITDebugReader(); 168 SyncWithRecords()169 bool SyncWithRecords() const { return sync_option_ == SyncOption::kSyncWithRecords; } 170 171 typedef std::function<bool(std::vector<JITDebugInfo>, bool)> debug_info_callback_t; 172 bool RegisterDebugInfoCallback(IOEventLoop* loop, const debug_info_callback_t& callback); 173 174 // There are two ways to select which processes to monitor. One is using MonitorProcess(), the 175 // other is finding all processes having libart.so using records. 176 bool MonitorProcess(pid_t pid); 177 bool UpdateRecord(const Record* record); 178 179 // Read new debug info from all monitored processes. 180 bool ReadAllProcesses(); 181 // Read new debug info from one process. 182 bool ReadProcess(pid_t pid); 183 184 // Flush all debug info registered before timestamp. 185 bool FlushDebugInfo(uint64_t timestamp); 186 IsPathInJITSymFile(const std::string & path)187 static bool IsPathInJITSymFile(const std::string& path) { 188 return path.find(std::string("_") + kJITAppCacheFile + ":") != path.npos || 189 path.find(std::string("_") + kJITZygoteCacheFile + ":") != path.npos; 190 } 191 192 // exported for testing 193 void ReadDexFileDebugInfo(Process& process, const std::vector<CodeEntry>& dex_entries, 194 std::vector<JITDebugInfo>* debug_info); 195 196 private: 197 // The location of descriptors in libart.so. 198 struct DescriptorsLocation { 199 bool is_64bit = false; 200 uint64_t jit_descriptor_addr = 0; 201 uint64_t dex_descriptor_addr = 0; 202 }; 203 204 bool ReadProcess(Process& process, std::vector<JITDebugInfo>* debug_info); 205 bool ReadDebugInfo(Process& process, Descriptor& new_descriptor, 206 std::vector<JITDebugInfo>* debug_info); 207 bool IsDescriptorChanged(Process& process, Descriptor& old_descriptor); 208 bool InitializeProcess(Process& process); 209 const DescriptorsLocation* GetDescriptorsLocation(const std::string& art_lib_path); 210 bool ReadRemoteMem(Process& process, uint64_t remote_addr, uint64_t size, void* data); 211 bool ReadDescriptors(Process& process, Descriptor* jit_descriptor, Descriptor* dex_descriptor); 212 template <typename DescriptorT> 213 bool ReadDescriptorsImpl(Process& process, Descriptor* jit_descriptor, 214 Descriptor* dex_descriptor); 215 template <typename DescriptorT> 216 bool ParseDescriptor(const DescriptorT& raw_descriptor, Descriptor* descriptor); 217 218 bool ReadNewCodeEntries(Process& process, const Descriptor& descriptor, 219 uint64_t last_action_timestamp, uint32_t read_entry_limit, 220 std::vector<CodeEntry>* new_code_entries); 221 template <typename CodeEntryT> 222 bool ReadNewCodeEntriesImpl(Process& process, const Descriptor& descriptor, 223 uint64_t last_action_timestamp, uint32_t read_entry_limit, 224 std::vector<CodeEntry>* new_code_entries); 225 226 bool ReadJITCodeDebugInfo(Process& process, const std::vector<CodeEntry>& jit_entries, 227 std::vector<JITDebugInfo>* debug_info); 228 TempSymFile* GetTempSymFile(Process& process, const CodeEntry& jit_entry); 229 std::vector<Symbol> ReadDexFileSymbolsInMemory(Process& process, uint64_t addr, uint64_t size); 230 bool AddDebugInfo(std::vector<JITDebugInfo> debug_info, bool sync_kernel_records); 231 232 const std::string symfile_prefix_; 233 SymFileOption symfile_option_; 234 SyncOption sync_option_; 235 IOEventRef read_event_ = nullptr; 236 debug_info_callback_t debug_info_callback_; 237 238 // Keys are pids of processes having libart.so, values show whether a process has been monitored. 239 std::unordered_map<pid_t, bool> pids_with_art_lib_; 240 241 // All monitored processes 242 std::unordered_map<pid_t, Process> processes_; 243 std::unordered_map<std::string, DescriptorsLocation> descriptors_location_cache_; 244 245 std::priority_queue<JITDebugInfo, std::vector<JITDebugInfo>, std::greater<JITDebugInfo>> 246 debug_info_q_; 247 248 // temporary files used to store jit symfiles created by the app process and the zygote process. 249 std::unique_ptr<TempSymFile> app_symfile_; 250 std::unique_ptr<TempSymFile> zygote_symfile_; 251 }; 252 253 } // namespace simpleperf 254 255 #endif // SIMPLE_PERF_JIT_DEBUG_READER_H_ 256