• 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 <inttypes.h>
10 #include <string.h>
11 #include <vector>
12 
13 #include "base/android/build_info.h"
14 #include "base/functional/bind.h"
15 #include "base/native_library.h"
16 #include "base/path_service.h"
17 #include "base/profiler/register_context.h"
18 #include "base/profiler/stack_buffer.h"
19 #include "base/profiler/stack_copier_signal.h"
20 #include "base/profiler/stack_sampler.h"
21 #include "base/profiler/stack_sampling_profiler_java_test_util.h"
22 #include "base/profiler/stack_sampling_profiler_test_util.h"
23 #include "base/profiler/thread_delegate_posix.h"
24 #include "base/test/bind.h"
25 #include "build/build_config.h"
26 #include "stack_sampling_profiler_test_util.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 
29 namespace base {
30 
31 namespace {
32 class TestStackCopierDelegate : public StackCopier::Delegate {
33  public:
OnStackCopy()34   void OnStackCopy() override {}
35 };
36 
CaptureScenario(UnwindScenario * scenario,ModuleCache * module_cache,OnceCallback<void (UnwinderStateCapture *,RegisterContext *,uintptr_t,std::vector<Frame> *)> unwind_callback)37 std::vector<Frame> CaptureScenario(
38     UnwindScenario* scenario,
39     ModuleCache* module_cache,
40     OnceCallback<void(UnwinderStateCapture*,
41                       RegisterContext*,
42                       uintptr_t,
43                       std::vector<Frame>*)> unwind_callback) {
44   std::vector<Frame> sample;
45   WithTargetThread(
46       scenario,
47       BindLambdaForTesting(
48           [&](SamplingProfilerThreadToken target_thread_token) {
49             auto thread_delegate =
50                 ThreadDelegatePosix::Create(target_thread_token);
51             ASSERT_TRUE(thread_delegate);
52             auto stack_copier =
53                 std::make_unique<StackCopierSignal>(std::move(thread_delegate));
54             std::unique_ptr<StackBuffer> stack_buffer =
55                 StackSampler::CreateStackBuffer();
56 
57             RegisterContext thread_context;
58             uintptr_t stack_top;
59             TimeTicks timestamp;
60             TestStackCopierDelegate delegate;
61             bool success =
62                 stack_copier->CopyStack(stack_buffer.get(), &stack_top,
63                                         &timestamp, &thread_context, &delegate);
64             ASSERT_TRUE(success);
65 
66             sample.emplace_back(
67                 RegisterContextInstructionPointer(&thread_context),
68                 module_cache->GetModuleForAddress(
69                     RegisterContextInstructionPointer(&thread_context)));
70 
71             std::move(unwind_callback)
72                 .Run(nullptr, &thread_context, stack_top, &sample);
73           }));
74 
75   return sample;
76 }
77 }  // namespace
78 
79 // Checks that the expected information is present in sampled frames.
TEST(LibunwindstackUnwinderAndroidTest,PlainFunction)80 TEST(LibunwindstackUnwinderAndroidTest, PlainFunction) {
81   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
82 
83   ModuleCache module_cache;
84   auto unwinder = std::make_unique<LibunwindstackUnwinderAndroid>();
85 
86   unwinder->Initialize(&module_cache);
87   std::vector<Frame> sample = CaptureScenario(
88       &scenario, &module_cache,
89       BindLambdaForTesting([&](UnwinderStateCapture* capture_state,
90                                RegisterContext* thread_context,
91                                uintptr_t stack_top,
92                                std::vector<Frame>* sample) {
93         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
94         UnwindResult result = unwinder->TryUnwind(capture_state, thread_context,
95                                                   stack_top, sample);
96         EXPECT_EQ(UnwindResult::kCompleted, result);
97       }));
98 
99   // Check that all the modules are valid.
100   for (const auto& frame : sample)
101     EXPECT_NE(nullptr, frame.module);
102 
103   // The stack should contain a full unwind.
104   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
105                                scenario.GetSetupFunctionAddressRange(),
106                                scenario.GetOuterFunctionAddressRange()});
107 }
108 
109 // Checks that the unwinder handles stacks containing dynamically-allocated
110 // stack memory.
TEST(LibunwindstackUnwinderAndroidTest,Alloca)111 TEST(LibunwindstackUnwinderAndroidTest, Alloca) {
112   UnwindScenario scenario(BindRepeating(&CallWithAlloca));
113 
114   ModuleCache module_cache;
115   auto unwinder = std::make_unique<LibunwindstackUnwinderAndroid>();
116 
117   unwinder->Initialize(&module_cache);
118   std::vector<Frame> sample = CaptureScenario(
119       &scenario, &module_cache,
120       BindLambdaForTesting([&](UnwinderStateCapture* capture_state,
121                                RegisterContext* thread_context,
122                                uintptr_t stack_top,
123                                std::vector<Frame>* sample) {
124         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
125         UnwindResult result = unwinder->TryUnwind(capture_state, thread_context,
126                                                   stack_top, sample);
127         EXPECT_EQ(UnwindResult::kCompleted, result);
128       }));
129 
130   // Check that all the modules are valid.
131   for (const auto& frame : sample)
132     EXPECT_NE(nullptr, frame.module);
133 
134   // The stack should contain a full unwind.
135   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
136                                scenario.GetSetupFunctionAddressRange(),
137                                scenario.GetOuterFunctionAddressRange()});
138 }
139 
140 // Checks that a stack that runs through another library produces a stack with
141 // the expected functions.
TEST(LibunwindstackUnwinderAndroidTest,OtherLibrary)142 TEST(LibunwindstackUnwinderAndroidTest, OtherLibrary) {
143   NativeLibrary other_library = LoadOtherLibrary();
144   UnwindScenario scenario(
145       BindRepeating(&CallThroughOtherLibrary, Unretained(other_library)));
146 
147   ModuleCache module_cache;
148   auto unwinder = std::make_unique<LibunwindstackUnwinderAndroid>();
149 
150   unwinder->Initialize(&module_cache);
151   std::vector<Frame> sample = CaptureScenario(
152       &scenario, &module_cache,
153       BindLambdaForTesting([&](UnwinderStateCapture* capture_state,
154                                RegisterContext* thread_context,
155                                uintptr_t stack_top,
156                                std::vector<Frame>* sample) {
157         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
158         UnwindResult result = unwinder->TryUnwind(capture_state, thread_context,
159                                                   stack_top, sample);
160         EXPECT_EQ(UnwindResult::kCompleted, result);
161       }));
162 
163   // The stack should contain a full unwind.
164   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
165                                scenario.GetSetupFunctionAddressRange(),
166                                scenario.GetOuterFunctionAddressRange()});
167 }
168 
169 // Checks that java frames can be unwound through and have function names.
TEST(LibunwindstackUnwinderAndroidTest,JavaFunction)170 TEST(LibunwindstackUnwinderAndroidTest, JavaFunction) {
171   auto* build_info = base::android::BuildInfo::GetInstance();
172   // Due to varying availability of compiled/JITed java unwind tables, unwinding
173   // is only expected to reliably succeed on Android P+
174   // https://android.googlesource.com/platform/system/unwinding/+/refs/heads/master/libunwindstack/AndroidVersions.md#android-9-pie_api-level-28
175   // The libunwindstack doc mentions in Android 9 it got the support for
176   // unwinding through JIT'd frames.
177   bool can_unwind = build_info->sdk_int() >= base::android::SDK_VERSION_P;
178   if (!can_unwind) {
179     GTEST_SKIP() << "Unwind info is not available on older version of Android";
180   }
181 
182   UnwindScenario scenario(base::BindRepeating(callWithJavaFunction));
183 
184   auto unwinder = std::make_unique<LibunwindstackUnwinderAndroid>();
185 
186   ModuleCache module_cache;
187   unwinder->Initialize(&module_cache);
188   const std::vector<Frame> sample = CaptureScenario(
189       &scenario, &module_cache,
190       BindLambdaForTesting([&](UnwinderStateCapture* capture_state,
191                                RegisterContext* thread_context,
192                                uintptr_t stack_top,
193                                std::vector<Frame>* sample) {
194         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
195         UnwindResult result = unwinder->TryUnwind(capture_state, thread_context,
196                                                   stack_top, sample);
197         EXPECT_EQ(UnwindResult::kCompleted, result);
198       }));
199 
200   // Check that all the modules are valid.
201   for (const auto& frame : sample) {
202     EXPECT_NE(frame.module, nullptr);
203   }
204 
205   // The stack should contain a full unwind.
206   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
207                                scenario.GetSetupFunctionAddressRange(),
208                                scenario.GetOuterFunctionAddressRange()});
209 }
210 
211 // TODO(b/269239545): Delete or re-enable (and enable updatable maps) this test.
TEST(LibunwindstackUnwinderAndroidTest,DISABLED_ReparsesMapsOnNewDynamicLibraryLoad)212 TEST(LibunwindstackUnwinderAndroidTest,
213      DISABLED_ReparsesMapsOnNewDynamicLibraryLoad) {
214   // The current version of /proc/self/maps is used to create
215   // memory_regions_map_ object.
216   auto unwinder = std::make_unique<LibunwindstackUnwinderAndroid>();
217   ModuleCache module_cache;
218   unwinder->Initialize(&module_cache);
219 
220   // Dynamically loading a library should update maps and a reparse is required
221   // to actually unwind through functions involving this library.
222   NativeLibrary dynamic_library =
223       LoadTestLibrary("base_profiler_reparsing_test_support_library");
224   UnwindScenario scenario(
225       BindRepeating(&CallThroughOtherLibrary, Unretained(dynamic_library)));
226 
227   auto sample = CaptureScenario(
228       &scenario, &module_cache,
229       BindLambdaForTesting([&](UnwinderStateCapture* capture_state,
230                                RegisterContext* thread_context,
231                                uintptr_t stack_top,
232                                std::vector<Frame>* sample) {
233         ASSERT_TRUE(unwinder->CanUnwindFrom(sample->back()));
234         UnwindResult result = unwinder->TryUnwind(capture_state, thread_context,
235                                                   stack_top, sample);
236         EXPECT_EQ(UnwindResult::kCompleted, result);
237       }));
238 
239   ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
240                                scenario.GetSetupFunctionAddressRange(),
241                                scenario.GetOuterFunctionAddressRange()});
242 }
243 
244 }  // namespace base
245