From e5defe1549a03dcd37860728789d990cf45e7405 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 23 Mar 2022 15:55:50 -0700 Subject: simpleperf: read jit descriptor and dex descriptor separately. Current code relies on jit descriptor and dex descriptor near each other in data section, and reads them together. But this assumption isn't true in hwasan build. So switch to read jit descriptor and dex descriptor separately. Also change to decide if a process is 64bit by checking the elf file type of libart.so. Bug: 226250109 Test: run simpleperf_unit_test Change-Id: I9d0073427e14fc4f476af94f43c47c10d5633987 --- simpleperf/JITDebugReader.cpp | 78 +++++++++++++++++++++++-------------------- simpleperf/JITDebugReader.h | 27 +++++++-------- 2 files changed, 54 insertions(+), 51 deletions(-) diff --git a/simpleperf/JITDebugReader.cpp b/simpleperf/JITDebugReader.cpp index 52db2959..28058940 100644 --- a/simpleperf/JITDebugReader.cpp +++ b/simpleperf/JITDebugReader.cpp @@ -411,17 +411,15 @@ bool JITDebugReader::InitializeProcess(Process& process) { if (art_lib_path.empty()) { return false; } - process.is_64bit = art_lib_path.find("lib64") != std::string::npos; // 2. Read libart.so to find the addresses of __jit_debug_descriptor and __dex_debug_descriptor. - const DescriptorsLocation* location = GetDescriptorsLocation(art_lib_path, process.is_64bit); + const DescriptorsLocation* location = GetDescriptorsLocation(art_lib_path); if (location == nullptr) { return false; } - process.descriptors_addr = location->relative_addr + min_vaddr_in_memory; - process.descriptors_size = location->size; - process.jit_descriptor_offset = location->jit_descriptor_offset; - process.dex_descriptor_offset = location->dex_descriptor_offset; + process.is_64bit = location->is_64bit; + process.jit_descriptor_addr = location->jit_descriptor_addr + min_vaddr_in_memory; + process.dex_descriptor_addr = location->dex_descriptor_addr + min_vaddr_in_memory; for (auto& map : thread_mmaps) { if (StartsWith(map.name, kJITZygoteCacheMmapPrefix)) { @@ -434,10 +432,10 @@ bool JITDebugReader::InitializeProcess(Process& process) { } const JITDebugReader::DescriptorsLocation* JITDebugReader::GetDescriptorsLocation( - const std::string& art_lib_path, bool is_64bit) { + const std::string& art_lib_path) { auto it = descriptors_location_cache_.find(art_lib_path); if (it != descriptors_location_cache_.end()) { - return it->second.relative_addr == 0u ? nullptr : &it->second; + return it->second.jit_descriptor_addr == 0u ? nullptr : &it->second; } DescriptorsLocation& location = descriptors_location_cache_[art_lib_path]; @@ -469,18 +467,9 @@ const JITDebugReader::DescriptorsLocation* JITDebugReader::GetDescriptorsLocatio if (jit_addr == 0u || dex_addr == 0u) { return nullptr; } - location.relative_addr = std::min(jit_addr, dex_addr); - location.size = std::max(jit_addr, dex_addr) + - (is_64bit ? sizeof(JITDescriptor64) : sizeof(JITDescriptor32)) - - location.relative_addr; - if (location.size >= 4096u) { - PLOG(WARNING) << "The descriptors_size is unexpected large: " << location.size; - } - if (descriptors_buf_.size() < location.size) { - descriptors_buf_.resize(location.size); - } - location.jit_descriptor_offset = jit_addr - location.relative_addr; - location.dex_descriptor_offset = dex_addr - location.relative_addr; + location.is_64bit = elf->Is64Bit(); + location.jit_descriptor_addr = jit_addr; + location.dex_descriptor_addr = dex_addr; return &location; } @@ -505,14 +494,40 @@ bool JITDebugReader::ReadRemoteMem(Process& process, uint64_t remote_addr, uint6 bool JITDebugReader::ReadDescriptors(Process& process, Descriptor* jit_descriptor, Descriptor* dex_descriptor) { - if (!ReadRemoteMem(process, process.descriptors_addr, process.descriptors_size, - descriptors_buf_.data())) { + if (process.is_64bit) { + return ReadDescriptorsImpl(process, jit_descriptor, dex_descriptor); + } + return ReadDescriptorsImpl(process, jit_descriptor, dex_descriptor); +} + +template +bool JITDebugReader::ReadDescriptorsImpl(Process& process, Descriptor* jit_descriptor, + Descriptor* dex_descriptor) { + DescriptorT raw_jit_descriptor; + DescriptorT raw_dex_descriptor; + iovec local_iovs[2]; + local_iovs[0].iov_base = &raw_jit_descriptor; + local_iovs[0].iov_len = sizeof(DescriptorT); + local_iovs[1].iov_base = &raw_dex_descriptor; + local_iovs[1].iov_len = sizeof(DescriptorT); + iovec remote_iovs[2]; + remote_iovs[0].iov_base = + reinterpret_cast(static_cast(process.jit_descriptor_addr)); + remote_iovs[0].iov_len = sizeof(DescriptorT); + remote_iovs[1].iov_base = + reinterpret_cast(static_cast(process.dex_descriptor_addr)); + remote_iovs[1].iov_len = sizeof(DescriptorT); + ssize_t result = process_vm_readv(process.pid, local_iovs, 2, remote_iovs, 2, 0); + if (static_cast(result) != sizeof(DescriptorT) * 2) { + PLOG(DEBUG) << "ReadDescriptor(pid " << process.pid << ", jit_addr " << std::hex + << process.jit_descriptor_addr << ", dex_addr " << process.dex_descriptor_addr + << ") failed"; + process.died = true; return false; } - if (!LoadDescriptor(process.is_64bit, &descriptors_buf_[process.jit_descriptor_offset], - jit_descriptor) || - !LoadDescriptor(process.is_64bit, &descriptors_buf_[process.dex_descriptor_offset], - dex_descriptor)) { + + if (!ParseDescriptor(raw_jit_descriptor, jit_descriptor) || + !ParseDescriptor(raw_dex_descriptor, dex_descriptor)) { return false; } jit_descriptor->type = DescriptorType::kJIT; @@ -520,17 +535,8 @@ bool JITDebugReader::ReadDescriptors(Process& process, Descriptor* jit_descripto return true; } -bool JITDebugReader::LoadDescriptor(bool is_64bit, const char* data, Descriptor* descriptor) { - if (is_64bit) { - return LoadDescriptorImpl(data, descriptor); - } - return LoadDescriptorImpl(data, descriptor); -} - template -bool JITDebugReader::LoadDescriptorImpl(const char* data, Descriptor* descriptor) { - DescriptorT raw_descriptor; - MoveFromBinaryFormat(raw_descriptor, data); +bool JITDebugReader::ParseDescriptor(const DescriptorT& raw_descriptor, Descriptor* descriptor) { if (!raw_descriptor.Valid()) { return false; } diff --git a/simpleperf/JITDebugReader.h b/simpleperf/JITDebugReader.h index 72f3790b..b9e984d5 100644 --- a/simpleperf/JITDebugReader.h +++ b/simpleperf/JITDebugReader.h @@ -162,13 +162,10 @@ class JITDebugReader { bool initialized = false; bool died = false; bool is_64bit = false; - // The jit descriptor and dex descriptor can be read in one process_vm_readv() call. - uint64_t descriptors_addr = 0; - uint64_t descriptors_size = 0; - // offset relative to descriptors_addr - uint64_t jit_descriptor_offset = 0; - // offset relative to descriptors_addr - uint64_t dex_descriptor_offset = 0; + // remote addr of jit descriptor + uint64_t jit_descriptor_addr = 0; + // remote addr of dex descriptor + uint64_t dex_descriptor_addr = 0; // The state we know about the remote jit debug descriptor. Descriptor last_jit_descriptor; @@ -181,10 +178,9 @@ class JITDebugReader { // The location of descriptors in libart.so. struct DescriptorsLocation { - uint64_t relative_addr = 0; - uint64_t size = 0; - uint64_t jit_descriptor_offset = 0; - uint64_t dex_descriptor_offset = 0; + bool is_64bit = false; + uint64_t jit_descriptor_addr = 0; + uint64_t dex_descriptor_addr = 0; }; bool ReadProcess(Process& process, std::vector* debug_info); @@ -192,12 +188,14 @@ class JITDebugReader { std::vector* debug_info); bool IsDescriptorChanged(Process& process, Descriptor& old_descriptor); bool InitializeProcess(Process& process); - const DescriptorsLocation* GetDescriptorsLocation(const std::string& art_lib_path, bool is_64bit); + const DescriptorsLocation* GetDescriptorsLocation(const std::string& art_lib_path); bool ReadRemoteMem(Process& process, uint64_t remote_addr, uint64_t size, void* data); bool ReadDescriptors(Process& process, Descriptor* jit_descriptor, Descriptor* dex_descriptor); - bool LoadDescriptor(bool is_64bit, const char* data, Descriptor* descriptor); template - bool LoadDescriptorImpl(const char* data, Descriptor* descriptor); + bool ReadDescriptorsImpl(Process& process, Descriptor* jit_descriptor, + Descriptor* dex_descriptor); + template + bool ParseDescriptor(const DescriptorT& raw_descriptor, Descriptor* descriptor); bool ReadNewCodeEntries(Process& process, const Descriptor& descriptor, uint64_t last_action_timestamp, uint32_t read_entry_limit, @@ -226,7 +224,6 @@ class JITDebugReader { // All monitored processes std::unordered_map processes_; std::unordered_map descriptors_location_cache_; - std::vector descriptors_buf_; std::priority_queue, std::greater> debug_info_q_; -- cgit v1.2.3