| 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 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 |