• 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     // remote addr of jit descriptor
166     uint64_t jit_descriptor_addr = 0;
167     // remote addr of dex descriptor
168     uint64_t dex_descriptor_addr = 0;
169 
170     // The state we know about the remote jit debug descriptor.
171     Descriptor last_jit_descriptor;
172     // The state we know about the remote dex debug descriptor.
173     Descriptor last_dex_descriptor;
174 
175     // memory space for /memfd:jit-zygote-cache
176     std::vector<std::pair<uint64_t, uint64_t>> jit_zygote_cache_ranges_;
177   };
178 
179   // The location of descriptors in libart.so.
180   struct DescriptorsLocation {
181     bool is_64bit = false;
182     uint64_t jit_descriptor_addr = 0;
183     uint64_t dex_descriptor_addr = 0;
184   };
185 
186   bool ReadProcess(Process& process, std::vector<JITDebugInfo>* debug_info);
187   bool ReadDebugInfo(Process& process, Descriptor& new_descriptor,
188                      std::vector<JITDebugInfo>* debug_info);
189   bool IsDescriptorChanged(Process& process, Descriptor& old_descriptor);
190   bool InitializeProcess(Process& process);
191   const DescriptorsLocation* GetDescriptorsLocation(const std::string& art_lib_path);
192   bool ReadRemoteMem(Process& process, uint64_t remote_addr, uint64_t size, void* data);
193   bool ReadDescriptors(Process& process, Descriptor* jit_descriptor, Descriptor* dex_descriptor);
194   template <typename DescriptorT>
195   bool ReadDescriptorsImpl(Process& process, Descriptor* jit_descriptor,
196                            Descriptor* dex_descriptor);
197   template <typename DescriptorT>
198   bool ParseDescriptor(const DescriptorT& raw_descriptor, Descriptor* descriptor);
199 
200   bool ReadNewCodeEntries(Process& process, const Descriptor& descriptor,
201                           uint64_t last_action_timestamp, uint32_t read_entry_limit,
202                           std::vector<CodeEntry>* new_code_entries);
203   template <typename CodeEntryT>
204   bool ReadNewCodeEntriesImpl(Process& process, const Descriptor& descriptor,
205                               uint64_t last_action_timestamp, uint32_t read_entry_limit,
206                               std::vector<CodeEntry>* new_code_entries);
207 
208   bool ReadJITCodeDebugInfo(Process& process, const std::vector<CodeEntry>& jit_entries,
209                             std::vector<JITDebugInfo>* debug_info);
210   TempSymFile* GetTempSymFile(Process& process, const CodeEntry& jit_entry);
211   void ReadDexFileDebugInfo(Process& process, const std::vector<CodeEntry>& dex_entries,
212                             std::vector<JITDebugInfo>* debug_info);
213   bool AddDebugInfo(const std::vector<JITDebugInfo>& debug_info, bool sync_kernel_records);
214 
215   const std::string symfile_prefix_;
216   SymFileOption symfile_option_;
217   SyncOption sync_option_;
218   IOEventRef read_event_ = nullptr;
219   debug_info_callback_t debug_info_callback_;
220 
221   // Keys are pids of processes having libart.so, values show whether a process has been monitored.
222   std::unordered_map<pid_t, bool> pids_with_art_lib_;
223 
224   // All monitored processes
225   std::unordered_map<pid_t, Process> processes_;
226   std::unordered_map<std::string, DescriptorsLocation> descriptors_location_cache_;
227 
228   std::priority_queue<JITDebugInfo, std::vector<JITDebugInfo>, std::greater<JITDebugInfo>>
229       debug_info_q_;
230 
231   // temporary files used to store jit symfiles created by the app process and the zygote process.
232   std::unique_ptr<TempSymFile> app_symfile_;
233   std::unique_ptr<TempSymFile> zygote_symfile_;
234 };
235 
236 }  // namespace simpleperf
237 
238 #endif  // SIMPLE_PERF_JIT_DEBUG_READER_H_
239