xref: /aosp_15_r20/external/cronet/base/profiler/native_unwinder_android.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 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/native_unwinder_android.h"
6 
7 #include <sys/mman.h>
8 
9 #include <string>
10 #include <vector>
11 
12 #include "base/memory/ptr_util.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/metrics/metrics_hashes.h"
15 #include "base/notreached.h"
16 #include "base/profiler/module_cache.h"
17 #include "base/profiler/native_unwinder_android_map_delegate.h"
18 #include "base/profiler/native_unwinder_android_memory_regions_map_impl.h"
19 #include "base/profiler/profile_builder.h"
20 #include "build/build_config.h"
21 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Elf.h"
22 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Maps.h"
23 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Memory.h"
24 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/Regs.h"
25 
26 #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
27 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/MachineArm.h"
28 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/RegsArm.h"
29 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
30 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/MachineArm64.h"
31 #include "third_party/libunwindstack/src/libunwindstack/include/unwindstack/RegsArm64.h"
32 #endif  // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
33 
34 namespace base {
35 namespace {
36 
37 class NonElfModule : public ModuleCache::Module {
38  public:
NonElfModule(unwindstack::MapInfo * map_info,bool is_java_name_hashing_enabled)39   explicit NonElfModule(unwindstack::MapInfo* map_info,
40                         bool is_java_name_hashing_enabled)
41       : start_(map_info->start()),
42         size_(map_info->end() - start_),
43         map_info_name_(map_info->name()),
44         is_java_name_hashing_enabled_(is_java_name_hashing_enabled) {}
45   ~NonElfModule() override = default;
46 
GetBaseAddress() const47   uintptr_t GetBaseAddress() const override { return start_; }
48 
GetId() const49   std::string GetId() const override {
50     // We provide a non-empty string only if Java name hashing is enabled, to
51     // allow us to easily filter out the results from outside the experiment.
52     if (is_java_name_hashing_enabled_) {
53       // Synthetic build id to use for DEX files that provide hashed function
54       // names rather than instruction pointers.
55       return "44444444BC18564712E780518FB3032B999";
56     } else {
57       return "";
58     }
59   }
60 
GetDebugBasename() const61   FilePath GetDebugBasename() const override {
62     return FilePath(map_info_name_);
63   }
64 
65   // Gets the size of the module.
GetSize() const66   size_t GetSize() const override { return size_; }
67 
68   // True if this is a native module.
IsNative() const69   bool IsNative() const override { return true; }
70 
71  private:
72   const uintptr_t start_;
73   const size_t size_;
74   const std::string map_info_name_;
75   const bool is_java_name_hashing_enabled_;
76 };
77 
CreateFromRegisterContext(RegisterContext * thread_context)78 std::unique_ptr<unwindstack::Regs> CreateFromRegisterContext(
79     RegisterContext* thread_context) {
80 #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
81   return WrapUnique<unwindstack::Regs>(unwindstack::RegsArm::Read(
82       reinterpret_cast<void*>(&thread_context->arm_r0)));
83 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
84   return WrapUnique<unwindstack::Regs>(unwindstack::RegsArm64::Read(
85       reinterpret_cast<void*>(&thread_context->regs[0])));
86 #else   // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
87   NOTREACHED();
88   return nullptr;
89 #endif  // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
90 }
91 
CopyToRegisterContext(unwindstack::Regs * regs,RegisterContext * thread_context)92 void CopyToRegisterContext(unwindstack::Regs* regs,
93                            RegisterContext* thread_context) {
94 #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
95   memcpy(reinterpret_cast<void*>(&thread_context->arm_r0), regs->RawData(),
96          unwindstack::ARM_REG_LAST * sizeof(uintptr_t));
97 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
98   memcpy(reinterpret_cast<void*>(&thread_context->regs[0]), regs->RawData(),
99          unwindstack::ARM64_REG_LAST * sizeof(uintptr_t));
100 #else   // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
101   NOTREACHED();
102 #endif  // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
103 }
104 
105 }  // namespace
106 
UnwindStackMemoryAndroid(uintptr_t stack_ptr,uintptr_t stack_top)107 UnwindStackMemoryAndroid::UnwindStackMemoryAndroid(uintptr_t stack_ptr,
108                                                    uintptr_t stack_top)
109     : stack_ptr_(stack_ptr), stack_top_(stack_top) {
110   DCHECK_LE(stack_ptr_, stack_top_);
111 }
112 
113 UnwindStackMemoryAndroid::~UnwindStackMemoryAndroid() = default;
114 
Read(uint64_t addr,void * dst,size_t size)115 size_t UnwindStackMemoryAndroid::Read(uint64_t addr, void* dst, size_t size) {
116   if (addr < stack_ptr_)
117     return 0;
118   if (size >= stack_top_ || addr > stack_top_ - size)
119     return 0;
120   memcpy(dst, reinterpret_cast<void*>(addr), size);
121   return size;
122 }
123 
124 // static
125 std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMap>
CreateMemoryRegionsMap(bool use_updatable_maps)126 NativeUnwinderAndroid::CreateMemoryRegionsMap(bool use_updatable_maps) {
127   std::unique_ptr<unwindstack::Maps> maps;
128   if (use_updatable_maps) {
129     maps = std::make_unique<unwindstack::LocalUpdatableMaps>();
130   } else {
131     maps = std::make_unique<unwindstack::LocalMaps>();
132   }
133   const bool success = maps->Parse();
134   DCHECK(success);
135 
136   return std::make_unique<NativeUnwinderAndroidMemoryRegionsMapImpl>(
137       std::move(maps), unwindstack::Memory::CreateLocalProcessMemory());
138 }
139 
NativeUnwinderAndroid(uintptr_t exclude_module_with_base_address,NativeUnwinderAndroidMapDelegate * map_delegate,bool is_java_name_hashing_enabled)140 NativeUnwinderAndroid::NativeUnwinderAndroid(
141     uintptr_t exclude_module_with_base_address,
142     NativeUnwinderAndroidMapDelegate* map_delegate,
143     bool is_java_name_hashing_enabled)
144     : is_java_name_hashing_enabled_(is_java_name_hashing_enabled),
145       exclude_module_with_base_address_(exclude_module_with_base_address),
146       map_delegate_(map_delegate),
147       memory_regions_map_(
148           static_cast<NativeUnwinderAndroidMemoryRegionsMapImpl*>(
149               map_delegate->GetMapReference())) {
150   DCHECK(map_delegate_);
151   DCHECK(memory_regions_map_);
152 }
153 
~NativeUnwinderAndroid()154 NativeUnwinderAndroid::~NativeUnwinderAndroid() {
155   if (module_cache())
156     module_cache()->UnregisterAuxiliaryModuleProvider(this);
157 
158   map_delegate_->ReleaseMapReference();
159 }
160 
InitializeModules()161 void NativeUnwinderAndroid::InitializeModules() {
162   module_cache()->RegisterAuxiliaryModuleProvider(this);
163 }
164 
CanUnwindFrom(const Frame & current_frame) const165 bool NativeUnwinderAndroid::CanUnwindFrom(const Frame& current_frame) const {
166   return current_frame.module && current_frame.module->IsNative() &&
167          current_frame.module->GetBaseAddress() !=
168              exclude_module_with_base_address_;
169 }
170 
TryUnwind(RegisterContext * thread_context,uintptr_t stack_top,std::vector<Frame> * stack)171 UnwindResult NativeUnwinderAndroid::TryUnwind(RegisterContext* thread_context,
172                                               uintptr_t stack_top,
173                                               std::vector<Frame>* stack) {
174   auto regs = CreateFromRegisterContext(thread_context);
175   DCHECK(regs);
176   unwindstack::ArchEnum arch = regs->Arch();
177 
178   do {
179     uint64_t cur_pc = regs->pc();
180     uint64_t cur_sp = regs->sp();
181     unwindstack::MapInfo* map_info =
182         memory_regions_map_->maps()->Find(cur_pc).get();
183     if (map_info == nullptr ||
184         map_info->flags() & unwindstack::MAPS_FLAGS_DEVICE_MAP) {
185       break;
186     }
187 
188     unwindstack::Elf* elf =
189         map_info->GetElf(memory_regions_map_->memory(), arch);
190     if (!elf->valid())
191       break;
192 
193     UnwindStackMemoryAndroid stack_memory(cur_sp, stack_top);
194     uintptr_t rel_pc = elf->GetRelPc(cur_pc, map_info);
195     bool is_signal_frame = false;
196     bool finished = false;
197     // map_info->GetElf() may return a valid elf whose memory() is nullptr.
198     // In the case, elf->StepIfSignalHandler() and elf->Step() are not
199     // available, because the method depends on elf->memory().
200     // (Regarding Step(), EvalRegister() needs memory.)
201     bool stepped =
202         elf->memory() &&
203         (elf->StepIfSignalHandler(rel_pc, regs.get(), &stack_memory) ||
204          elf->Step(rel_pc, regs.get(), &stack_memory, &finished,
205                    &is_signal_frame));
206     if (stepped && finished)
207       return UnwindResult::kCompleted;
208 
209     if (!stepped) {
210       // Stepping failed. Try unwinding using return address.
211       if (stack->size() == 1) {
212         if (!regs->SetPcFromReturnAddress(&stack_memory))
213           return UnwindResult::kAborted;
214       } else {
215         break;
216       }
217     }
218 
219     // If the pc and sp didn't change, then consider everything stopped.
220     if (cur_pc == regs->pc() && cur_sp == regs->sp())
221       return UnwindResult::kAborted;
222 
223     // Exclusive range of expected stack pointer values after the unwind.
224     struct {
225       uintptr_t start;
226       uintptr_t end;
227     } expected_stack_pointer_range = {static_cast<uintptr_t>(cur_sp),
228                                       stack_top};
229     if (regs->sp() < expected_stack_pointer_range.start ||
230         regs->sp() >= expected_stack_pointer_range.end) {
231       return UnwindResult::kAborted;
232     }
233 
234     if (regs->dex_pc() != 0) {
235       // Add a frame to represent the dex file.
236       EmitDexFrame(regs->dex_pc(), arch, stack);
237 
238       // Clear the dex pc so that we don't repeat this frame later.
239       regs->set_dex_pc(0);
240     }
241 
242     // Add the frame to |stack|. Must use GetModuleForAddress rather than
243     // GetExistingModuleForAddress because the unwound-to address may be in a
244     // module associated with a different unwinder.
245     const ModuleCache::Module* module =
246         module_cache()->GetModuleForAddress(regs->pc());
247     stack->emplace_back(regs->pc(), module);
248   } while (CanUnwindFrom(stack->back()));
249 
250   // Restore registers necessary for further unwinding in |thread_context|.
251   CopyToRegisterContext(regs.get(), thread_context);
252   return UnwindResult::kUnrecognizedFrame;
253 }
254 
255 std::unique_ptr<const ModuleCache::Module>
TryCreateModuleForAddress(uintptr_t address)256 NativeUnwinderAndroid::TryCreateModuleForAddress(uintptr_t address) {
257   unwindstack::MapInfo* map_info =
258       memory_regions_map_->maps()->Find(address).get();
259   if (map_info == nullptr || !(map_info->flags() & PROT_EXEC) ||
260       map_info->flags() & unwindstack::MAPS_FLAGS_DEVICE_MAP) {
261     return nullptr;
262   }
263   return std::make_unique<NonElfModule>(map_info,
264                                         is_java_name_hashing_enabled_);
265 }
266 
GetOrCreateDexFiles(unwindstack::ArchEnum arch)267 unwindstack::DexFiles* NativeUnwinderAndroid::GetOrCreateDexFiles(
268     unwindstack::ArchEnum arch) {
269   if (!dex_files_) {
270     dex_files_ = unwindstack::CreateDexFiles(
271         arch, memory_regions_map_->memory(), search_libs_);
272   }
273   return dex_files_.get();
274 }
275 
EmitDexFrame(uintptr_t dex_pc,unwindstack::ArchEnum arch,std::vector<Frame> * stack)276 void NativeUnwinderAndroid::EmitDexFrame(uintptr_t dex_pc,
277                                          unwindstack::ArchEnum arch,
278                                          std::vector<Frame>* stack) {
279   const ModuleCache::Module* module =
280       module_cache()->GetExistingModuleForAddress(dex_pc);
281   if (!module) {
282     // The region containing |dex_pc| may not be in module_cache() since it's
283     // usually not executable (.dex file). Since non-executable regions
284     // are used much less commonly, it's lazily added here instead of from
285     // AddInitialModulesFromMaps().
286     unwindstack::MapInfo* map_info =
287         memory_regions_map_->maps()->Find(dex_pc).get();
288     if (map_info) {
289       auto new_module = std::make_unique<NonElfModule>(
290           map_info, is_java_name_hashing_enabled_);
291       module = new_module.get();
292       module_cache()->AddCustomNativeModule(std::move(new_module));
293     }
294   }
295 
296   if (is_java_name_hashing_enabled_) {
297     unwindstack::SharedString function_name;
298     uint64_t function_offset = 0;
299     GetOrCreateDexFiles(arch)->GetFunctionName(
300         memory_regions_map_->maps(), dex_pc, &function_name, &function_offset);
301     stack->emplace_back(
302         HashMetricNameAs32Bits(static_cast<const std::string&>(function_name)),
303         module);
304     UMA_HISTOGRAM_COUNTS_1000(
305         "UMA.StackProfiler.JavaNameLength",
306         static_cast<const std::string&>(function_name).size());
307   } else {
308     stack->emplace_back(dex_pc, module);
309   }
310 }
311 
312 }  // namespace base
313