| OLD | NEW | 
|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "base/profiler/win32_stack_frame_unwinder.h" | 5 #include "base/profiler/win32_stack_frame_unwinder.h" | 
| 6 | 6 | 
|  | 7 #include <memory> | 
| 7 #include <utility> | 8 #include <utility> | 
| 8 #include <vector> | 9 #include <vector> | 
| 9 | 10 | 
| 10 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" | 
| 11 #include "base/macros.h" | 12 #include "base/macros.h" | 
| 12 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/ptr_util.h" | 
| 13 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" | 
| 14 | 15 | 
| 15 namespace base { | 16 namespace base { | 
| 16 | 17 | 
| 17 namespace { | 18 namespace { | 
| 18 | 19 | 
| 19 class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { | 20 class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { | 
| 20  public: | 21  public: | 
| 21   TestUnwindFunctions(); | 22   TestUnwindFunctions(); | 
| 22 | 23 | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 119 } | 120 } | 
| 120 | 121 | 
| 121 }  // namespace | 122 }  // namespace | 
| 122 | 123 | 
| 123 class Win32StackFrameUnwinderTest : public testing::Test { | 124 class Win32StackFrameUnwinderTest : public testing::Test { | 
| 124  protected: | 125  protected: | 
| 125   Win32StackFrameUnwinderTest() {} | 126   Win32StackFrameUnwinderTest() {} | 
| 126 | 127 | 
| 127   // This exists so that Win32StackFrameUnwinder's constructor can be private | 128   // This exists so that Win32StackFrameUnwinder's constructor can be private | 
| 128   // with a single friend declaration of this test fixture. | 129   // with a single friend declaration of this test fixture. | 
| 129   scoped_ptr<Win32StackFrameUnwinder> CreateUnwinder(); | 130   std::unique_ptr<Win32StackFrameUnwinder> CreateUnwinder(); | 
| 130 | 131 | 
| 131   // Weak pointer to the unwind functions used by last created unwinder. | 132   // Weak pointer to the unwind functions used by last created unwinder. | 
| 132   TestUnwindFunctions* unwind_functions_; | 133   TestUnwindFunctions* unwind_functions_; | 
| 133 | 134 | 
| 134  private: | 135  private: | 
| 135   DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinderTest); | 136   DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinderTest); | 
| 136 }; | 137 }; | 
| 137 | 138 | 
| 138 scoped_ptr<Win32StackFrameUnwinder> | 139 std::unique_ptr<Win32StackFrameUnwinder> | 
| 139 Win32StackFrameUnwinderTest::CreateUnwinder() { | 140 Win32StackFrameUnwinderTest::CreateUnwinder() { | 
| 140   scoped_ptr<TestUnwindFunctions> unwind_functions(new TestUnwindFunctions); | 141   std::unique_ptr<TestUnwindFunctions> unwind_functions( | 
|  | 142       new TestUnwindFunctions); | 
| 141   unwind_functions_ = unwind_functions.get(); | 143   unwind_functions_ = unwind_functions.get(); | 
| 142   return make_scoped_ptr( | 144   return base::WrapUnique( | 
| 143       new Win32StackFrameUnwinder(std::move(unwind_functions))); | 145       new Win32StackFrameUnwinder(std::move(unwind_functions))); | 
| 144 } | 146 } | 
| 145 | 147 | 
| 146 // Checks the case where all frames have unwind information. | 148 // Checks the case where all frames have unwind information. | 
| 147 TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { | 149 TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { | 
| 148   scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 150   std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 
| 149   CONTEXT context = {0}; | 151   CONTEXT context = {0}; | 
| 150   ScopedModuleHandle module; | 152   ScopedModuleHandle module; | 
| 151 | 153 | 
| 152   unwind_functions_->SetHasRuntimeFunction(&context); | 154   unwind_functions_->SetHasRuntimeFunction(&context); | 
| 153   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 155   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 
| 154   EXPECT_TRUE(module.IsValid()); | 156   EXPECT_TRUE(module.IsValid()); | 
| 155 | 157 | 
| 156   unwind_functions_->SetHasRuntimeFunction(&context); | 158   unwind_functions_->SetHasRuntimeFunction(&context); | 
| 157   module.Set(nullptr); | 159   module.Set(nullptr); | 
| 158   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 160   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 
| 159   EXPECT_TRUE(module.IsValid()); | 161   EXPECT_TRUE(module.IsValid()); | 
| 160 | 162 | 
| 161   unwind_functions_->SetHasRuntimeFunction(&context); | 163   unwind_functions_->SetHasRuntimeFunction(&context); | 
| 162   module.Set(nullptr); | 164   module.Set(nullptr); | 
| 163   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 165   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 
| 164   EXPECT_TRUE(module.IsValid()); | 166   EXPECT_TRUE(module.IsValid()); | 
| 165 } | 167 } | 
| 166 | 168 | 
| 167 // Checks that an instruction pointer in an unloaded module fails to unwind. | 169 // Checks that an instruction pointer in an unloaded module fails to unwind. | 
| 168 TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) { | 170 TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) { | 
| 169   scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 171   std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 
| 170   CONTEXT context = {0}; | 172   CONTEXT context = {0}; | 
| 171   ScopedModuleHandle module; | 173   ScopedModuleHandle module; | 
| 172 | 174 | 
| 173   unwind_functions_->SetUnloadedModule(); | 175   unwind_functions_->SetUnloadedModule(); | 
| 174   EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); | 176   EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); | 
| 175 } | 177 } | 
| 176 | 178 | 
| 177 // Checks that the CONTEXT's stack pointer gets popped when the top frame has no | 179 // Checks that the CONTEXT's stack pointer gets popped when the top frame has no | 
| 178 // unwind information. | 180 // unwind information. | 
| 179 TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) { | 181 TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) { | 
| 180   scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 182   std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 
| 181   CONTEXT context = {0}; | 183   CONTEXT context = {0}; | 
| 182   ScopedModuleHandle module; | 184   ScopedModuleHandle module; | 
| 183   DWORD64 next_ip = 0x0123456789abcdef; | 185   DWORD64 next_ip = 0x0123456789abcdef; | 
| 184   DWORD64 original_rsp = reinterpret_cast<DWORD64>(&next_ip); | 186   DWORD64 original_rsp = reinterpret_cast<DWORD64>(&next_ip); | 
| 185   context.Rsp = original_rsp; | 187   context.Rsp = original_rsp; | 
| 186 | 188 | 
| 187   unwind_functions_->SetNoRuntimeFunction(&context); | 189   unwind_functions_->SetNoRuntimeFunction(&context); | 
| 188   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 190   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 
| 189   EXPECT_EQ(next_ip, context.Rip); | 191   EXPECT_EQ(next_ip, context.Rip); | 
| 190   EXPECT_EQ(original_rsp + 8, context.Rsp); | 192   EXPECT_EQ(original_rsp + 8, context.Rsp); | 
| 191   EXPECT_TRUE(module.IsValid()); | 193   EXPECT_TRUE(module.IsValid()); | 
| 192 | 194 | 
| 193   unwind_functions_->SetHasRuntimeFunction(&context); | 195   unwind_functions_->SetHasRuntimeFunction(&context); | 
| 194   module.Set(nullptr); | 196   module.Set(nullptr); | 
| 195   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 197   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 
| 196   EXPECT_TRUE(module.IsValid()); | 198   EXPECT_TRUE(module.IsValid()); | 
| 197 | 199 | 
| 198   unwind_functions_->SetHasRuntimeFunction(&context); | 200   unwind_functions_->SetHasRuntimeFunction(&context); | 
| 199   module.Set(nullptr); | 201   module.Set(nullptr); | 
| 200   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 202   EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 
| 201   EXPECT_TRUE(module.IsValid()); | 203   EXPECT_TRUE(module.IsValid()); | 
| 202 } | 204 } | 
| 203 | 205 | 
| 204 // Checks that a frame below the top of the stack with missing unwind info | 206 // Checks that a frame below the top of the stack with missing unwind info | 
| 205 // terminates the unwinding. | 207 // terminates the unwinding. | 
| 206 TEST_F(Win32StackFrameUnwinderTest, FrameBelowTopWithoutUnwindInfo) { | 208 TEST_F(Win32StackFrameUnwinderTest, FrameBelowTopWithoutUnwindInfo) { | 
| 207   { | 209   { | 
| 208     // First stack, with a bad function below the top of the stack. | 210     // First stack, with a bad function below the top of the stack. | 
| 209     scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 211     std::unique_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 
| 210     CONTEXT context = {0}; | 212     CONTEXT context = {0}; | 
| 211     ScopedModuleHandle module; | 213     ScopedModuleHandle module; | 
| 212     unwind_functions_->SetHasRuntimeFunction(&context); | 214     unwind_functions_->SetHasRuntimeFunction(&context); | 
| 213     EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 215     EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); | 
| 214     EXPECT_TRUE(module.IsValid()); | 216     EXPECT_TRUE(module.IsValid()); | 
| 215 | 217 | 
| 216     unwind_functions_->SetNoRuntimeFunction(&context); | 218     unwind_functions_->SetNoRuntimeFunction(&context); | 
| 217     EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); | 219     EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); | 
| 218   } | 220   } | 
| 219 } | 221 } | 
| 220 | 222 | 
| 221 }  // namespace base | 223 }  // namespace base | 
| OLD | NEW | 
|---|