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