1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/profiler/libunwindstack_unwinder_android.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <sys/mman.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <string>
10*6777b538SAndroid Build Coastguard Worker #include <vector>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Elf.h"
13*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Error.h"
14*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Maps.h"
15*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Memory.h"
16*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Regs.h"
17*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Unwinder.h"
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/profiler/module_cache.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/profiler/native_unwinder_android.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/profiler/profile_builder.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/base_tracing.h"
26*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
29*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/MachineArm.h"
30*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/RegsArm.h"
31*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
32*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/MachineArm64.h"
33*6777b538SAndroid Build Coastguard Worker #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/RegsArm64.h"
34*6777b538SAndroid Build Coastguard Worker #endif // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker namespace base {
37*6777b538SAndroid Build Coastguard Worker namespace {
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker class NonElfModule : public ModuleCache::Module {
40*6777b538SAndroid Build Coastguard Worker public:
NonElfModule(unwindstack::MapInfo * map_info)41*6777b538SAndroid Build Coastguard Worker explicit NonElfModule(unwindstack::MapInfo* map_info)
42*6777b538SAndroid Build Coastguard Worker : start_(map_info->start()),
43*6777b538SAndroid Build Coastguard Worker size_(map_info->end() - start_),
44*6777b538SAndroid Build Coastguard Worker map_info_name_(map_info->name()) {}
45*6777b538SAndroid Build Coastguard Worker ~NonElfModule() override = default;
46*6777b538SAndroid Build Coastguard Worker
GetBaseAddress() const47*6777b538SAndroid Build Coastguard Worker uintptr_t GetBaseAddress() const override { return start_; }
48*6777b538SAndroid Build Coastguard Worker
GetId() const49*6777b538SAndroid Build Coastguard Worker std::string GetId() const override { return std::string(); }
50*6777b538SAndroid Build Coastguard Worker
GetDebugBasename() const51*6777b538SAndroid Build Coastguard Worker FilePath GetDebugBasename() const override {
52*6777b538SAndroid Build Coastguard Worker return FilePath(map_info_name_);
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker
GetSize() const55*6777b538SAndroid Build Coastguard Worker size_t GetSize() const override { return size_; }
56*6777b538SAndroid Build Coastguard Worker
IsNative() const57*6777b538SAndroid Build Coastguard Worker bool IsNative() const override { return true; }
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker private:
60*6777b538SAndroid Build Coastguard Worker const uintptr_t start_;
61*6777b538SAndroid Build Coastguard Worker const size_t size_;
62*6777b538SAndroid Build Coastguard Worker const std::string map_info_name_;
63*6777b538SAndroid Build Coastguard Worker };
64*6777b538SAndroid Build Coastguard Worker
CreateFromRegisterContext(RegisterContext * thread_context)65*6777b538SAndroid Build Coastguard Worker std::unique_ptr<unwindstack::Regs> CreateFromRegisterContext(
66*6777b538SAndroid Build Coastguard Worker RegisterContext* thread_context) {
67*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
68*6777b538SAndroid Build Coastguard Worker return base::WrapUnique<unwindstack::Regs>(unwindstack::RegsArm::Read(
69*6777b538SAndroid Build Coastguard Worker reinterpret_cast<void*>(&thread_context->arm_r0)));
70*6777b538SAndroid Build Coastguard Worker #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
71*6777b538SAndroid Build Coastguard Worker return base::WrapUnique<unwindstack::Regs>(unwindstack::RegsArm64::Read(
72*6777b538SAndroid Build Coastguard Worker reinterpret_cast<void*>(&thread_context->regs[0])));
73*6777b538SAndroid Build Coastguard Worker #else // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
74*6777b538SAndroid Build Coastguard Worker NOTREACHED();
75*6777b538SAndroid Build Coastguard Worker return nullptr;
76*6777b538SAndroid Build Coastguard Worker #endif // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker
WriteLibunwindstackTraceEventArgs(unwindstack::ErrorCode error_code,std::optional<int> num_frames,perfetto::EventContext & ctx)79*6777b538SAndroid Build Coastguard Worker void WriteLibunwindstackTraceEventArgs(unwindstack::ErrorCode error_code,
80*6777b538SAndroid Build Coastguard Worker std::optional<int> num_frames,
81*6777b538SAndroid Build Coastguard Worker perfetto::EventContext& ctx) {
82*6777b538SAndroid Build Coastguard Worker auto* track_event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
83*6777b538SAndroid Build Coastguard Worker auto* libunwindstack_unwinder = track_event->set_libunwindstack_unwinder();
84*6777b538SAndroid Build Coastguard Worker using ProtoEnum = perfetto::protos::pbzero::LibunwindstackUnwinder::ErrorCode;
85*6777b538SAndroid Build Coastguard Worker libunwindstack_unwinder->set_error_code(static_cast<ProtoEnum>(error_code));
86*6777b538SAndroid Build Coastguard Worker if (num_frames.has_value()) {
87*6777b538SAndroid Build Coastguard Worker libunwindstack_unwinder->set_num_frames(*num_frames);
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker }
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker } // namespace
92*6777b538SAndroid Build Coastguard Worker
LibunwindstackUnwinderAndroid()93*6777b538SAndroid Build Coastguard Worker LibunwindstackUnwinderAndroid::LibunwindstackUnwinderAndroid()
94*6777b538SAndroid Build Coastguard Worker : memory_regions_map_(
95*6777b538SAndroid Build Coastguard Worker static_cast<NativeUnwinderAndroidMemoryRegionsMapImpl*>(
96*6777b538SAndroid Build Coastguard Worker NativeUnwinderAndroid::CreateMemoryRegionsMap(
97*6777b538SAndroid Build Coastguard Worker /*use_updatable_maps=*/false)
98*6777b538SAndroid Build Coastguard Worker .release())) {
99*6777b538SAndroid Build Coastguard Worker TRACE_EVENT_INSTANT(
100*6777b538SAndroid Build Coastguard Worker TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
101*6777b538SAndroid Build Coastguard Worker "LibunwindstackUnwinderAndroid::LibunwindstackUnwinderAndroid");
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker
104*6777b538SAndroid Build Coastguard Worker LibunwindstackUnwinderAndroid::~LibunwindstackUnwinderAndroid() = default;
105*6777b538SAndroid Build Coastguard Worker
InitializeModules()106*6777b538SAndroid Build Coastguard Worker void LibunwindstackUnwinderAndroid::InitializeModules() {}
107*6777b538SAndroid Build Coastguard Worker
CanUnwindFrom(const Frame & current_frame) const108*6777b538SAndroid Build Coastguard Worker bool LibunwindstackUnwinderAndroid::CanUnwindFrom(
109*6777b538SAndroid Build Coastguard Worker const Frame& current_frame) const {
110*6777b538SAndroid Build Coastguard Worker return true;
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker
GetOrCreateJitDebug(unwindstack::ArchEnum arch)113*6777b538SAndroid Build Coastguard Worker unwindstack::JitDebug* LibunwindstackUnwinderAndroid::GetOrCreateJitDebug(
114*6777b538SAndroid Build Coastguard Worker unwindstack::ArchEnum arch) {
115*6777b538SAndroid Build Coastguard Worker if (!jit_debug_) {
116*6777b538SAndroid Build Coastguard Worker jit_debug_ = unwindstack::CreateJitDebug(
117*6777b538SAndroid Build Coastguard Worker arch, memory_regions_map_->memory(), search_libs_);
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker return jit_debug_.get();
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker
GetOrCreateDexFiles(unwindstack::ArchEnum arch)122*6777b538SAndroid Build Coastguard Worker unwindstack::DexFiles* LibunwindstackUnwinderAndroid::GetOrCreateDexFiles(
123*6777b538SAndroid Build Coastguard Worker unwindstack::ArchEnum arch) {
124*6777b538SAndroid Build Coastguard Worker if (!dex_files_) {
125*6777b538SAndroid Build Coastguard Worker dex_files_ = unwindstack::CreateDexFiles(
126*6777b538SAndroid Build Coastguard Worker arch, memory_regions_map_->memory(), search_libs_);
127*6777b538SAndroid Build Coastguard Worker }
128*6777b538SAndroid Build Coastguard Worker return dex_files_.get();
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker
TryUnwind(RegisterContext * thread_context,uintptr_t stack_top,std::vector<Frame> * stack)131*6777b538SAndroid Build Coastguard Worker UnwindResult LibunwindstackUnwinderAndroid::TryUnwind(
132*6777b538SAndroid Build Coastguard Worker RegisterContext* thread_context,
133*6777b538SAndroid Build Coastguard Worker uintptr_t stack_top,
134*6777b538SAndroid Build Coastguard Worker std::vector<Frame>* stack) {
135*6777b538SAndroid Build Coastguard Worker TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
136*6777b538SAndroid Build Coastguard Worker "LibunwindstackUnwinderAndroid::TryUnwind");
137*6777b538SAndroid Build Coastguard Worker // 500 is taken from traced_perf's own limit:
138*6777b538SAndroid Build Coastguard Worker // https://cs.android.com/android/platform/superproject/+/master:external/perfetto/src/profiling/memory/unwinding.cc;l=64;drc=5860970a8606bb48059aa31ee506328286b9bf92
139*6777b538SAndroid Build Coastguard Worker const int kMaxFrames = 500;
140*6777b538SAndroid Build Coastguard Worker
141*6777b538SAndroid Build Coastguard Worker // We use a struct and lambda here to cleanly express the result of an attempt
142*6777b538SAndroid Build Coastguard Worker // to unwind. Sometimes when we fail we can succeed if we reparse maps and so
143*6777b538SAndroid Build Coastguard Worker // we will call |attempt_unwind| twice.
144*6777b538SAndroid Build Coastguard Worker struct UnwindValues {
145*6777b538SAndroid Build Coastguard Worker unwindstack::ErrorCode error_code;
146*6777b538SAndroid Build Coastguard Worker uint64_t warnings;
147*6777b538SAndroid Build Coastguard Worker std::vector<unwindstack::FrameData> frames;
148*6777b538SAndroid Build Coastguard Worker };
149*6777b538SAndroid Build Coastguard Worker
150*6777b538SAndroid Build Coastguard Worker std::unique_ptr<unwindstack::Regs> regs =
151*6777b538SAndroid Build Coastguard Worker CreateFromRegisterContext(thread_context);
152*6777b538SAndroid Build Coastguard Worker DCHECK(regs);
153*6777b538SAndroid Build Coastguard Worker
154*6777b538SAndroid Build Coastguard Worker TRACE_EVENT_BEGIN(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
155*6777b538SAndroid Build Coastguard Worker "libunwindstack::Unwind");
156*6777b538SAndroid Build Coastguard Worker unwindstack::Unwinder unwinder(kMaxFrames, memory_regions_map_->maps(),
157*6777b538SAndroid Build Coastguard Worker regs.get(), memory_regions_map_->memory());
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker unwinder.SetJitDebug(GetOrCreateJitDebug(regs->Arch()));
160*6777b538SAndroid Build Coastguard Worker unwinder.SetDexFiles(GetOrCreateDexFiles(regs->Arch()));
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker unwinder.Unwind(/*initial_map_names_to_skip=*/nullptr,
163*6777b538SAndroid Build Coastguard Worker /*map_suffixes_to_ignore=*/nullptr);
164*6777b538SAndroid Build Coastguard Worker TRACE_EVENT_END(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"));
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker // Currently libunwindstack doesn't support warnings.
167*6777b538SAndroid Build Coastguard Worker UnwindValues values =
168*6777b538SAndroid Build Coastguard Worker UnwindValues{unwinder.LastErrorCode(), /*unwinder.warnings()*/ 0,
169*6777b538SAndroid Build Coastguard Worker unwinder.ConsumeFrames()};
170*6777b538SAndroid Build Coastguard Worker
171*6777b538SAndroid Build Coastguard Worker if (values.error_code != unwindstack::ERROR_NONE) {
172*6777b538SAndroid Build Coastguard Worker TRACE_EVENT_INSTANT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
173*6777b538SAndroid Build Coastguard Worker "Libunwindstack Failure",
174*6777b538SAndroid Build Coastguard Worker [&values](perfetto::EventContext& ctx) {
175*6777b538SAndroid Build Coastguard Worker WriteLibunwindstackTraceEventArgs(
176*6777b538SAndroid Build Coastguard Worker values.error_code, values.frames.size(), ctx);
177*6777b538SAndroid Build Coastguard Worker });
178*6777b538SAndroid Build Coastguard Worker }
179*6777b538SAndroid Build Coastguard Worker if (values.frames.empty()) {
180*6777b538SAndroid Build Coastguard Worker return UnwindResult::kCompleted;
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker
183*6777b538SAndroid Build Coastguard Worker // The list of frames provided by Libunwindstack's Unwind() contains the
184*6777b538SAndroid Build Coastguard Worker // executing frame. The executing frame is also added by
185*6777b538SAndroid Build Coastguard Worker // StackSamplerImpl::WalkStack(). Ignore the frame from the latter to avoid
186*6777b538SAndroid Build Coastguard Worker // duplication. In case a java method was being interpreted libunwindstack
187*6777b538SAndroid Build Coastguard Worker // adds a dummy frame for it and then writes the corresponding native frame.
188*6777b538SAndroid Build Coastguard Worker // In such a scenario we want to prefer the frames produced by
189*6777b538SAndroid Build Coastguard Worker // libunwindstack.
190*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(stack->size(), 1u);
191*6777b538SAndroid Build Coastguard Worker stack->clear();
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Worker for (const unwindstack::FrameData& frame : values.frames) {
194*6777b538SAndroid Build Coastguard Worker const ModuleCache::Module* module =
195*6777b538SAndroid Build Coastguard Worker module_cache()->GetModuleForAddress(frame.pc);
196*6777b538SAndroid Build Coastguard Worker if (module == nullptr && frame.map_info != nullptr) {
197*6777b538SAndroid Build Coastguard Worker // Try searching for the module with same module start.
198*6777b538SAndroid Build Coastguard Worker module = module_cache()->GetModuleForAddress(frame.map_info->start());
199*6777b538SAndroid Build Coastguard Worker if (module == nullptr) {
200*6777b538SAndroid Build Coastguard Worker auto module_for_caching =
201*6777b538SAndroid Build Coastguard Worker std::make_unique<NonElfModule>(frame.map_info.get());
202*6777b538SAndroid Build Coastguard Worker module = module_for_caching.get();
203*6777b538SAndroid Build Coastguard Worker module_cache()->AddCustomNativeModule(std::move(module_for_caching));
204*6777b538SAndroid Build Coastguard Worker }
205*6777b538SAndroid Build Coastguard Worker if (frame.pc < frame.map_info->start() ||
206*6777b538SAndroid Build Coastguard Worker frame.pc >= frame.map_info->end()) {
207*6777b538SAndroid Build Coastguard Worker TRACE_EVENT_INSTANT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
208*6777b538SAndroid Build Coastguard Worker "PC out of map range",
209*6777b538SAndroid Build Coastguard Worker [&values](perfetto::EventContext& ctx) {
210*6777b538SAndroid Build Coastguard Worker WriteLibunwindstackTraceEventArgs(
211*6777b538SAndroid Build Coastguard Worker values.error_code, std::nullopt, ctx);
212*6777b538SAndroid Build Coastguard Worker });
213*6777b538SAndroid Build Coastguard Worker }
214*6777b538SAndroid Build Coastguard Worker }
215*6777b538SAndroid Build Coastguard Worker stack->emplace_back(frame.pc, module, frame.function_name);
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker return UnwindResult::kCompleted;
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker } // namespace base
221