blob: 24e991ed706e4ca9b348d05414659bef2792ce6c [file] [log] [blame]
/*
* 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 <inttypes.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include <android-base/stringprintf.h>
#include <android-base/threads.h>
#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Arch.h>
#include <unwindstack/DexFiles.h>
#include <unwindstack/Error.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>
#include <unwindstack/Unwinder.h>
#if defined(__BIONIC__)
#include <bionic/reserved_signals.h>
static constexpr int kThreadUnwindSignal = BIONIC_SIGNAL_BACKTRACE;
#else
#include <signal.h>
static int kThreadUnwindSignal = SIGRTMIN;
#endif
// Use the demangler from libc++.
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
namespace unwindstack {
void AndroidUnwinderData::DemangleFunctionNames() {
for (auto& frame : frames) {
char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr);
if (demangled_name != nullptr) {
frame.function_name = demangled_name;
free(demangled_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<std::string> search_libs [[clang::no_destroy]] = {"libart.so", "libartd.so"};
bool initialize = true;
std::call_once(initialize_, [this, &initialize, &error]() {
initialize = InternalInitialize(error);
if (!initialize) {
return;
}
jit_debug_ = CreateJitDebug(arch_, process_memory_, search_libs);
#if defined(DEXFILE_SUPPORT)
dex_files_ = CreateDexFiles(arch_, process_memory_, search_libs);
#endif
});
return initialize;
}
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<pid_t> 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;
}
std::unique_ptr<Regs> 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> 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<pid_t> tid, AndroidUnwinderData& data) {
if (!tid) {
*tid = android::base::GetThreadId();
}
if (static_cast<uint64_t>(*tid) == android::base::GetThreadId()) {
// Unwind current thread.
std::unique_ptr<Regs> 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<Regs>* 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_);
}
if (arch_ == ARCH_UNKNOWN) {
error.code = ERROR_BAD_ARCH;
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<pid_t> tid, AndroidUnwinderData& data) {
if (!tid) {
*tid = pid_;
}
std::unique_ptr<Regs> regs(Regs::RemoteGet(*tid));
return AndroidUnwinder::Unwind(regs.get(), data);
}
} // namespace unwindstack