Index: base/profiler/win32_stack_frame_unwinder_unittest.cc |
diff --git a/base/profiler/win32_stack_frame_unwinder_unittest.cc b/base/profiler/win32_stack_frame_unwinder_unittest.cc |
index ae5a2a6ea109edb2600914a572e32123e40cf68c..2fe34a70b333c36cf80e60afff0e36c6ec4a50d7 100644 |
--- a/base/profiler/win32_stack_frame_unwinder_unittest.cc |
+++ b/base/profiler/win32_stack_frame_unwinder_unittest.cc |
@@ -23,6 +23,11 @@ class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { |
DWORD64 program_counter, |
PRUNTIME_FUNCTION runtime_function, |
CONTEXT* context) override; |
+ ScopedModuleHandle GetModuleForProgramCounter( |
+ DWORD64 program_counter) override; |
+ |
+ // Instructs GetModuleForProgramCounter to return null on the next call. |
+ void SetUnloadedModule(); |
// These functions set whether the next frame will have a RUNTIME_FUNCTION, |
// and allow specification of a custom image_base. |
@@ -48,6 +53,7 @@ class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { |
static RUNTIME_FUNCTION* const kInvalidRuntimeFunction; |
+ bool module_is_loaded_; |
DWORD64 expected_program_counter_; |
DWORD64 custom_image_base_; |
DWORD64 next_image_base_; |
@@ -62,7 +68,8 @@ RUNTIME_FUNCTION* const TestUnwindFunctions::kInvalidRuntimeFunction = |
reinterpret_cast<RUNTIME_FUNCTION*>(static_cast<uintptr_t>(-1)); |
TestUnwindFunctions::TestUnwindFunctions() |
- : expected_program_counter_(0), |
+ : module_is_loaded_(true), |
+ expected_program_counter_(0), |
custom_image_base_(0), |
next_image_base_(kImageBaseIncrement), |
expected_image_base_(0), |
@@ -101,6 +108,19 @@ void TestUnwindFunctions::VirtualUnwind(DWORD64 image_base, |
EXPECT_EQ(&runtime_functions_.back(), runtime_function); |
} |
+ScopedModuleHandle TestUnwindFunctions::GetModuleForProgramCounter( |
+ DWORD64 program_counter) { |
+ bool return_non_null_value = module_is_loaded_; |
+ module_is_loaded_ = true; |
+ return ScopedModuleHandle(return_non_null_value ? |
+ ModuleHandleTraits::kNonNullModuleForTesting : |
+ nullptr); |
+} |
+ |
+void TestUnwindFunctions::SetUnloadedModule() { |
+ module_is_loaded_ = false; |
+} |
+ |
void TestUnwindFunctions::SetHasRuntimeFunction(CONTEXT* context) { |
SetNextFrameState(HAS_RUNTIME_FUNCTION, 0, context); |
} |
@@ -184,15 +204,31 @@ Win32StackFrameUnwinderTest::CreateUnwinder() { |
TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
+} |
+ |
+// Checks that an instruction pointer in an unloaded module fails to unwind. |
+TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) { |
+ scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
+ CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
+ |
+ unwind_functions_->SetUnloadedModule(); |
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
} |
// Checks that the CONTEXT's stack pointer gets popped when the top frame has no |
@@ -200,19 +236,25 @@ TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { |
TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) { |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
const DWORD64 original_rsp = 128; |
context.Rsp = original_rsp; |
unwind_functions_->SetNoRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
EXPECT_EQ(original_rsp, context.Rip); |
EXPECT_EQ(original_rsp + 8, context.Rsp); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
} |
// Checks that a frame below the top of the stack with missing unwind info |
@@ -223,13 +265,15 @@ TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) { |
// First stack, with a bad function below the top of the stack. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetNoRuntimeFunction( |
image_base_for_module_with_bad_function, |
&context); |
- EXPECT_FALSE(unwinder->TryUnwind(&context)); |
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
} |
{ |
@@ -237,10 +281,11 @@ TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) { |
// unwind info from the previously-seen module is blacklisted. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
unwind_functions_->SetNoRuntimeFunction( |
image_base_for_module_with_bad_function, |
&context); |
- EXPECT_FALSE(unwinder->TryUnwind(&context)); |
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
} |
{ |
@@ -251,18 +296,24 @@ TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) { |
// module. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
unwind_functions_->SetHasRuntimeFunction( |
image_base_for_module_with_bad_function, |
&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction( |
image_base_for_module_with_bad_function, |
&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
} |
{ |
@@ -273,16 +324,22 @@ TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) { |
// previously-seen module. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
unwind_functions_->SetNoRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetHasRuntimeFunction( |
image_base_for_module_with_bad_function, |
&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ module.Set(nullptr); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
} |
} |
@@ -296,21 +353,25 @@ TEST_F(Win32StackFrameUnwinderTest, ModuleFromQuestionableFrameNotBlacklisted) { |
// First stack, with both the first and second frames missing unwind info. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
unwind_functions_->SetNoRuntimeFunction(&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module, |
&context); |
- EXPECT_FALSE(unwinder->TryUnwind(&context)); |
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
} |
{ |
// Second stack; check that the questionable module was not blacklisted. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module, |
&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
} |
} |
@@ -323,52 +384,57 @@ TEST_F(Win32StackFrameUnwinderTest, RuntimeFunctionSanityCheck) { |
// instruction pointer between the two. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
RUNTIME_FUNCTION runtime_function = {0}; |
runtime_function.BeginAddress = 128; |
runtime_function.EndAddress = 512; |
unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
runtime_function, 256, |
&context); |
- EXPECT_TRUE(unwinder->TryUnwind(&context)); |
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
+ EXPECT_TRUE(module.IsValid()); |
} |
{ |
// Test begin address greater than end address. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
RUNTIME_FUNCTION runtime_function = {0}; |
runtime_function.BeginAddress = 512; |
runtime_function.EndAddress = 128; |
unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
runtime_function, 256, |
&context); |
- EXPECT_FALSE(unwinder->TryUnwind(&context)); |
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
} |
{ |
// Test instruction pointer before begin address. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
RUNTIME_FUNCTION runtime_function = {0}; |
runtime_function.BeginAddress = 128; |
runtime_function.EndAddress = 512; |
unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
runtime_function, 50, |
&context); |
- EXPECT_FALSE(unwinder->TryUnwind(&context)); |
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
} |
{ |
// Test instruction pointer after end address. |
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
CONTEXT context = {0}; |
+ ScopedModuleHandle module; |
RUNTIME_FUNCTION runtime_function = {0}; |
runtime_function.BeginAddress = 128; |
runtime_function.EndAddress = 512; |
unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
runtime_function, 600, |
&context); |
- EXPECT_FALSE(unwinder->TryUnwind(&context)); |
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
} |
} |