// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/profiler/native_unwinder_android.h" #include #include #include #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Elf.h" #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Memory.h" #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Regs.h" #include "base/memory/ptr_util.h" #include "base/notreached.h" #include "base/profiler/module_cache.h" #include "base/profiler/profile_builder.h" #include "build/build_config.h" #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/MachineArm.h" #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/RegsArm.h" #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS) #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/MachineArm64.h" #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/RegsArm64.h" #endif // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) namespace base { namespace { class NonElfModule : public ModuleCache::Module { public: NonElfModule(unwindstack::MapInfo* map_info) : start_(map_info->start), size_(map_info->end - start_), map_info_name_(map_info->name) {} ~NonElfModule() override = default; uintptr_t GetBaseAddress() const override { return start_; } std::string GetId() const override { return std::string(); } FilePath GetDebugBasename() const override { return FilePath(map_info_name_); } // Gets the size of the module. size_t GetSize() const override { return size_; } // True if this is a native module. bool IsNative() const override { return true; } private: const uintptr_t start_; const size_t size_; const std::string map_info_name_; }; std::unique_ptr CreateFromRegisterContext( RegisterContext* thread_context) { #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) return WrapUnique(unwindstack::RegsArm::Read( reinterpret_cast(&thread_context->arm_r0))); #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS) return WrapUnique(unwindstack::RegsArm64::Read( reinterpret_cast(&thread_context->regs[0]))); #else // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) NOTREACHED(); return nullptr; #endif // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) } void CopyToRegisterContext(unwindstack::Regs* regs, RegisterContext* thread_context) { #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) memcpy(reinterpret_cast(&thread_context->arm_r0), regs->RawData(), unwindstack::ARM_REG_LAST * sizeof(uintptr_t)); #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS) memcpy(reinterpret_cast(&thread_context->regs[0]), regs->RawData(), unwindstack::ARM64_REG_LAST * sizeof(uintptr_t)); #else // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) NOTREACHED(); #endif // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) } } // namespace UnwindStackMemoryAndroid::UnwindStackMemoryAndroid(uintptr_t stack_ptr, uintptr_t stack_top) : stack_ptr_(stack_ptr), stack_top_(stack_top) { DCHECK_LE(stack_ptr_, stack_top_); } UnwindStackMemoryAndroid::~UnwindStackMemoryAndroid() = default; size_t UnwindStackMemoryAndroid::Read(uint64_t addr, void* dst, size_t size) { if (addr < stack_ptr_) return 0; if (size >= stack_top_ || addr > stack_top_ - size) return 0; memcpy(dst, reinterpret_cast(addr), size); return size; } // static std::unique_ptr NativeUnwinderAndroid::CreateMaps() { auto maps = std::make_unique(); if (maps->Parse()) return maps; return nullptr; } // static std::unique_ptr NativeUnwinderAndroid::CreateProcessMemory() { return unwindstack::Memory::CreateLocalProcessMemory(); } NativeUnwinderAndroid::NativeUnwinderAndroid( unwindstack::Maps* memory_regions_map, unwindstack::Memory* process_memory, uintptr_t exclude_module_with_base_address) : memory_regions_map_(memory_regions_map), process_memory_(process_memory), exclude_module_with_base_address_(exclude_module_with_base_address) {} NativeUnwinderAndroid::~NativeUnwinderAndroid() { if (module_cache()) module_cache()->UnregisterAuxiliaryModuleProvider(this); } void NativeUnwinderAndroid::InitializeModules() { module_cache()->RegisterAuxiliaryModuleProvider(this); } bool NativeUnwinderAndroid::CanUnwindFrom(const Frame& current_frame) const { return current_frame.module && current_frame.module->IsNative() && current_frame.module->GetBaseAddress() != exclude_module_with_base_address_; } UnwindResult NativeUnwinderAndroid::TryUnwind(RegisterContext* thread_context, uintptr_t stack_top, std::vector* stack) const { auto regs = CreateFromRegisterContext(thread_context); DCHECK(regs); unwindstack::ArchEnum arch = regs->Arch(); do { uint64_t cur_pc = regs->pc(); uint64_t cur_sp = regs->sp(); unwindstack::MapInfo* map_info = memory_regions_map_->Find(cur_pc); if (map_info == nullptr || map_info->flags & unwindstack::MAPS_FLAGS_DEVICE_MAP) { break; } unwindstack::Elf* elf = map_info->GetElf( {process_memory_.get(), [](unwindstack::Memory*) {}}, arch); if (!elf->valid()) break; UnwindStackMemoryAndroid stack_memory(cur_sp, stack_top); uintptr_t rel_pc = elf->GetRelPc(cur_pc, map_info); bool finished = false; bool stepped = elf->StepIfSignalHandler(rel_pc, regs.get(), &stack_memory) || elf->Step(rel_pc, regs.get(), &stack_memory, &finished); if (stepped && finished) return UnwindResult::kCompleted; if (!stepped) { // Stepping failed. Try unwinding using return address. if (stack->size() == 1) { if (!regs->SetPcFromReturnAddress(&stack_memory)) return UnwindResult::kAborted; } else { break; } } // If the pc and sp didn't change, then consider everything stopped. if (cur_pc == regs->pc() && cur_sp == regs->sp()) return UnwindResult::kAborted; // Exclusive range of expected stack pointer values after the unwind. struct { uintptr_t start; uintptr_t end; } expected_stack_pointer_range = {static_cast(cur_sp), stack_top}; if (regs->sp() < expected_stack_pointer_range.start || regs->sp() >= expected_stack_pointer_range.end) { return UnwindResult::kAborted; } if (regs->dex_pc() != 0) { // Add a frame to represent the dex file. EmitDexFrame(regs->dex_pc(), stack); // Clear the dex pc so that we don't repeat this frame later. regs->set_dex_pc(0); } // Add the frame to |stack|. Must use GetModuleForAddress rather than // GetExistingModuleForAddress because the unwound-to address may be in a // module associated with a different unwinder. const ModuleCache::Module* module = module_cache()->GetModuleForAddress(regs->pc()); stack->emplace_back(regs->pc(), module); } while (CanUnwindFrom(stack->back())); // Restore registers necessary for further unwinding in |thread_context|. CopyToRegisterContext(regs.get(), thread_context); return UnwindResult::kUnrecognizedFrame; } std::unique_ptr NativeUnwinderAndroid::TryCreateModuleForAddress(uintptr_t address) { unwindstack::MapInfo* map_info = memory_regions_map_->Find(address); if (map_info == nullptr || !(map_info->flags & PROT_EXEC) || map_info->flags & unwindstack::MAPS_FLAGS_DEVICE_MAP) { return nullptr; } return std::make_unique(map_info); } void NativeUnwinderAndroid::EmitDexFrame(uintptr_t dex_pc, std::vector* stack) const { const ModuleCache::Module* module = module_cache()->GetExistingModuleForAddress(dex_pc); if (!module) { // The region containing |dex_pc| may not be in module_cache() since it's // usually not executable (.dex file). Since non-executable regions // are used much less commonly, it's lazily added here instead of from // AddInitialModulesFromMaps(). unwindstack::MapInfo* map_info = memory_regions_map_->Find(dex_pc); if (map_info) { auto new_module = std::make_unique(map_info); module = new_module.get(); module_cache()->AddCustomNativeModule(std::move(new_module)); } } stack->emplace_back(dex_pc, module); } } // namespace base