• 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 #include "JITDebugReader.h"
18 
19 #include <inttypes.h>
20 #include <sys/mman.h>
21 #include <sys/uio.h>
22 
23 #include <algorithm>
24 #include <unordered_map>
25 #include <unordered_set>
26 #include <vector>
27 
28 #include <android-base/file.h>
29 #include <android-base/logging.h>
30 #include <android-base/strings.h>
31 
32 #include "dso.h"
33 #include "environment.h"
34 #include "read_apk.h"
35 #include "read_elf.h"
36 #include "utils.h"
37 
38 namespace simpleperf {
39 
40 // If the size of a symfile is larger than EXPECTED_MAX_SYMFILE_SIZE, we don't want to read it
41 // remotely.
42 static constexpr size_t MAX_JIT_SYMFILE_SIZE = 1024 * 1024u;
43 
44 // It takes about 30us-130us on Pixel (depending on the cpu frequency) to check if the descriptors
45 // have been updated (most time spent in process_vm_preadv). We want to know if the JIT debug info
46 // changed as soon as possible, while not wasting too much time checking for updates. So use a
47 // period of 100 ms.
48 // In system wide profiling, we may need to check JIT debug info changes for many processes, to
49 // avoid spending all time checking, wait 100 ms between any two checks.
50 static constexpr size_t kUpdateJITDebugInfoIntervalInMs = 100;
51 
52 // Match the format of JITDescriptor in art/runtime/jit/debugger_itnerface.cc.
53 template <typename ADDRT>
54 struct JITDescriptor {
55   uint32_t version;
56   uint32_t action_flag;
57   ADDRT relevant_entry_addr;
58   ADDRT first_entry_addr;
59   uint8_t magic[8];
60   uint32_t flags;
61   uint32_t sizeof_descriptor;
62   uint32_t sizeof_entry;
63   uint32_t action_seqlock;  // incremented before and after any modification
64   uint64_t action_timestamp;  // CLOCK_MONOTONIC time of last action
65 
Validsimpleperf::JITDescriptor66   bool Valid() const {
67     return version == 1 && strncmp(reinterpret_cast<const char*>(magic), "Android1", 8) == 0;
68   }
69 };
70 
71 // Match the format of JITCodeEntry in art/runtime/jit/debugger_itnerface.cc.
72 template <typename ADDRT>
73 struct JITCodeEntry {
74   ADDRT next_addr;
75   ADDRT prev_addr;
76   ADDRT symfile_addr;
77   uint64_t symfile_size;
78   uint64_t register_timestamp;  // CLOCK_MONOTONIC time of entry registration
79 
Validsimpleperf::JITCodeEntry80   bool Valid() const {
81     return symfile_addr > 0u && symfile_size > 0u;
82   }
83 };
84 
85 // Match the format of JITCodeEntry in art/runtime/jit/debugger_interface.cc.
86 template <typename ADDRT>
87 struct __attribute__((packed)) PackedJITCodeEntry {
88   ADDRT next_addr;
89   ADDRT prev_addr;
90   ADDRT symfile_addr;
91   uint64_t symfile_size;
92   uint64_t register_timestamp;
93 
Validsimpleperf::PackedJITCodeEntry94   bool Valid() const {
95     return symfile_addr > 0u && symfile_size > 0u;
96   }
97 };
98 
99 using JITDescriptor32 = JITDescriptor<uint32_t>;
100 using JITDescriptor64 = JITDescriptor<uint64_t>;
101 
102 #if defined(__x86_64__)
103 // Make sure simpleperf built for i386 and x86_64 see the correct JITCodeEntry layout of i386.
104 using JITCodeEntry32 = PackedJITCodeEntry<uint32_t>;
105 #else
106 using JITCodeEntry32 = JITCodeEntry<uint32_t>;
107 #endif
108 using JITCodeEntry64 = JITCodeEntry<uint64_t>;
109 
110 // We want to support both 64-bit and 32-bit simpleperf when profiling either 64-bit or 32-bit
111 // apps. So using static_asserts to make sure that simpleperf on arm and aarch64 having the same
112 // view of structures, and simpleperf on i386 and x86_64 having the same view of structures.
113 static_assert(sizeof(JITDescriptor32) == 48, "");
114 static_assert(sizeof(JITDescriptor64) == 56, "");
115 #if defined(__i386__) or defined(__x86_64__)
116 static_assert(sizeof(JITCodeEntry32) == 28, "");
117 #else
118 static_assert(sizeof(JITCodeEntry32) == 32, "");
119 #endif
120 static_assert(sizeof(JITCodeEntry64) == 40, "");
121 
RegisterDebugInfoCallback(IOEventLoop * loop,const debug_info_callback_t & callback)122 bool JITDebugReader::RegisterDebugInfoCallback(IOEventLoop* loop,
123                                              const debug_info_callback_t& callback) {
124   debug_info_callback_ = callback;
125   read_event_ = loop->AddPeriodicEvent(SecondToTimeval(kUpdateJITDebugInfoIntervalInMs / 1000.0),
126                                        [this]() { return ReadAllProcesses(); });
127   return (read_event_ != nullptr && IOEventLoop::DisableEvent(read_event_));
128 }
129 
MonitorProcess(pid_t pid)130 bool JITDebugReader::MonitorProcess(pid_t pid) {
131   if (processes_.find(pid) == processes_.end()) {
132     processes_[pid].pid = pid;
133     LOG(DEBUG) << "Start monitoring process " << pid;
134     if (processes_.size() == 1u) {
135       if (!IOEventLoop::EnableEvent(read_event_)) {
136         return false;
137       }
138     }
139   }
140   return true;
141 }
142 
IsArtLib(const std::string & filename)143 static bool IsArtLib(const std::string& filename) {
144   return android::base::EndsWith(filename, "libart.so") ||
145       android::base::EndsWith(filename, "libartd.so");
146 }
147 
UpdateRecord(const Record * record)148 bool JITDebugReader::UpdateRecord(const Record* record) {
149   if (record->type() == PERF_RECORD_MMAP) {
150     auto r = static_cast<const MmapRecord*>(record);
151     if (IsArtLib(r->filename)) {
152       pids_with_art_lib_.emplace(r->data->pid, false);
153     }
154   } else if (record->type() == PERF_RECORD_MMAP2) {
155     auto r = static_cast<const Mmap2Record*>(record);
156     if (IsArtLib(r->filename)) {
157       pids_with_art_lib_.emplace(r->data->pid, false);
158     }
159   } else if (record->type() == PERF_RECORD_FORK) {
160     auto r = static_cast<const ForkRecord*>(record);
161     if (r->data->pid != r->data->ppid &&
162         pids_with_art_lib_.find(r->data->ppid) != pids_with_art_lib_.end()) {
163       pids_with_art_lib_.emplace(r->data->pid, false);
164     }
165   } else if (record->type() == PERF_RECORD_SAMPLE) {
166     auto r = static_cast<const SampleRecord*>(record);
167     auto it = pids_with_art_lib_.find(r->tid_data.pid);
168     if (it != pids_with_art_lib_.end() && !it->second) {
169       it->second = true;
170       if (!MonitorProcess(r->tid_data.pid)) {
171         return false;
172       }
173       return ReadProcess(r->tid_data.pid);
174     }
175   }
176   return FlushDebugInfo(record->Timestamp());
177 }
178 
FlushDebugInfo(uint64_t timestamp)179 bool JITDebugReader::FlushDebugInfo(uint64_t timestamp) {
180   if (sync_with_records_) {
181     if (!debug_info_q_.empty() && debug_info_q_.top().timestamp < timestamp) {
182       std::vector<JITDebugInfo> debug_info;
183       while (!debug_info_q_.empty() && debug_info_q_.top().timestamp < timestamp) {
184         debug_info.emplace_back(debug_info_q_.top());
185         debug_info_q_.pop();
186       }
187       return debug_info_callback_(debug_info, false);
188     }
189   }
190   return true;
191 }
192 
ReadAllProcesses()193 bool JITDebugReader::ReadAllProcesses() {
194   if (!IOEventLoop::DisableEvent(read_event_)) {
195     return false;
196   }
197   std::vector<JITDebugInfo> debug_info;
198   for (auto it = processes_.begin(); it != processes_.end();) {
199     Process& process = it->second;
200     ReadProcess(process, &debug_info);
201     if (process.died) {
202       LOG(DEBUG) << "Stop monitoring process " << process.pid;
203       it = processes_.erase(it);
204     } else {
205       ++it;
206     }
207   }
208   if (!AddDebugInfo(debug_info, true)) {
209     return false;
210   }
211   if (!processes_.empty()) {
212     return IOEventLoop::EnableEvent(read_event_);
213   }
214   return true;
215 }
216 
ReadProcess(pid_t pid)217 bool JITDebugReader::ReadProcess(pid_t pid) {
218   auto it = processes_.find(pid);
219   if (it != processes_.end()) {
220     std::vector<JITDebugInfo> debug_info;
221     ReadProcess(it->second, &debug_info);
222     return AddDebugInfo(debug_info, false);
223   }
224   return true;
225 }
226 
ReadProcess(Process & process,std::vector<JITDebugInfo> * debug_info)227 void JITDebugReader::ReadProcess(Process& process, std::vector<JITDebugInfo>* debug_info) {
228   if (process.died || (!process.initialized && !InitializeProcess(process))) {
229     return;
230   }
231   // 1. Read descriptors.
232   Descriptor jit_descriptor;
233   Descriptor dex_descriptor;
234   if (!ReadDescriptors(process, &jit_descriptor, &dex_descriptor)) {
235     return;
236   }
237   // 2. Return if descriptors are not changed.
238   if (jit_descriptor.action_seqlock == process.last_jit_descriptor.action_seqlock &&
239       dex_descriptor.action_seqlock == process.last_dex_descriptor.action_seqlock) {
240     return;
241   }
242 
243   // 3. Read new symfiles.
244   auto check_descriptor = [&](Descriptor& descriptor, bool is_jit) {
245       Descriptor tmp_jit_descriptor;
246       Descriptor tmp_dex_descriptor;
247       if (!ReadDescriptors(process, &tmp_jit_descriptor, &tmp_dex_descriptor)) {
248         return false;
249       }
250       if (is_jit) {
251         return descriptor.action_seqlock == tmp_jit_descriptor.action_seqlock;
252       }
253       return descriptor.action_seqlock == tmp_dex_descriptor.action_seqlock;
254   };
255 
256   auto read_debug_info = [&](Descriptor& new_descriptor, Descriptor& old_descriptor, bool is_jit) {
257     bool has_update = new_descriptor.action_seqlock != old_descriptor.action_seqlock &&
258                       (new_descriptor.action_seqlock & 1) == 0;
259     LOG(DEBUG) << (is_jit ? "JIT" : "Dex") << " symfiles of pid " << process.pid
260         << ": old seqlock " << old_descriptor.action_seqlock
261         << ", new seqlock " << new_descriptor.action_seqlock;
262     if (!has_update) {
263       return false;
264     }
265     std::vector<CodeEntry> new_entries;
266     // Adding or removing one code entry will make two increments of action_seqlock. So we should
267     // not read more than (seqlock_diff / 2) new entries.
268     uint32_t read_entry_limit = (new_descriptor.action_seqlock - old_descriptor.action_seqlock) / 2;
269     if (!ReadNewCodeEntries(process, new_descriptor, old_descriptor.action_timestamp,
270                             read_entry_limit, &new_entries)) {
271       return false;
272     }
273     // Check if the descriptor was changed while we were reading new entries.
274     if (!check_descriptor(new_descriptor, is_jit)) {
275       return false;
276     }
277     LOG(DEBUG) << (is_jit ? "JIT" : "Dex") << " symfiles of pid " << process.pid
278                << ": read " << new_entries.size() << " new entries";
279     if (new_entries.empty()) {
280       return true;
281     }
282     if (is_jit) {
283       ReadJITCodeDebugInfo(process, new_entries, debug_info);
284     } else {
285       ReadDexFileDebugInfo(process, new_entries, debug_info);
286     }
287     return true;
288   };
289   if (read_debug_info(jit_descriptor, process.last_jit_descriptor, true)) {
290     process.last_jit_descriptor = jit_descriptor;
291   }
292   if (read_debug_info(dex_descriptor, process.last_dex_descriptor, false)) {
293     process.last_dex_descriptor = dex_descriptor;
294   }
295 }
296 
InitializeProcess(Process & process)297 bool JITDebugReader::InitializeProcess(Process& process) {
298   // 1. Read map file to find the location of libart.so.
299   std::vector<ThreadMmap> thread_mmaps;
300   if (!GetThreadMmapsInProcess(process.pid, &thread_mmaps)) {
301     process.died = true;
302     return false;
303   }
304   std::string art_lib_path;
305   uint64_t min_vaddr_in_memory;
306   for (auto& map : thread_mmaps) {
307     if ((map.prot & PROT_EXEC) && IsArtLib(map.name)) {
308       art_lib_path = map.name;
309       min_vaddr_in_memory = map.start_addr;
310       break;
311     }
312   }
313   if (art_lib_path.empty()) {
314     return false;
315   }
316   process.is_64bit = art_lib_path.find("lib64") != std::string::npos;
317 
318   // 2. Read libart.so to find the addresses of __jit_debug_descriptor and __dex_debug_descriptor.
319   const DescriptorsLocation* location = GetDescriptorsLocation(art_lib_path, process.is_64bit);
320   if (location == nullptr) {
321     return false;
322   }
323   process.descriptors_addr = location->relative_addr + min_vaddr_in_memory;
324   process.descriptors_size = location->size;
325   process.jit_descriptor_offset = location->jit_descriptor_offset;
326   process.dex_descriptor_offset = location->dex_descriptor_offset;
327   process.initialized = true;
328   return true;
329 }
330 
GetDescriptorsLocation(const std::string & art_lib_path,bool is_64bit)331 const JITDebugReader::DescriptorsLocation* JITDebugReader::GetDescriptorsLocation(
332     const std::string& art_lib_path, bool is_64bit) {
333   auto it = descriptors_location_cache_.find(art_lib_path);
334   if (it != descriptors_location_cache_.end()) {
335     return it->second.relative_addr == 0u ? nullptr : &it->second;
336   }
337   DescriptorsLocation& location = descriptors_location_cache_[art_lib_path];
338 
339   // Read libart.so to find the addresses of __jit_debug_descriptor and __dex_debug_descriptor.
340   uint64_t min_vaddr_in_file;
341   uint64_t file_offset;
342   ElfStatus status = ReadMinExecutableVirtualAddressFromElfFile(art_lib_path, BuildId(),
343                                                                 &min_vaddr_in_file,
344                                                                 &file_offset);
345   if (status != ElfStatus::NO_ERROR) {
346     LOG(ERROR) << "ReadMinExecutableVirtualAddress failed, status = " << status;
347     return nullptr;
348   }
349   const char* jit_str = "__jit_debug_descriptor";
350   const char* dex_str = "__dex_debug_descriptor";
351   uint64_t jit_addr = 0u;
352   uint64_t dex_addr = 0u;
353 
354   auto callback = [&](const ElfFileSymbol& symbol) {
355     if (symbol.name == jit_str) {
356       jit_addr = symbol.vaddr - min_vaddr_in_file;
357     } else if (symbol.name == dex_str) {
358       dex_addr = symbol.vaddr - min_vaddr_in_file;
359     }
360   };
361   if (ParseDynamicSymbolsFromElfFile(art_lib_path, callback) != ElfStatus::NO_ERROR) {
362     return nullptr;
363   }
364   if (jit_addr == 0u || dex_addr == 0u) {
365     return nullptr;
366   }
367   location.relative_addr = std::min(jit_addr, dex_addr);
368   location.size = std::max(jit_addr, dex_addr) +
369       (is_64bit ? sizeof(JITDescriptor64) : sizeof(JITDescriptor32)) - location.relative_addr;
370   if (location.size >= 4096u) {
371     PLOG(WARNING) << "The descriptors_size is unexpected large: " << location.size;
372   }
373   if (descriptors_buf_.size() < location.size) {
374     descriptors_buf_.resize(location.size);
375   }
376   location.jit_descriptor_offset = jit_addr - location.relative_addr;
377   location.dex_descriptor_offset = dex_addr - location.relative_addr;
378   return &location;
379 }
380 
ReadRemoteMem(Process & process,uint64_t remote_addr,uint64_t size,void * data)381 bool JITDebugReader::ReadRemoteMem(Process& process, uint64_t remote_addr, uint64_t size,
382                                    void* data) {
383   iovec local_iov;
384   local_iov.iov_base = data;
385   local_iov.iov_len = size;
386   iovec remote_iov;
387   remote_iov.iov_base = reinterpret_cast<void*>(static_cast<uintptr_t>(remote_addr));
388   remote_iov.iov_len = size;
389   ssize_t result = process_vm_readv(process.pid, &local_iov, 1, &remote_iov, 1, 0);
390   if (static_cast<size_t>(result) != size) {
391     PLOG(DEBUG) << "ReadRemoteMem(" << " pid " << process.pid << ", addr " << std::hex
392                 << remote_addr << ", size " << size << ") failed";
393     process.died = true;
394     return false;
395   }
396   return true;
397 }
398 
ReadDescriptors(Process & process,Descriptor * jit_descriptor,Descriptor * dex_descriptor)399 bool JITDebugReader::ReadDescriptors(Process& process, Descriptor* jit_descriptor,
400                                      Descriptor* dex_descriptor) {
401   if (!ReadRemoteMem(process, process.descriptors_addr, process.descriptors_size,
402                      descriptors_buf_.data())) {
403     return false;
404   }
405   return LoadDescriptor(process.is_64bit, &descriptors_buf_[process.jit_descriptor_offset],
406                         jit_descriptor) &&
407       LoadDescriptor(process.is_64bit, &descriptors_buf_[process.dex_descriptor_offset],
408                      dex_descriptor);
409 }
410 
LoadDescriptor(bool is_64bit,const char * data,Descriptor * descriptor)411 bool JITDebugReader::LoadDescriptor(bool is_64bit, const char* data, Descriptor* descriptor) {
412   if (is_64bit) {
413     return LoadDescriptorImpl<JITDescriptor64, JITCodeEntry64>(data, descriptor);
414   }
415   return LoadDescriptorImpl<JITDescriptor32, JITCodeEntry32>(data, descriptor);
416 }
417 
418 template <typename DescriptorT, typename CodeEntryT>
LoadDescriptorImpl(const char * data,Descriptor * descriptor)419 bool JITDebugReader::LoadDescriptorImpl(const char* data, Descriptor* descriptor) {
420   DescriptorT raw_descriptor;
421   MoveFromBinaryFormat(raw_descriptor, data);
422   if (!raw_descriptor.Valid() || sizeof(raw_descriptor) != raw_descriptor.sizeof_descriptor ||
423       sizeof(CodeEntryT) != raw_descriptor.sizeof_entry) {
424     return false;
425   }
426   descriptor->action_seqlock = raw_descriptor.action_seqlock;
427   descriptor->action_timestamp = raw_descriptor.action_timestamp;
428   descriptor->first_entry_addr = raw_descriptor.first_entry_addr;
429   return true;
430 }
431 
432 // Read new code entries with timestamp > last_action_timestamp.
433 // Since we don't stop the app process while reading code entries, it is possible we are reading
434 // broken data. So return false once we detect that the data is broken.
ReadNewCodeEntries(Process & process,const Descriptor & descriptor,uint64_t last_action_timestamp,uint32_t read_entry_limit,std::vector<CodeEntry> * new_code_entries)435 bool JITDebugReader::ReadNewCodeEntries(Process& process, const Descriptor& descriptor,
436                                         uint64_t last_action_timestamp, uint32_t read_entry_limit,
437                                         std::vector<CodeEntry>* new_code_entries) {
438   if (process.is_64bit) {
439     return ReadNewCodeEntriesImpl<JITDescriptor64, JITCodeEntry64>(
440         process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
441   }
442   return ReadNewCodeEntriesImpl<JITDescriptor32, JITCodeEntry32>(
443       process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
444 }
445 
446 template <typename DescriptorT, typename CodeEntryT>
ReadNewCodeEntriesImpl(Process & process,const Descriptor & descriptor,uint64_t last_action_timestamp,uint32_t read_entry_limit,std::vector<CodeEntry> * new_code_entries)447 bool JITDebugReader::ReadNewCodeEntriesImpl(Process& process, const Descriptor& descriptor,
448                                             uint64_t last_action_timestamp,
449                                             uint32_t read_entry_limit,
450                                             std::vector<CodeEntry>* new_code_entries) {
451   uint64_t current_entry_addr = descriptor.first_entry_addr;
452   uint64_t prev_entry_addr = 0u;
453   std::unordered_set<uint64_t> entry_addr_set;
454   for (size_t i = 0u; i < read_entry_limit && current_entry_addr != 0u; ++i) {
455     if (entry_addr_set.find(current_entry_addr) != entry_addr_set.end()) {
456       // We enter a loop, which means a broken linked list.
457       return false;
458     }
459     CodeEntryT entry;
460     if (!ReadRemoteMem(process, current_entry_addr, sizeof(entry), &entry)) {
461       return false;
462     }
463     if (entry.prev_addr != prev_entry_addr || !entry.Valid()) {
464       // A broken linked list
465       return false;
466     }
467     if (entry.register_timestamp <= last_action_timestamp) {
468       // The linked list has entries with timestamp in decreasing order. So stop searching
469       // once we hit an entry with timestamp <= last_action_timestmap.
470       break;
471     }
472     CodeEntry code_entry;
473     code_entry.addr = current_entry_addr;
474     code_entry.symfile_addr = entry.symfile_addr;
475     code_entry.symfile_size = entry.symfile_size;
476     code_entry.timestamp = entry.register_timestamp;
477     new_code_entries->push_back(code_entry);
478     entry_addr_set.insert(current_entry_addr);
479     prev_entry_addr = current_entry_addr;
480     current_entry_addr = entry.next_addr;
481   }
482   return true;
483 }
484 
ReadJITCodeDebugInfo(Process & process,const std::vector<CodeEntry> & jit_entries,std::vector<JITDebugInfo> * debug_info)485 void JITDebugReader::ReadJITCodeDebugInfo(Process& process,
486                                           const std::vector<CodeEntry>& jit_entries,
487                                           std::vector<JITDebugInfo>* debug_info) {
488   std::vector<char> data;
489   for (auto& jit_entry : jit_entries) {
490     if (jit_entry.symfile_size > MAX_JIT_SYMFILE_SIZE) {
491       continue;
492     }
493     if (data.size() < jit_entry.symfile_size) {
494       data.resize(jit_entry.symfile_size);
495     }
496     if (!ReadRemoteMem(process, jit_entry.symfile_addr, jit_entry.symfile_size, data.data())) {
497       continue;
498     }
499     if (!IsValidElfFileMagic(data.data(), jit_entry.symfile_size)) {
500       continue;
501     }
502     uint64_t min_addr = UINT64_MAX;
503     uint64_t max_addr = 0;
504     auto callback = [&](const ElfFileSymbol& symbol) {
505       min_addr = std::min(min_addr, symbol.vaddr);
506       max_addr = std::max(max_addr, symbol.vaddr + symbol.len);
507       LOG(VERBOSE) << "JITSymbol " << symbol.name << " at [" << std::hex << symbol.vaddr
508                    << " - " << (symbol.vaddr + symbol.len) << " with size " << symbol.len;
509     };
510     if (ParseSymbolsFromElfFileInMemory(data.data(), jit_entry.symfile_size, callback) !=
511         ElfStatus::NO_ERROR || min_addr >= max_addr) {
512       continue;
513     }
514     std::unique_ptr<TemporaryFile> tmp_file = ScopedTempFiles::CreateTempFile(!keep_symfiles_);
515     if (tmp_file == nullptr || !android::base::WriteFully(tmp_file->fd, data.data(),
516                                                           jit_entry.symfile_size)) {
517       continue;
518     }
519     if (keep_symfiles_) {
520       tmp_file->DoNotRemove();
521     }
522     debug_info->emplace_back(process.pid, jit_entry.timestamp, min_addr, max_addr - min_addr,
523                              tmp_file->path);
524   }
525 }
526 
ReadDexFileDebugInfo(Process & process,const std::vector<CodeEntry> & dex_entries,std::vector<JITDebugInfo> * debug_info)527 void JITDebugReader::ReadDexFileDebugInfo(Process& process,
528                                           const std::vector<CodeEntry>& dex_entries,
529                                           std::vector<JITDebugInfo>* debug_info) {
530   std::vector<ThreadMmap> thread_mmaps;
531   if (!GetThreadMmapsInProcess(process.pid, &thread_mmaps)) {
532     process.died = true;
533     return;
534   }
535   auto comp = [](const ThreadMmap& map, uint64_t addr) {
536     return map.start_addr <= addr;
537   };
538   for (auto& dex_entry : dex_entries) {
539     auto it = std::lower_bound(thread_mmaps.begin(), thread_mmaps.end(),
540                                dex_entry.symfile_addr, comp);
541     if (it == thread_mmaps.begin()) {
542       continue;
543     }
544     --it;
545     if (it->start_addr + it->len < dex_entry.symfile_addr + dex_entry.symfile_size) {
546       continue;
547     }
548     std::string file_path;
549     std::string zip_path;
550     std::string entry_path;
551     if (ParseExtractedInMemoryPath(it->name, &zip_path, &entry_path)) {
552       file_path = GetUrlInApk(zip_path, entry_path);
553     } else {
554       if (!IsRegularFile(it->name)) {
555         // TODO: read dex file only exist in memory?
556         continue;
557       }
558       file_path = it->name;
559     }
560     // Offset of dex file in .vdex file or .apk file.
561     uint64_t dex_file_offset = dex_entry.symfile_addr - it->start_addr + it->pgoff;
562     debug_info->emplace_back(process.pid, dex_entry.timestamp, dex_file_offset, file_path);
563     LOG(VERBOSE) << "DexFile " << file_path << "+" << std::hex << dex_file_offset
564                  << " in map [" << it->start_addr << " - " << (it->start_addr + it->len)
565                  << "] with size " << dex_entry.symfile_size;
566   }
567 }
568 
AddDebugInfo(const std::vector<JITDebugInfo> & debug_info,bool sync_kernel_records)569 bool JITDebugReader::AddDebugInfo(const std::vector<JITDebugInfo>& debug_info,
570                                     bool sync_kernel_records) {
571   if (!debug_info.empty()) {
572     if (sync_with_records_) {
573       for (auto& info : debug_info) {
574         debug_info_q_.push(std::move(info));
575       }
576     } else {
577       return debug_info_callback_(debug_info, sync_kernel_records);
578     }
579   }
580   return true;
581 }
582 
583 }  // namespace simpleperf
584