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 <vector> | 5 #include <vector> |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "base/profiler/win32_stack_frame_unwinder.h" | 9 #include "base/profiler/win32_stack_frame_unwinder.h" |
10 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
11 | 11 |
12 namespace base { | 12 namespace base { |
13 | 13 |
14 namespace { | 14 namespace { |
15 | 15 |
16 class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { | 16 class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions { |
17 public: | 17 public: |
18 TestUnwindFunctions(); | 18 TestUnwindFunctions(); |
19 | 19 |
20 PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter, | 20 PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter, |
21 PDWORD64 image_base) override; | 21 PDWORD64 image_base) override; |
22 void VirtualUnwind(DWORD64 image_base, | 22 void VirtualUnwind(DWORD64 image_base, |
23 DWORD64 program_counter, | 23 DWORD64 program_counter, |
24 PRUNTIME_FUNCTION runtime_function, | 24 PRUNTIME_FUNCTION runtime_function, |
25 CONTEXT* context) override; | 25 CONTEXT* context) override; |
| 26 ScopedModuleHandle GetModuleForProgramCounter( |
| 27 DWORD64 program_counter) override; |
| 28 |
| 29 // Instructs GetModuleForProgramCounter to return null on the next call. |
| 30 void SetUnloadedModule(); |
26 | 31 |
27 // These functions set whether the next frame will have a RUNTIME_FUNCTION, | 32 // These functions set whether the next frame will have a RUNTIME_FUNCTION, |
28 // and allow specification of a custom image_base. | 33 // and allow specification of a custom image_base. |
29 void SetHasRuntimeFunction(CONTEXT* context); | 34 void SetHasRuntimeFunction(CONTEXT* context); |
30 void SetHasRuntimeFunction(DWORD64 image_base, CONTEXT* context); | 35 void SetHasRuntimeFunction(DWORD64 image_base, CONTEXT* context); |
31 void SetHasRuntimeFunction(DWORD64 image_base, | 36 void SetHasRuntimeFunction(DWORD64 image_base, |
32 const RUNTIME_FUNCTION& runtime_function, | 37 const RUNTIME_FUNCTION& runtime_function, |
33 DWORD program_counter_offset, | 38 DWORD program_counter_offset, |
34 CONTEXT* context); | 39 CONTEXT* context); |
35 void SetNoRuntimeFunction(CONTEXT* context); | 40 void SetNoRuntimeFunction(CONTEXT* context); |
36 void SetNoRuntimeFunction(DWORD64 image_base, CONTEXT* context); | 41 void SetNoRuntimeFunction(DWORD64 image_base, CONTEXT* context); |
37 | 42 |
38 private: | 43 private: |
39 enum RuntimeFunctionState { NO_RUNTIME_FUNCTION, HAS_RUNTIME_FUNCTION }; | 44 enum RuntimeFunctionState { NO_RUNTIME_FUNCTION, HAS_RUNTIME_FUNCTION }; |
40 | 45 |
41 enum { kImageBaseIncrement = 1 << 20 }; | 46 enum { kImageBaseIncrement = 1 << 20 }; |
42 | 47 |
43 // Sets whether the next frame should have a RUNTIME_FUNCTION, and allows | 48 // Sets whether the next frame should have a RUNTIME_FUNCTION, and allows |
44 // specification of a custom image_base. | 49 // specification of a custom image_base. |
45 void SetNextFrameState(RuntimeFunctionState runtime_function_state, | 50 void SetNextFrameState(RuntimeFunctionState runtime_function_state, |
46 DWORD64 image_base, | 51 DWORD64 image_base, |
47 CONTEXT* context); | 52 CONTEXT* context); |
48 | 53 |
49 static RUNTIME_FUNCTION* const kInvalidRuntimeFunction; | 54 static RUNTIME_FUNCTION* const kInvalidRuntimeFunction; |
50 | 55 |
| 56 bool module_is_loaded_; |
51 DWORD64 expected_program_counter_; | 57 DWORD64 expected_program_counter_; |
52 DWORD64 custom_image_base_; | 58 DWORD64 custom_image_base_; |
53 DWORD64 next_image_base_; | 59 DWORD64 next_image_base_; |
54 DWORD64 expected_image_base_; | 60 DWORD64 expected_image_base_; |
55 RUNTIME_FUNCTION* next_runtime_function_; | 61 RUNTIME_FUNCTION* next_runtime_function_; |
56 std::vector<RUNTIME_FUNCTION> runtime_functions_; | 62 std::vector<RUNTIME_FUNCTION> runtime_functions_; |
57 | 63 |
58 DISALLOW_COPY_AND_ASSIGN(TestUnwindFunctions); | 64 DISALLOW_COPY_AND_ASSIGN(TestUnwindFunctions); |
59 }; | 65 }; |
60 | 66 |
61 RUNTIME_FUNCTION* const TestUnwindFunctions::kInvalidRuntimeFunction = | 67 RUNTIME_FUNCTION* const TestUnwindFunctions::kInvalidRuntimeFunction = |
62 reinterpret_cast<RUNTIME_FUNCTION*>(static_cast<uintptr_t>(-1)); | 68 reinterpret_cast<RUNTIME_FUNCTION*>(static_cast<uintptr_t>(-1)); |
63 | 69 |
64 TestUnwindFunctions::TestUnwindFunctions() | 70 TestUnwindFunctions::TestUnwindFunctions() |
65 : expected_program_counter_(0), | 71 : module_is_loaded_(true), |
| 72 expected_program_counter_(0), |
66 custom_image_base_(0), | 73 custom_image_base_(0), |
67 next_image_base_(kImageBaseIncrement), | 74 next_image_base_(kImageBaseIncrement), |
68 expected_image_base_(0), | 75 expected_image_base_(0), |
69 next_runtime_function_(kInvalidRuntimeFunction) { | 76 next_runtime_function_(kInvalidRuntimeFunction) { |
70 } | 77 } |
71 | 78 |
72 PRUNTIME_FUNCTION TestUnwindFunctions::LookupFunctionEntry( | 79 PRUNTIME_FUNCTION TestUnwindFunctions::LookupFunctionEntry( |
73 DWORD64 program_counter, | 80 DWORD64 program_counter, |
74 PDWORD64 image_base) { | 81 PDWORD64 image_base) { |
75 EXPECT_EQ(expected_program_counter_, program_counter); | 82 EXPECT_EQ(expected_program_counter_, program_counter); |
(...skipping 18 matching lines...) Expand all Loading... |
94 << "before invoking TryUnwind()"; | 101 << "before invoking TryUnwind()"; |
95 EXPECT_EQ(expected_image_base_, image_base); | 102 EXPECT_EQ(expected_image_base_, image_base); |
96 expected_image_base_ = 0; | 103 expected_image_base_ = 0; |
97 EXPECT_EQ(expected_program_counter_, program_counter); | 104 EXPECT_EQ(expected_program_counter_, program_counter); |
98 expected_program_counter_ = 0; | 105 expected_program_counter_ = 0; |
99 // This function should only be called when LookupFunctionEntry returns | 106 // This function should only be called when LookupFunctionEntry returns |
100 // a RUNTIME_FUNCTION. | 107 // a RUNTIME_FUNCTION. |
101 EXPECT_EQ(&runtime_functions_.back(), runtime_function); | 108 EXPECT_EQ(&runtime_functions_.back(), runtime_function); |
102 } | 109 } |
103 | 110 |
| 111 ScopedModuleHandle TestUnwindFunctions::GetModuleForProgramCounter( |
| 112 DWORD64 program_counter) { |
| 113 bool return_non_null_value = module_is_loaded_; |
| 114 module_is_loaded_ = true; |
| 115 return ScopedModuleHandle(return_non_null_value ? |
| 116 ModuleHandleTraits::kNonNullModuleForTesting : |
| 117 nullptr); |
| 118 } |
| 119 |
| 120 void TestUnwindFunctions::SetUnloadedModule() { |
| 121 module_is_loaded_ = false; |
| 122 } |
| 123 |
104 void TestUnwindFunctions::SetHasRuntimeFunction(CONTEXT* context) { | 124 void TestUnwindFunctions::SetHasRuntimeFunction(CONTEXT* context) { |
105 SetNextFrameState(HAS_RUNTIME_FUNCTION, 0, context); | 125 SetNextFrameState(HAS_RUNTIME_FUNCTION, 0, context); |
106 } | 126 } |
107 | 127 |
108 void TestUnwindFunctions::SetHasRuntimeFunction(DWORD64 image_base, | 128 void TestUnwindFunctions::SetHasRuntimeFunction(DWORD64 image_base, |
109 CONTEXT* context) { | 129 CONTEXT* context) { |
110 SetNextFrameState(HAS_RUNTIME_FUNCTION, image_base, context); | 130 SetNextFrameState(HAS_RUNTIME_FUNCTION, image_base, context); |
111 } | 131 } |
112 | 132 |
113 void TestUnwindFunctions::SetHasRuntimeFunction( | 133 void TestUnwindFunctions::SetHasRuntimeFunction( |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 Win32StackFrameUnwinderTest::CreateUnwinder() { | 197 Win32StackFrameUnwinderTest::CreateUnwinder() { |
178 scoped_ptr<TestUnwindFunctions> unwind_functions(new TestUnwindFunctions); | 198 scoped_ptr<TestUnwindFunctions> unwind_functions(new TestUnwindFunctions); |
179 unwind_functions_ = unwind_functions.get(); | 199 unwind_functions_ = unwind_functions.get(); |
180 return make_scoped_ptr(new Win32StackFrameUnwinder(unwind_functions.Pass())); | 200 return make_scoped_ptr(new Win32StackFrameUnwinder(unwind_functions.Pass())); |
181 } | 201 } |
182 | 202 |
183 // Checks the case where all frames have unwind information. | 203 // Checks the case where all frames have unwind information. |
184 TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { | 204 TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) { |
185 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 205 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
186 CONTEXT context = {0}; | 206 CONTEXT context = {0}; |
| 207 ScopedModuleHandle module; |
187 | 208 |
188 unwind_functions_->SetHasRuntimeFunction(&context); | 209 unwind_functions_->SetHasRuntimeFunction(&context); |
189 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 210 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 211 EXPECT_TRUE(module.IsValid()); |
190 | 212 |
191 unwind_functions_->SetHasRuntimeFunction(&context); | 213 unwind_functions_->SetHasRuntimeFunction(&context); |
192 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 214 module.Set(nullptr); |
| 215 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 216 EXPECT_TRUE(module.IsValid()); |
193 | 217 |
194 unwind_functions_->SetHasRuntimeFunction(&context); | 218 unwind_functions_->SetHasRuntimeFunction(&context); |
195 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 219 module.Set(nullptr); |
| 220 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 221 EXPECT_TRUE(module.IsValid()); |
| 222 } |
| 223 |
| 224 // Checks that an instruction pointer in an unloaded module fails to unwind. |
| 225 TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) { |
| 226 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
| 227 CONTEXT context = {0}; |
| 228 ScopedModuleHandle module; |
| 229 |
| 230 unwind_functions_->SetUnloadedModule(); |
| 231 EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
196 } | 232 } |
197 | 233 |
198 // Checks that the CONTEXT's stack pointer gets popped when the top frame has no | 234 // Checks that the CONTEXT's stack pointer gets popped when the top frame has no |
199 // unwind information. | 235 // unwind information. |
200 TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) { | 236 TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) { |
201 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 237 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
202 CONTEXT context = {0}; | 238 CONTEXT context = {0}; |
| 239 ScopedModuleHandle module; |
203 const DWORD64 original_rsp = 128; | 240 const DWORD64 original_rsp = 128; |
204 context.Rsp = original_rsp; | 241 context.Rsp = original_rsp; |
205 | 242 |
206 unwind_functions_->SetNoRuntimeFunction(&context); | 243 unwind_functions_->SetNoRuntimeFunction(&context); |
207 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 244 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
208 EXPECT_EQ(original_rsp, context.Rip); | 245 EXPECT_EQ(original_rsp, context.Rip); |
209 EXPECT_EQ(original_rsp + 8, context.Rsp); | 246 EXPECT_EQ(original_rsp + 8, context.Rsp); |
| 247 EXPECT_TRUE(module.IsValid()); |
210 | 248 |
211 unwind_functions_->SetHasRuntimeFunction(&context); | 249 unwind_functions_->SetHasRuntimeFunction(&context); |
212 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 250 module.Set(nullptr); |
| 251 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 252 EXPECT_TRUE(module.IsValid()); |
213 | 253 |
214 unwind_functions_->SetHasRuntimeFunction(&context); | 254 unwind_functions_->SetHasRuntimeFunction(&context); |
215 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 255 module.Set(nullptr); |
| 256 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 257 EXPECT_TRUE(module.IsValid()); |
216 } | 258 } |
217 | 259 |
218 // Checks that a frame below the top of the stack with missing unwind info | 260 // Checks that a frame below the top of the stack with missing unwind info |
219 // results in blacklisting the module. | 261 // results in blacklisting the module. |
220 TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) { | 262 TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) { |
221 const DWORD64 image_base_for_module_with_bad_function = 1024; | 263 const DWORD64 image_base_for_module_with_bad_function = 1024; |
222 { | 264 { |
223 // First stack, with a bad function below the top of the stack. | 265 // First stack, with a bad function below the top of the stack. |
224 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 266 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
225 CONTEXT context = {0}; | 267 CONTEXT context = {0}; |
| 268 ScopedModuleHandle module; |
226 unwind_functions_->SetHasRuntimeFunction(&context); | 269 unwind_functions_->SetHasRuntimeFunction(&context); |
227 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 270 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 271 EXPECT_TRUE(module.IsValid()); |
228 | 272 |
229 unwind_functions_->SetNoRuntimeFunction( | 273 unwind_functions_->SetNoRuntimeFunction( |
230 image_base_for_module_with_bad_function, | 274 image_base_for_module_with_bad_function, |
231 &context); | 275 &context); |
232 EXPECT_FALSE(unwinder->TryUnwind(&context)); | 276 EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
233 } | 277 } |
234 | 278 |
235 { | 279 { |
236 // Second stack; check that a function at the top of the stack without | 280 // Second stack; check that a function at the top of the stack without |
237 // unwind info from the previously-seen module is blacklisted. | 281 // unwind info from the previously-seen module is blacklisted. |
238 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 282 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
239 CONTEXT context = {0}; | 283 CONTEXT context = {0}; |
| 284 ScopedModuleHandle module; |
240 unwind_functions_->SetNoRuntimeFunction( | 285 unwind_functions_->SetNoRuntimeFunction( |
241 image_base_for_module_with_bad_function, | 286 image_base_for_module_with_bad_function, |
242 &context); | 287 &context); |
243 EXPECT_FALSE(unwinder->TryUnwind(&context)); | 288 EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
244 } | 289 } |
245 | 290 |
246 { | 291 { |
247 // Third stack; check that a function at the top of the stack *with* unwind | 292 // Third stack; check that a function at the top of the stack *with* unwind |
248 // info from the previously-seen module is not blacklisted. Then check that | 293 // info from the previously-seen module is not blacklisted. Then check that |
249 // functions below the top of the stack with unwind info are not | 294 // functions below the top of the stack with unwind info are not |
250 // blacklisted, regardless of whether they are in the previously-seen | 295 // blacklisted, regardless of whether they are in the previously-seen |
251 // module. | 296 // module. |
252 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 297 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
253 CONTEXT context = {0}; | 298 CONTEXT context = {0}; |
| 299 ScopedModuleHandle module; |
254 unwind_functions_->SetHasRuntimeFunction( | 300 unwind_functions_->SetHasRuntimeFunction( |
255 image_base_for_module_with_bad_function, | 301 image_base_for_module_with_bad_function, |
256 &context); | 302 &context); |
257 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 303 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 304 EXPECT_TRUE(module.IsValid()); |
258 | 305 |
259 unwind_functions_->SetHasRuntimeFunction(&context); | 306 unwind_functions_->SetHasRuntimeFunction(&context); |
260 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 307 module.Set(nullptr); |
| 308 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 309 EXPECT_TRUE(module.IsValid()); |
261 | 310 |
262 unwind_functions_->SetHasRuntimeFunction( | 311 unwind_functions_->SetHasRuntimeFunction( |
263 image_base_for_module_with_bad_function, | 312 image_base_for_module_with_bad_function, |
264 &context); | 313 &context); |
265 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 314 module.Set(nullptr); |
| 315 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 316 EXPECT_TRUE(module.IsValid()); |
266 } | 317 } |
267 | 318 |
268 { | 319 { |
269 // Fourth stack; check that a function at the top of the stack without | 320 // Fourth stack; check that a function at the top of the stack without |
270 // unwind info and not from the previously-seen module is not | 321 // unwind info and not from the previously-seen module is not |
271 // blacklisted. Then check that functions below the top of the stack with | 322 // blacklisted. Then check that functions below the top of the stack with |
272 // unwind info are not blacklisted, regardless of whether they are in the | 323 // unwind info are not blacklisted, regardless of whether they are in the |
273 // previously-seen module. | 324 // previously-seen module. |
274 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 325 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
275 CONTEXT context = {0}; | 326 CONTEXT context = {0}; |
| 327 ScopedModuleHandle module; |
276 unwind_functions_->SetNoRuntimeFunction(&context); | 328 unwind_functions_->SetNoRuntimeFunction(&context); |
277 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 329 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 330 EXPECT_TRUE(module.IsValid()); |
278 | 331 |
279 unwind_functions_->SetHasRuntimeFunction(&context); | 332 unwind_functions_->SetHasRuntimeFunction(&context); |
280 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 333 module.Set(nullptr); |
| 334 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 335 EXPECT_TRUE(module.IsValid()); |
281 | 336 |
282 unwind_functions_->SetHasRuntimeFunction( | 337 unwind_functions_->SetHasRuntimeFunction( |
283 image_base_for_module_with_bad_function, | 338 image_base_for_module_with_bad_function, |
284 &context); | 339 &context); |
285 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 340 module.Set(nullptr); |
| 341 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 342 EXPECT_TRUE(module.IsValid()); |
286 } | 343 } |
287 } | 344 } |
288 | 345 |
289 // Checks that a frame below the top of the stack with missing unwind info does | 346 // Checks that a frame below the top of the stack with missing unwind info does |
290 // not result in blacklisting the module if the first frame also was missing | 347 // not result in blacklisting the module if the first frame also was missing |
291 // unwind info. This ensures we don't blacklist an innocent module because the | 348 // unwind info. This ensures we don't blacklist an innocent module because the |
292 // first frame was bad but we didn't know it at the time. | 349 // first frame was bad but we didn't know it at the time. |
293 TEST_F(Win32StackFrameUnwinderTest, ModuleFromQuestionableFrameNotBlacklisted) { | 350 TEST_F(Win32StackFrameUnwinderTest, ModuleFromQuestionableFrameNotBlacklisted) { |
294 const DWORD64 image_base_for_questionable_module = 2048; | 351 const DWORD64 image_base_for_questionable_module = 2048; |
295 { | 352 { |
296 // First stack, with both the first and second frames missing unwind info. | 353 // First stack, with both the first and second frames missing unwind info. |
297 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 354 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
298 CONTEXT context = {0}; | 355 CONTEXT context = {0}; |
| 356 ScopedModuleHandle module; |
299 unwind_functions_->SetNoRuntimeFunction(&context); | 357 unwind_functions_->SetNoRuntimeFunction(&context); |
300 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 358 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 359 EXPECT_TRUE(module.IsValid()); |
301 | 360 |
302 unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module, | 361 unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module, |
303 &context); | 362 &context); |
304 EXPECT_FALSE(unwinder->TryUnwind(&context)); | 363 EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
305 } | 364 } |
306 | 365 |
307 { | 366 { |
308 // Second stack; check that the questionable module was not blacklisted. | 367 // Second stack; check that the questionable module was not blacklisted. |
309 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 368 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
310 CONTEXT context = {0}; | 369 CONTEXT context = {0}; |
| 370 ScopedModuleHandle module; |
311 unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module, | 371 unwind_functions_->SetNoRuntimeFunction(image_base_for_questionable_module, |
312 &context); | 372 &context); |
313 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 373 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 374 EXPECT_TRUE(module.IsValid()); |
314 } | 375 } |
315 } | 376 } |
316 | 377 |
317 // Checks that frames with RUNTIME_FUNCTION structures with nonsensical values | 378 // Checks that frames with RUNTIME_FUNCTION structures with nonsensical values |
318 // are not unwound. | 379 // are not unwound. |
319 TEST_F(Win32StackFrameUnwinderTest, RuntimeFunctionSanityCheck) { | 380 TEST_F(Win32StackFrameUnwinderTest, RuntimeFunctionSanityCheck) { |
320 const DWORD64 image_base_for_sanity_check = 3072; | 381 const DWORD64 image_base_for_sanity_check = 3072; |
321 { | 382 { |
322 // Test the expected case: end address greater than begin address and | 383 // Test the expected case: end address greater than begin address and |
323 // instruction pointer between the two. | 384 // instruction pointer between the two. |
324 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 385 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
325 CONTEXT context = {0}; | 386 CONTEXT context = {0}; |
| 387 ScopedModuleHandle module; |
326 RUNTIME_FUNCTION runtime_function = {0}; | 388 RUNTIME_FUNCTION runtime_function = {0}; |
327 runtime_function.BeginAddress = 128; | 389 runtime_function.BeginAddress = 128; |
328 runtime_function.EndAddress = 512; | 390 runtime_function.EndAddress = 512; |
329 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, | 391 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
330 runtime_function, 256, | 392 runtime_function, 256, |
331 &context); | 393 &context); |
332 EXPECT_TRUE(unwinder->TryUnwind(&context)); | 394 EXPECT_TRUE(unwinder->TryUnwind(&context, &module)); |
| 395 EXPECT_TRUE(module.IsValid()); |
333 } | 396 } |
334 | 397 |
335 { | 398 { |
336 // Test begin address greater than end address. | 399 // Test begin address greater than end address. |
337 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 400 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
338 CONTEXT context = {0}; | 401 CONTEXT context = {0}; |
| 402 ScopedModuleHandle module; |
339 RUNTIME_FUNCTION runtime_function = {0}; | 403 RUNTIME_FUNCTION runtime_function = {0}; |
340 runtime_function.BeginAddress = 512; | 404 runtime_function.BeginAddress = 512; |
341 runtime_function.EndAddress = 128; | 405 runtime_function.EndAddress = 128; |
342 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, | 406 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
343 runtime_function, 256, | 407 runtime_function, 256, |
344 &context); | 408 &context); |
345 EXPECT_FALSE(unwinder->TryUnwind(&context)); | 409 EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
346 } | 410 } |
347 | 411 |
348 { | 412 { |
349 // Test instruction pointer before begin address. | 413 // Test instruction pointer before begin address. |
350 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 414 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
351 CONTEXT context = {0}; | 415 CONTEXT context = {0}; |
| 416 ScopedModuleHandle module; |
352 RUNTIME_FUNCTION runtime_function = {0}; | 417 RUNTIME_FUNCTION runtime_function = {0}; |
353 runtime_function.BeginAddress = 128; | 418 runtime_function.BeginAddress = 128; |
354 runtime_function.EndAddress = 512; | 419 runtime_function.EndAddress = 512; |
355 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, | 420 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
356 runtime_function, 50, | 421 runtime_function, 50, |
357 &context); | 422 &context); |
358 EXPECT_FALSE(unwinder->TryUnwind(&context)); | 423 EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
359 } | 424 } |
360 | 425 |
361 { | 426 { |
362 // Test instruction pointer after end address. | 427 // Test instruction pointer after end address. |
363 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); | 428 scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder(); |
364 CONTEXT context = {0}; | 429 CONTEXT context = {0}; |
| 430 ScopedModuleHandle module; |
365 RUNTIME_FUNCTION runtime_function = {0}; | 431 RUNTIME_FUNCTION runtime_function = {0}; |
366 runtime_function.BeginAddress = 128; | 432 runtime_function.BeginAddress = 128; |
367 runtime_function.EndAddress = 512; | 433 runtime_function.EndAddress = 512; |
368 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, | 434 unwind_functions_->SetHasRuntimeFunction(image_base_for_sanity_check, |
369 runtime_function, 600, | 435 runtime_function, 600, |
370 &context); | 436 &context); |
371 EXPECT_FALSE(unwinder->TryUnwind(&context)); | 437 EXPECT_FALSE(unwinder->TryUnwind(&context, &module)); |
372 } | 438 } |
373 } | 439 } |
374 | 440 |
375 } // namespace base | 441 } // namespace base |
OLD | NEW |