• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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