/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__BIONIC__) #include static constexpr int kThreadUnwindSignal = BIONIC_SIGNAL_BACKTRACE; #else #include static int kThreadUnwindSignal = SIGRTMIN; #endif namespace unwindstack { void AndroidUnwinderData::DemangleFunctionNames() { for (auto& frame : frames) { frame.function_name = DemangleNameIfNeeded(frame.function_name); } } std::string AndroidUnwinderData::GetErrorString() { std::string error_msg(GetErrorCodeString(error.code)); if (error.address != 0) { error_msg += android::base::StringPrintf(" at address 0x%" PRIx64, error.address); } return error_msg; } AndroidUnwinder* AndroidUnwinder::Create(pid_t pid) { if (pid == getpid()) { return new AndroidLocalUnwinder; } else { return new AndroidRemoteUnwinder(pid); } } bool AndroidUnwinder::Initialize(ErrorData& error) { // Android stores the jit and dex file location only in the library // libart.so or libartd.so. static std::vector search_libs [[clang::no_destroy]] = {"libart.so", "libartd.so"}; std::call_once(initialize_, [this, &error]() { if (!InternalInitialize(error)) { initialize_status_ = false; return; } jit_debug_ = CreateJitDebug(arch_, process_memory_, search_libs); #if defined(DEXFILE_SUPPORT) dex_files_ = CreateDexFiles(arch_, process_memory_, search_libs); #endif initialize_status_ = true; }); return initialize_status_; } std::string AndroidUnwinder::FormatFrame(const FrameData& frame) const { if (arch_ == ARCH_UNKNOWN) { return ""; } return Unwinder::FormatFrame(arch_, frame); } bool AndroidLocalUnwinder::InternalInitialize(ErrorData& error) { arch_ = Regs::CurrentArch(); maps_.reset(new LocalUpdatableMaps); if (!maps_->Parse()) { error.code = ERROR_MAPS_PARSE; return false; } if (process_memory_ == nullptr) { process_memory_ = Memory::CreateProcessMemoryThreadCached(getpid()); } return true; } FrameData AndroidUnwinder::BuildFrameFromPcOnly(uint64_t pc) { return Unwinder::BuildFrameFromPcOnly(pc, arch_, maps_.get(), jit_debug_.get(), process_memory_, true); } bool AndroidUnwinder::Unwind(AndroidUnwinderData& data) { return Unwind(std::nullopt, data); } bool AndroidUnwinder::Unwind(std::optional tid, AndroidUnwinderData& data) { if (!Initialize(data.error)) { return false; } return InternalUnwind(tid, data); } bool AndroidUnwinder::Unwind(void* ucontext, AndroidUnwinderData& data) { if (ucontext == nullptr) { data.error.code = ERROR_INVALID_PARAMETER; return false; } if (!Initialize(data.error)) { return false; } std::unique_ptr regs(Regs::CreateFromUcontext(arch_, ucontext)); return Unwind(regs.get(), data); } bool AndroidUnwinder::Unwind(Regs* initial_regs, AndroidUnwinderData& data) { if (initial_regs == nullptr) { data.error.code = ERROR_INVALID_PARAMETER; return false; } if (!Initialize(data.error)) { return false; } if (arch_ != initial_regs->Arch()) { data.error.code = ERROR_BAD_ARCH; return false; } std::unique_ptr regs(initial_regs->Clone()); if (data.saved_initial_regs) { (*data.saved_initial_regs).reset(initial_regs->Clone()); } Unwinder unwinder(data.max_frames.value_or(max_frames_), maps_.get(), regs.get(), process_memory_); unwinder.SetJitDebug(jit_debug_.get()); unwinder.SetDexFiles(dex_files_.get()); unwinder.Unwind(data.show_all_frames ? nullptr : &initial_map_names_to_skip_, &map_suffixes_to_ignore_); data.frames = unwinder.ConsumeFrames(); data.error = unwinder.LastError(); return data.frames.size() != 0; } bool AndroidLocalUnwinder::InternalUnwind(std::optional tid, AndroidUnwinderData& data) { if (!tid) { tid = android::base::GetThreadId(); } if (static_cast(*tid) == android::base::GetThreadId()) { // Unwind current thread. std::unique_ptr regs(Regs::CreateFromLocal()); RegsGetLocal(regs.get()); return AndroidUnwinder::Unwind(regs.get(), data); } ThreadUnwinder unwinder(data.max_frames.value_or(max_frames_), maps_.get(), process_memory_); unwinder.SetJitDebug(jit_debug_.get()); unwinder.SetDexFiles(dex_files_.get()); std::unique_ptr* initial_regs = nullptr; if (data.saved_initial_regs) { initial_regs = &data.saved_initial_regs.value(); } unwinder.UnwindWithSignal(kThreadUnwindSignal, *tid, initial_regs, data.show_all_frames ? nullptr : &initial_map_names_to_skip_, &map_suffixes_to_ignore_); data.frames = unwinder.ConsumeFrames(); data.error = unwinder.LastError(); return data.frames.size() != 0; } bool AndroidRemoteUnwinder::InternalInitialize(ErrorData& error) { if (arch_ == ARCH_UNKNOWN) { arch_ = Regs::RemoteGetArch(pid_, &error.code); } if (arch_ == ARCH_UNKNOWN) { return false; } maps_.reset(new RemoteMaps(pid_)); if (!maps_->Parse()) { error.code = ERROR_MAPS_PARSE; return false; } if (process_memory_ == nullptr) { process_memory_ = Memory::CreateProcessMemoryCached(pid_); } return true; } bool AndroidRemoteUnwinder::InternalUnwind(std::optional tid, AndroidUnwinderData& data) { if (!tid) { tid = pid_; } std::unique_ptr regs(Regs::RemoteGet(*tid, &data.error.code)); if (regs == nullptr) { return false; } return AndroidUnwinder::Unwind(regs.get(), data); } } // namespace unwindstack