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