• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #endif  // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
76 }
77 
WriteLibunwindstackTraceEventArgs(unwindstack::ErrorCode error_code,std::optional<int> num_frames,perfetto::EventContext & ctx)78 void WriteLibunwindstackTraceEventArgs(unwindstack::ErrorCode error_code,
79                                        std::optional<int> num_frames,
80                                        perfetto::EventContext& ctx) {
81   auto* track_event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
82   auto* libunwindstack_unwinder = track_event->set_libunwindstack_unwinder();
83   using ProtoEnum = perfetto::protos::pbzero::LibunwindstackUnwinder::ErrorCode;
84   libunwindstack_unwinder->set_error_code(static_cast<ProtoEnum>(error_code));
85   if (num_frames.has_value()) {
86     libunwindstack_unwinder->set_num_frames(*num_frames);
87   }
88 }
89 
IsJavaModule(const base::ModuleCache::Module * module)90 bool IsJavaModule(const base::ModuleCache::Module* module) {
91   if (!module) {
92     return false;
93   }
94 
95   const auto path = module->GetDebugBasename();
96   const std::string& debug_basename = path.value();
97 
98   return debug_basename.find("chrome.apk") != std::string::npos ||
99          debug_basename.find("base.apk") != std::string::npos;
100 }
101 
102 }  // namespace
103 
LibunwindstackUnwinderAndroid()104 LibunwindstackUnwinderAndroid::LibunwindstackUnwinderAndroid()
105     : memory_regions_map_(
106           static_cast<NativeUnwinderAndroidMemoryRegionsMapImpl*>(
107               NativeUnwinderAndroid::CreateMemoryRegionsMap(
108                   /*use_updatable_maps=*/false)
109                   .release())) {
110   TRACE_EVENT_INSTANT(
111       TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
112       "LibunwindstackUnwinderAndroid::LibunwindstackUnwinderAndroid");
113 }
114 
115 LibunwindstackUnwinderAndroid::~LibunwindstackUnwinderAndroid() = default;
116 
InitializeModules()117 void LibunwindstackUnwinderAndroid::InitializeModules() {}
118 
CanUnwindFrom(const Frame & current_frame) const119 bool LibunwindstackUnwinderAndroid::CanUnwindFrom(
120     const Frame& current_frame) const {
121   return true;
122 }
123 
GetOrCreateJitDebug(unwindstack::ArchEnum arch)124 unwindstack::JitDebug* LibunwindstackUnwinderAndroid::GetOrCreateJitDebug(
125     unwindstack::ArchEnum arch) {
126   if (!jit_debug_) {
127     jit_debug_ = unwindstack::CreateJitDebug(
128         arch, memory_regions_map_->memory(), search_libs_);
129   }
130   return jit_debug_.get();
131 }
132 
GetOrCreateDexFiles(unwindstack::ArchEnum arch)133 unwindstack::DexFiles* LibunwindstackUnwinderAndroid::GetOrCreateDexFiles(
134     unwindstack::ArchEnum arch) {
135   if (!dex_files_) {
136     dex_files_ = unwindstack::CreateDexFiles(
137         arch, memory_regions_map_->memory(), search_libs_);
138   }
139   return dex_files_.get();
140 }
141 
TryUnwind(UnwinderStateCapture * capture_state,RegisterContext * thread_context,uintptr_t stack_top,std::vector<Frame> * stack)142 UnwindResult LibunwindstackUnwinderAndroid::TryUnwind(
143     UnwinderStateCapture* capture_state,
144     RegisterContext* thread_context,
145     uintptr_t stack_top,
146     std::vector<Frame>* stack) {
147   TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
148               "LibunwindstackUnwinderAndroid::TryUnwind");
149   // 500 is taken from traced_perf's own limit:
150   // https://cs.android.com/android/platform/superproject/+/master:external/perfetto/src/profiling/memory/unwinding.cc;l=64;drc=5860970a8606bb48059aa31ee506328286b9bf92
151   const int kMaxFrames = 500;
152 
153   // We use a struct and lambda here to cleanly express the result of an attempt
154   // to unwind. Sometimes when we fail we can succeed if we reparse maps and so
155   // we will call |attempt_unwind| twice.
156   struct UnwindValues {
157     unwindstack::ErrorCode error_code;
158     uint64_t warnings;
159     std::vector<unwindstack::FrameData> frames;
160   };
161 
162   std::unique_ptr<unwindstack::Regs> regs =
163       CreateFromRegisterContext(thread_context);
164   DCHECK(regs);
165 
166   TRACE_EVENT_BEGIN(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
167                     "libunwindstack::Unwind");
168   unwindstack::Unwinder unwinder(kMaxFrames, memory_regions_map_->maps(),
169                                  regs.get(), memory_regions_map_->memory());
170 
171   unwinder.SetJitDebug(GetOrCreateJitDebug(regs->Arch()));
172   unwinder.SetDexFiles(GetOrCreateDexFiles(regs->Arch()));
173 
174   unwinder.Unwind(/*initial_map_names_to_skip=*/nullptr,
175                   /*map_suffixes_to_ignore=*/nullptr);
176   TRACE_EVENT_END(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"));
177 
178   // Currently libunwindstack doesn't support warnings.
179   UnwindValues values =
180       UnwindValues{unwinder.LastErrorCode(), /*unwinder.warnings()*/ 0,
181                    unwinder.ConsumeFrames()};
182 
183   if (values.error_code != unwindstack::ERROR_NONE) {
184     TRACE_EVENT_INSTANT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
185                         "Libunwindstack Failure",
186                         [&values](perfetto::EventContext& ctx) {
187                           WriteLibunwindstackTraceEventArgs(
188                               values.error_code, values.frames.size(), ctx);
189                         });
190   }
191   if (values.frames.empty()) {
192     return UnwindResult::kCompleted;
193   }
194 
195   // The list of frames provided by Libunwindstack's Unwind() contains the
196   // executing frame. The executing frame is also added by
197   // StackSamplerImpl::WalkStack(). Ignore the frame from the latter to avoid
198   // duplication. In case a java method was being interpreted libunwindstack
199   // adds a dummy frame for it and then writes the corresponding native frame.
200   // In such a scenario we want to prefer the frames produced by
201   // libunwindstack.
202   DCHECK_EQ(stack->size(), 1u);
203   stack->clear();
204 
205   for (const unwindstack::FrameData& frame : values.frames) {
206     const ModuleCache::Module* module =
207         module_cache()->GetModuleForAddress(frame.pc);
208     if (module == nullptr && frame.map_info != nullptr) {
209       // Try searching for the module with same module start.
210       module = module_cache()->GetModuleForAddress(frame.map_info->start());
211       if (module == nullptr) {
212         auto module_for_caching =
213             std::make_unique<NonElfModule>(frame.map_info.get());
214         module = module_for_caching.get();
215         module_cache()->AddCustomNativeModule(std::move(module_for_caching));
216       }
217       if (frame.pc < frame.map_info->start() ||
218           frame.pc >= frame.map_info->end()) {
219         TRACE_EVENT_INSTANT(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
220                             "PC out of map range",
221                             [&values](perfetto::EventContext& ctx) {
222                               WriteLibunwindstackTraceEventArgs(
223                                   values.error_code, std::nullopt, ctx);
224                             });
225       }
226     }
227     std::string function_name = IsJavaModule(module) ? frame.function_name : "";
228     stack->emplace_back(frame.pc, module, std::move(function_name));
229   }
230   return UnwindResult::kCompleted;
231 }
232 
233 }  // namespace base
234