Fix emulator build error
[platform/framework/web/chromium-efl.git] / base / profiler / stack_copier_suspend_unittest.cc
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 <algorithm>
6 #include <cstring>
7 #include <memory>
8 #include <numeric>
9 #include <utility>
10
11 #include "base/memory/raw_ptr.h"
12 #include "base/memory/raw_ref.h"
13 #include "base/profiler/stack_buffer.h"
14 #include "base/profiler/stack_copier_suspend.h"
15 #include "base/profiler/suspendable_thread_delegate.h"
16 #include "build/build_config.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 #if BUILDFLAG(IS_CHROMEOS)
21 #include "base/memory/page_size.h"
22 #endif
23
24 namespace base {
25
26 namespace {
27
28 using ::testing::Each;
29 using ::testing::ElementsAre;
30
31 // A thread delegate for use in tests that provides the expected behavior when
32 // operating on the supplied fake stack.
33 class TestSuspendableThreadDelegate : public SuspendableThreadDelegate {
34  public:
35   class TestScopedSuspendThread
36       : public SuspendableThreadDelegate::ScopedSuspendThread {
37    public:
38     TestScopedSuspendThread() = default;
39
40     TestScopedSuspendThread(const TestScopedSuspendThread&) = delete;
41     TestScopedSuspendThread& operator=(const TestScopedSuspendThread&) = delete;
42
43     bool WasSuccessful() const override { return true; }
44   };
45
46   TestSuspendableThreadDelegate(const std::vector<uintptr_t>& fake_stack,
47                                 // The register context will be initialized to
48                                 // *|thread_context| if non-null.
49                                 RegisterContext* thread_context = nullptr)
50       : fake_stack_(fake_stack), thread_context_(thread_context) {}
51
52   TestSuspendableThreadDelegate(const TestSuspendableThreadDelegate&) = delete;
53   TestSuspendableThreadDelegate& operator=(
54       const TestSuspendableThreadDelegate&) = delete;
55
56   std::unique_ptr<ScopedSuspendThread> CreateScopedSuspendThread() override {
57     return std::make_unique<TestScopedSuspendThread>();
58   }
59
60   bool GetThreadContext(RegisterContext* thread_context) override {
61     if (thread_context_)
62       *thread_context = *thread_context_;
63     // Set the stack pointer to be consistent with the provided fake stack.
64     RegisterContextStackPointer(thread_context) =
65         reinterpret_cast<uintptr_t>(&(*fake_stack_)[0]);
66     RegisterContextInstructionPointer(thread_context) =
67         reinterpret_cast<uintptr_t>((*fake_stack_)[0]);
68     return true;
69   }
70
71   PlatformThreadId GetThreadId() const override { return PlatformThreadId(); }
72
73   uintptr_t GetStackBaseAddress() const override {
74     return reinterpret_cast<uintptr_t>(&(*fake_stack_)[0] +
75                                        fake_stack_->size());
76   }
77
78   bool CanCopyStack(uintptr_t stack_pointer) override { return true; }
79
80   std::vector<uintptr_t*> GetRegistersToRewrite(
81       RegisterContext* thread_context) override {
82     return {&RegisterContextFramePointer(thread_context)};
83   }
84
85  private:
86   // Must be a reference to retain the underlying allocation from the vector
87   // passed to the constructor.
88   const raw_ref<const std::vector<uintptr_t>> fake_stack_;
89   raw_ptr<RegisterContext> thread_context_;
90 };
91
92 class TestStackCopierDelegate : public StackCopier::Delegate {
93  public:
94   void OnStackCopy() override {
95     on_stack_copy_was_invoked_ = true;
96   }
97
98   bool on_stack_copy_was_invoked() const { return on_stack_copy_was_invoked_; }
99
100  private:
101   bool on_stack_copy_was_invoked_ = false;
102 };
103
104 }  // namespace
105
106 TEST(StackCopierSuspendTest, CopyStack) {
107   const std::vector<uintptr_t> stack = {0, 1, 2, 3, 4};
108   StackCopierSuspend stack_copier_suspend(
109       std::make_unique<TestSuspendableThreadDelegate>(stack));
110
111   std::unique_ptr<StackBuffer> stack_buffer =
112       std::make_unique<StackBuffer>(stack.size() * sizeof(uintptr_t));
113   uintptr_t stack_top = 0;
114   TimeTicks timestamp;
115   RegisterContext register_context{};
116   TestStackCopierDelegate stack_copier_delegate;
117   stack_copier_suspend.CopyStack(stack_buffer.get(), &stack_top, &timestamp,
118                                  &register_context, &stack_copier_delegate);
119
120   uintptr_t* stack_copy_bottom =
121       reinterpret_cast<uintptr_t*>(stack_buffer.get()->buffer());
122   std::vector<uintptr_t> stack_copy(stack_copy_bottom,
123                                     stack_copy_bottom + stack.size());
124   EXPECT_EQ(stack, stack_copy);
125 }
126
127 TEST(StackCopierSuspendTest, CopyStackBufferTooSmall) {
128   std::vector<uintptr_t> stack;
129 #if BUILDFLAG(IS_CHROMEOS)
130   // ChromeOS will round up the size of the stack up to the next multiple of
131   // the page size. To make the buffer "too small", the stack must be 1 element
132   // larger than the page size.
133   const size_t kStackElements = (GetPageSize() / sizeof(stack[0])) + 1;
134 #else  // #if BUILDFLAG(IS_CHROMEOS)
135   const size_t kStackElements = 5;  // Arbitrary
136 #endif
137   stack.reserve(kStackElements);
138   for (size_t i = 0; i < kStackElements; ++i) {
139     stack.push_back(i);
140   }
141   StackCopierSuspend stack_copier_suspend(
142       std::make_unique<TestSuspendableThreadDelegate>(stack));
143
144   std::unique_ptr<StackBuffer> stack_buffer =
145       std::make_unique<StackBuffer>((stack.size() - 1) * sizeof(stack[0]));
146   // Make the buffer different than the input stack.
147   constexpr uintptr_t kBufferInitializer = 100;
148   size_t stack_buffer_elements =
149       stack_buffer->size() / sizeof(stack_buffer->buffer()[0]);
150   std::fill_n(stack_buffer->buffer(), stack_buffer_elements,
151               kBufferInitializer);
152   uintptr_t stack_top = 0;
153   TimeTicks timestamp;
154   RegisterContext register_context{};
155   TestStackCopierDelegate stack_copier_delegate;
156   stack_copier_suspend.CopyStack(stack_buffer.get(), &stack_top, &timestamp,
157                                  &register_context, &stack_copier_delegate);
158
159   uintptr_t* stack_copy_bottom =
160       reinterpret_cast<uintptr_t*>(stack_buffer.get()->buffer());
161   std::vector<uintptr_t> stack_copy(stack_copy_bottom,
162                                     stack_copy_bottom + stack_buffer_elements);
163   // Use the buffer not being overwritten as a proxy for the unwind being
164   // aborted.
165   EXPECT_THAT(stack_copy, Each(kBufferInitializer));
166 }
167
168 TEST(StackCopierSuspendTest, CopyStackAndRewritePointers) {
169   // Allocate space for the stack, then make its elements point to themselves.
170   std::vector<uintptr_t> stack(2);
171   stack[0] = reinterpret_cast<uintptr_t>(&stack[0]);
172   stack[1] = reinterpret_cast<uintptr_t>(&stack[1]);
173   StackCopierSuspend stack_copier_suspend(
174       std::make_unique<TestSuspendableThreadDelegate>(stack));
175
176   std::unique_ptr<StackBuffer> stack_buffer =
177       std::make_unique<StackBuffer>(stack.size() * sizeof(uintptr_t));
178   uintptr_t stack_top = 0;
179   TimeTicks timestamp;
180   RegisterContext register_context{};
181   TestStackCopierDelegate stack_copier_delegate;
182   stack_copier_suspend.CopyStack(stack_buffer.get(), &stack_top, &timestamp,
183                                  &register_context, &stack_copier_delegate);
184
185   uintptr_t* stack_copy_bottom =
186       reinterpret_cast<uintptr_t*>(stack_buffer.get()->buffer());
187   std::vector<uintptr_t> stack_copy(stack_copy_bottom,
188                                     stack_copy_bottom + stack.size());
189   EXPECT_THAT(stack_copy,
190               ElementsAre(reinterpret_cast<uintptr_t>(stack_copy_bottom),
191                           reinterpret_cast<uintptr_t>(stack_copy_bottom) +
192                               sizeof(uintptr_t)));
193 }
194
195 TEST(StackCopierSuspendTest, CopyStackTimeStamp) {
196   const std::vector<uintptr_t> stack = {0};
197   StackCopierSuspend stack_copier_suspend(
198       std::make_unique<TestSuspendableThreadDelegate>(stack));
199
200   std::unique_ptr<StackBuffer> stack_buffer =
201       std::make_unique<StackBuffer>(stack.size() * sizeof(uintptr_t));
202   uintptr_t stack_top = 0;
203   TimeTicks timestamp;
204   RegisterContext register_context{};
205   TestStackCopierDelegate stack_copier_delegate;
206
207   TimeTicks before = TimeTicks::Now();
208   stack_copier_suspend.CopyStack(stack_buffer.get(), &stack_top, &timestamp,
209                                  &register_context, &stack_copier_delegate);
210   TimeTicks after = TimeTicks::Now();
211
212   EXPECT_GE(timestamp, before);
213   EXPECT_LE(timestamp, after);
214 }
215
216 TEST(StackCopierSuspendTest, CopyStackDelegateInvoked) {
217   const std::vector<uintptr_t> stack = {0};
218   StackCopierSuspend stack_copier_suspend(
219       std::make_unique<TestSuspendableThreadDelegate>(stack));
220
221   std::unique_ptr<StackBuffer> stack_buffer =
222       std::make_unique<StackBuffer>(stack.size() * sizeof(uintptr_t));
223   uintptr_t stack_top = 0;
224   TimeTicks timestamp;
225   RegisterContext register_context{};
226   TestStackCopierDelegate stack_copier_delegate;
227
228   stack_copier_suspend.CopyStack(stack_buffer.get(), &stack_top, &timestamp,
229                                  &register_context, &stack_copier_delegate);
230
231   EXPECT_TRUE(stack_copier_delegate.on_stack_copy_was_invoked());
232 }
233
234 TEST(StackCopierSuspendTest, RewriteRegisters) {
235   std::vector<uintptr_t> stack = {0, 1, 2};
236   RegisterContext register_context{};
237   TestStackCopierDelegate stack_copier_delegate;
238   RegisterContextFramePointer(&register_context) =
239       reinterpret_cast<uintptr_t>(&stack[1]);
240   StackCopierSuspend stack_copier_suspend(
241       std::make_unique<TestSuspendableThreadDelegate>(stack,
242                                                       &register_context));
243
244   std::unique_ptr<StackBuffer> stack_buffer =
245       std::make_unique<StackBuffer>(stack.size() * sizeof(uintptr_t));
246   uintptr_t stack_top = 0;
247   TimeTicks timestamp;
248   stack_copier_suspend.CopyStack(stack_buffer.get(), &stack_top, &timestamp,
249                                  &register_context, &stack_copier_delegate);
250
251   uintptr_t stack_copy_bottom =
252       reinterpret_cast<uintptr_t>(stack_buffer.get()->buffer());
253   EXPECT_EQ(stack_copy_bottom + sizeof(uintptr_t),
254             RegisterContextFramePointer(&register_context));
255 }
256
257 }  // namespace base