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 ×tamp, &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