#include "base/profiler/libunwindstack_unwinder_android.h"
#include <sys/mman.h>
#include <string>
#include <vector>
#include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Elf.h"
#include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Error.h"
#include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Maps.h"
#include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Memory.h"
#include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Regs.h"
#include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Unwinder.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/profiler/module_cache.h"
#include "base/profiler/native_unwinder_android.h"
#include "base/profiler/profile_builder.h"
#include "base/trace_event/base_tracing.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
namespace base {
namespace {
class NonElfModule : public ModuleCache::Module {
public:
explicit 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_);
}
size_t GetSize() const override { return size_; }
bool IsNative() const override { return true; }
private:
const uintptr_t start_;
const size_t size_;
const std::string map_info_name_;
};
std::unique_ptr<unwindstack::Regs> CreateFromRegisterContext(
RegisterContext* thread_context) {
#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
return base::WrapUnique<unwindstack::Regs>(unwindstack::RegsArm::Read(
reinterpret_cast<void*>(&thread_context->arm_r0)));
#elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
return base::WrapUnique<unwindstack::Regs>(unwindstack::RegsArm64::Read(
reinterpret_cast<void*>(&thread_context->regs[0])));
#else
NOTREACHED();
return nullptr;
#endif
}
}
LibunwindstackUnwinderAndroid::LibunwindstackUnwinderAndroid()
: memory_regions_map_(NativeUnwinderAndroid::CreateMemoryRegionsMap(
true)),
process_memory_(std::shared_ptr<unwindstack::Memory>(
memory_regions_map_->TakeMemory().release())) {
TRACE_EVENT_INSTANT(
TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
"LibunwindstackUnwinderAndroid::LibunwindstackUnwinderAndroid");
}
LibunwindstackUnwinderAndroid::~LibunwindstackUnwinderAndroid() = default;
void LibunwindstackUnwinderAndroid::InitializeModules() {}
bool LibunwindstackUnwinderAndroid::CanUnwindFrom(
const Frame& current_frame) const {
return true;
}
unwindstack::JitDebug* LibunwindstackUnwinderAndroid::GetOrCreateJitDebug(
unwindstack::ArchEnum arch) {
if (!jit_debug_) {
jit_debug_ =
unwindstack::CreateJitDebug(arch, process_memory_, search_libs_);
}
return jit_debug_.get();
}
unwindstack::DexFiles* LibunwindstackUnwinderAndroid::GetOrCreateDexFiles(
unwindstack::ArchEnum arch) {
if (!dex_files_) {
dex_files_ =
unwindstack::CreateDexFiles(arch, process_memory_, search_libs_);
}
return dex_files_.get();
}
UnwindResult LibunwindstackUnwinderAndroid::TryUnwind(
RegisterContext* thread_context,
uintptr_t stack_top,
std::vector<Frame>* stack) {
TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
"LibunwindstackUnwinderAndroid::TryUnwind");
const int kMaxFrames = 500;
struct UnwindValues {
unwindstack::ErrorCode error_code;
uint64_t warnings;
std::vector<unwindstack::FrameData> frames;
};
std::unique_ptr<unwindstack::Regs> regs =
CreateFromRegisterContext(thread_context);
DCHECK(regs);
unwindstack::Unwinder unwinder(kMaxFrames, memory_regions_map_->GetMaps(),
regs.get(), process_memory_);
unwinder.SetJitDebug(GetOrCreateJitDebug(regs->Arch()));
unwinder.SetDexFiles(GetOrCreateDexFiles(regs->Arch()));
unwinder.Unwind(nullptr,
nullptr);
UnwindValues values =
UnwindValues{unwinder.LastErrorCode(), 0,
unwinder.ConsumeFrames()};
if (values.error_code != unwindstack::ERROR_NONE) {
TRACE_EVENT_INSTANT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
"TryUnwind Failure", "error", values.error_code,
"warning", values.warnings, "num_frames",
values.frames.size());
}
if (values.frames.empty()) {
return UnwindResult::kCompleted;
}
DCHECK_EQ(stack->size(), 1u);
stack->clear();
for (const unwindstack::FrameData& frame : values.frames) {
const ModuleCache::Module* module =
module_cache()->GetModuleForAddress(frame.pc);
if (module == nullptr && frame.map_info != nullptr) {
auto module_for_caching =
std::make_unique<NonElfModule>(frame.map_info.get());
module = module_for_caching.get();
module_cache()->AddCustomNativeModule(std::move(module_for_caching));
}
stack->emplace_back(frame.pc, module, frame.function_name);
}
return UnwindResult::kCompleted;
}
}