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