• 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 
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