LEFT | RIGHT |
(no file at all) | |
1 // Copyright (c) 2006, Google Inc. | 1 // Copyright (c) 2006, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 #include "google_breakpad/processor/call_stack.h" | 44 #include "google_breakpad/processor/call_stack.h" |
45 #include "google_breakpad/processor/code_module.h" | 45 #include "google_breakpad/processor/code_module.h" |
46 #include "google_breakpad/processor/code_modules.h" | 46 #include "google_breakpad/processor/code_modules.h" |
47 #include "google_breakpad/processor/minidump.h" | 47 #include "google_breakpad/processor/minidump.h" |
48 #include "google_breakpad/processor/minidump_processor.h" | 48 #include "google_breakpad/processor/minidump_processor.h" |
49 #include "google_breakpad/processor/process_state.h" | 49 #include "google_breakpad/processor/process_state.h" |
50 #include "google_breakpad/processor/stack_frame.h" | 50 #include "google_breakpad/processor/stack_frame.h" |
51 #include "google_breakpad/processor/symbol_supplier.h" | 51 #include "google_breakpad/processor/symbol_supplier.h" |
52 #include "processor/logging.h" | 52 #include "processor/logging.h" |
53 #include "processor/scoped_ptr.h" | 53 #include "processor/scoped_ptr.h" |
| 54 #include "processor/stackwalker_unittest_utils.h" |
54 | 55 |
55 using std::map; | 56 using std::map; |
56 | 57 |
57 namespace google_breakpad { | 58 namespace google_breakpad { |
58 class MockMinidump : public Minidump { | 59 class MockMinidump : public Minidump { |
59 public: | 60 public: |
60 MockMinidump() : Minidump("") { | 61 MockMinidump() : Minidump("") { |
61 } | 62 } |
62 | 63 |
63 MOCK_METHOD0(Read, bool()); | 64 MOCK_METHOD0(Read, bool()); |
64 MOCK_CONST_METHOD0(path, string()); | 65 MOCK_CONST_METHOD0(path, string()); |
65 MOCK_CONST_METHOD0(header, const MDRawHeader*()); | 66 MOCK_CONST_METHOD0(header, const MDRawHeader*()); |
66 MOCK_METHOD0(GetThreadList, MinidumpThreadList*()); | 67 MOCK_METHOD0(GetThreadList, MinidumpThreadList*()); |
67 }; | 68 MOCK_METHOD0(GetSystemInfo, MinidumpSystemInfo*()); |
68 } | 69 MOCK_METHOD0(GetBreakpadInfo, MinidumpBreakpadInfo*()); |
| 70 MOCK_METHOD0(GetException, MinidumpException*()); |
| 71 MOCK_METHOD0(GetAssertion, MinidumpAssertion*()); |
| 72 MOCK_METHOD0(GetModuleList, MinidumpModuleList*()); |
| 73 }; |
| 74 |
| 75 class MockMinidumpThreadList : public MinidumpThreadList { |
| 76 public: |
| 77 MockMinidumpThreadList() : MinidumpThreadList(NULL) {} |
| 78 |
| 79 MOCK_CONST_METHOD0(thread_count, unsigned int()); |
| 80 MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int)); |
| 81 }; |
| 82 |
| 83 class MockMinidumpThread : public MinidumpThread { |
| 84 public: |
| 85 MockMinidumpThread() : MinidumpThread(NULL) {} |
| 86 |
| 87 MOCK_CONST_METHOD1(GetThreadID, bool(u_int32_t*)); |
| 88 MOCK_METHOD0(GetContext, MinidumpContext*()); |
| 89 MOCK_METHOD0(GetMemory, MinidumpMemoryRegion*()); |
| 90 }; |
| 91 |
| 92 // This is crappy, but MinidumpProcessor really does want a |
| 93 // MinidumpMemoryRegion. |
| 94 class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { |
| 95 public: |
| 96 MockMinidumpMemoryRegion(u_int64_t base, const string& contents) : |
| 97 MinidumpMemoryRegion(NULL) { |
| 98 region_.Init(base, contents); |
| 99 } |
| 100 |
| 101 u_int64_t GetBase() const { return region_.GetBase(); } |
| 102 u_int32_t GetSize() const { return region_.GetSize(); } |
| 103 |
| 104 bool GetMemoryAtAddress(u_int64_t address, u_int8_t *value) const { |
| 105 return region_.GetMemoryAtAddress(address, value); |
| 106 } |
| 107 bool GetMemoryAtAddress(u_int64_t address, u_int16_t *value) const { |
| 108 return region_.GetMemoryAtAddress(address, value); |
| 109 } |
| 110 bool GetMemoryAtAddress(u_int64_t address, u_int32_t *value) const { |
| 111 return region_.GetMemoryAtAddress(address, value); |
| 112 } |
| 113 bool GetMemoryAtAddress(u_int64_t address, u_int64_t *value) const { |
| 114 return region_.GetMemoryAtAddress(address, value); |
| 115 } |
| 116 |
| 117 MockMemoryRegion region_; |
| 118 }; |
| 119 |
| 120 } // namespace google_breakpad |
69 | 121 |
70 namespace { | 122 namespace { |
71 | 123 |
72 using google_breakpad::BasicSourceLineResolver; | 124 using google_breakpad::BasicSourceLineResolver; |
73 using google_breakpad::CallStack; | 125 using google_breakpad::CallStack; |
74 using google_breakpad::CodeModule; | 126 using google_breakpad::CodeModule; |
| 127 using google_breakpad::MinidumpContext; |
| 128 using google_breakpad::MinidumpMemoryRegion; |
75 using google_breakpad::MinidumpProcessor; | 129 using google_breakpad::MinidumpProcessor; |
| 130 using google_breakpad::MinidumpSystemInfo; |
76 using google_breakpad::MinidumpThreadList; | 131 using google_breakpad::MinidumpThreadList; |
77 using google_breakpad::MinidumpThread; | 132 using google_breakpad::MinidumpThread; |
78 using google_breakpad::MockMinidump; | 133 using google_breakpad::MockMinidump; |
| 134 using google_breakpad::MockMinidumpMemoryRegion; |
| 135 using google_breakpad::MockMinidumpThread; |
| 136 using google_breakpad::MockMinidumpThreadList; |
79 using google_breakpad::ProcessState; | 137 using google_breakpad::ProcessState; |
80 using google_breakpad::scoped_ptr; | 138 using google_breakpad::scoped_ptr; |
81 using google_breakpad::SymbolSupplier; | 139 using google_breakpad::SymbolSupplier; |
82 using google_breakpad::SystemInfo; | 140 using google_breakpad::SystemInfo; |
83 using ::testing::_; | 141 using ::testing::_; |
| 142 using ::testing::DoAll; |
84 using ::testing::Mock; | 143 using ::testing::Mock; |
85 using ::testing::Ne; | 144 using ::testing::Ne; |
86 using ::testing::Property; | 145 using ::testing::Property; |
87 using ::testing::Return; | 146 using ::testing::Return; |
| 147 using ::testing::SetArgumentPointee; |
88 | 148 |
89 static const char *kSystemInfoOS = "Windows NT"; | 149 static const char *kSystemInfoOS = "Windows NT"; |
90 static const char *kSystemInfoOSShort = "windows"; | 150 static const char *kSystemInfoOSShort = "windows"; |
91 static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; | 151 static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; |
92 static const char *kSystemInfoCPU = "x86"; | 152 static const char *kSystemInfoCPU = "x86"; |
93 static const char *kSystemInfoCPUInfo = | 153 static const char *kSystemInfoCPUInfo = |
94 "GenuineIntel family 6 model 13 stepping 8"; | 154 "GenuineIntel family 6 model 13 stepping 8"; |
95 | 155 |
96 #define ASSERT_TRUE_ABORT(cond) \ | 156 #define ASSERT_TRUE_ABORT(cond) \ |
97 if (!(cond)) { \ | 157 if (!(cond)) { \ |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 } | 259 } |
200 | 260 |
201 void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) { | 261 void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) { |
202 map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); | 262 map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); |
203 if (it != memory_buffers_.end()) { | 263 if (it != memory_buffers_.end()) { |
204 delete [] it->second; | 264 delete [] it->second; |
205 memory_buffers_.erase(it); | 265 memory_buffers_.erase(it); |
206 } | 266 } |
207 } | 267 } |
208 | 268 |
209 // A mock symbol supplier that always returns NOT_FOUND; one current | 269 // A test system info stream, just returns values from the |
210 // use for testing the processor's caching of symbol lookups. | 270 // MDRawSystemInfo fed to it. |
211 class MockSymbolSupplier : public SymbolSupplier { | 271 class TestMinidumpSystemInfo : public MinidumpSystemInfo { |
212 public: | 272 public: |
213 MockSymbolSupplier() { } | 273 TestMinidumpSystemInfo(MDRawSystemInfo info) : |
214 MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule*, | 274 MinidumpSystemInfo(NULL) { |
215 const SystemInfo*, | 275 valid_ = true; |
216 string*)); | 276 system_info_ = info; |
217 MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule*, | 277 csd_version_ = new string(""); |
218 const SystemInfo*, | 278 } |
219 string*, | 279 }; |
220 string*)); | 280 |
221 MOCK_METHOD4(GetCStringSymbolData, SymbolResult(const CodeModule*, | 281 // A test minidump context, just returns the MDRawContextX86 |
222 const SystemInfo*, | 282 // fed to it. |
223 string*, | 283 class TestMinidumpContext : public MinidumpContext { |
224 char**)); | 284 public: |
225 MOCK_METHOD1(FreeSymbolData, void(const CodeModule*)); | 285 TestMinidumpContext(const MDRawContextX86& context) : MinidumpContext(NULL) { |
| 286 valid_ = true; |
| 287 context_.x86 = new MDRawContextX86(context); |
| 288 context_flags_ = MD_CONTEXT_X86; |
| 289 } |
226 }; | 290 }; |
227 | 291 |
228 class MinidumpProcessorTest : public ::testing::Test { | 292 class MinidumpProcessorTest : public ::testing::Test { |
229 }; | 293 }; |
230 | 294 |
231 TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) { | 295 TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) { |
232 MockMinidump dump; | 296 MockMinidump dump; |
233 TestSymbolSupplier supplier; | 297 TestSymbolSupplier supplier; |
234 BasicSourceLineResolver resolver; | 298 BasicSourceLineResolver resolver; |
235 MinidumpProcessor processor(&supplier, &resolver); | 299 MinidumpProcessor processor(&supplier, &resolver); |
236 ProcessState state; | 300 ProcessState state; |
237 | 301 |
238 EXPECT_EQ(processor.Process("nonexistent minidump", &state), | 302 EXPECT_EQ(processor.Process("nonexistent minidump", &state), |
239 google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND); | 303 google_breakpad::PROCESS_ERROR_MINIDUMP_NOT_FOUND); |
240 | 304 |
241 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); | 305 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); |
242 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); | 306 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); |
243 | 307 |
244 MDRawHeader fakeHeader; | 308 MDRawHeader fakeHeader; |
245 fakeHeader.time_date_stamp = 0; | 309 fakeHeader.time_date_stamp = 0; |
246 EXPECT_CALL(dump, header()).WillOnce(Return((MDRawHeader*)NULL)). | 310 EXPECT_CALL(dump, header()).WillOnce(Return((MDRawHeader*)NULL)). |
247 WillRepeatedly(Return(&fakeHeader)); | 311 WillRepeatedly(Return(&fakeHeader)); |
| 312 |
248 EXPECT_EQ(processor.Process(&dump, &state), | 313 EXPECT_EQ(processor.Process(&dump, &state), |
249 google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER); | 314 google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER); |
250 | 315 |
251 EXPECT_CALL(dump, GetThreadList()). | 316 EXPECT_CALL(dump, GetThreadList()). |
252 WillOnce(Return((MinidumpThreadList*)NULL)); | 317 WillOnce(Return((MinidumpThreadList*)NULL)); |
| 318 EXPECT_CALL(dump, GetSystemInfo()). |
| 319 WillRepeatedly(Return((MinidumpSystemInfo*)NULL)); |
| 320 |
253 EXPECT_EQ(processor.Process(&dump, &state), | 321 EXPECT_EQ(processor.Process(&dump, &state), |
254 google_breakpad::PROCESS_ERROR_NO_THREAD_LIST); | 322 google_breakpad::PROCESS_ERROR_NO_THREAD_LIST); |
255 } | 323 } |
256 | 324 |
257 // This test case verifies that the symbol supplier is only consulted | 325 // This test case verifies that the symbol supplier is only consulted |
258 // once per minidump per module. | 326 // once per minidump per module. |
259 TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) { | 327 TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) { |
260 MockSymbolSupplier supplier; | 328 MockSymbolSupplier supplier; |
261 BasicSourceLineResolver resolver; | 329 BasicSourceLineResolver resolver; |
262 MinidumpProcessor processor(&supplier, &resolver); | 330 MinidumpProcessor processor(&supplier, &resolver); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 // EXPLOITABILITY_NOT_ANALYZED. | 433 // EXPLOITABILITY_NOT_ANALYZED. |
366 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED, | 434 ASSERT_EQ(google_breakpad::EXPLOITABILITY_NOT_ANALYZED, |
367 state.exploitability()); | 435 state.exploitability()); |
368 | 436 |
369 // Test that the symbol supplier can interrupt processing | 437 // Test that the symbol supplier can interrupt processing |
370 state.Clear(); | 438 state.Clear(); |
371 supplier.set_interrupt(true); | 439 supplier.set_interrupt(true); |
372 ASSERT_EQ(processor.Process(minidump_file, &state), | 440 ASSERT_EQ(processor.Process(minidump_file, &state), |
373 google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED); | 441 google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED); |
374 } | 442 } |
| 443 |
| 444 TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) { |
| 445 MockMinidump dump; |
| 446 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); |
| 447 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); |
| 448 |
| 449 MDRawHeader fake_header; |
| 450 fake_header.time_date_stamp = 0; |
| 451 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); |
| 452 |
| 453 MDRawSystemInfo raw_system_info; |
| 454 memset(&raw_system_info, 0, sizeof(raw_system_info)); |
| 455 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; |
| 456 raw_system_info.platform_id = MD_OS_WIN32_NT; |
| 457 TestMinidumpSystemInfo dump_system_info(raw_system_info); |
| 458 |
| 459 EXPECT_CALL(dump, GetSystemInfo()). |
| 460 WillRepeatedly(Return(&dump_system_info)); |
| 461 |
| 462 MockMinidumpThreadList thread_list; |
| 463 EXPECT_CALL(dump, GetThreadList()). |
| 464 WillOnce(Return(&thread_list)); |
| 465 |
| 466 // Return a thread missing stack memory. |
| 467 MockMinidumpThread no_memory_thread; |
| 468 EXPECT_CALL(no_memory_thread, GetThreadID(_)). |
| 469 WillRepeatedly(DoAll(SetArgumentPointee<0>(1), |
| 470 Return(true))); |
| 471 EXPECT_CALL(no_memory_thread, GetMemory()). |
| 472 WillRepeatedly(Return((MinidumpMemoryRegion*)NULL)); |
| 473 |
| 474 MDRawContextX86 no_memory_thread_raw_context; |
| 475 memset(&no_memory_thread_raw_context, 0, |
| 476 sizeof(no_memory_thread_raw_context)); |
| 477 no_memory_thread_raw_context.context_flags = MD_CONTEXT_X86_FULL; |
| 478 const u_int32_t kExpectedEIP = 0xabcd1234; |
| 479 no_memory_thread_raw_context.eip = kExpectedEIP; |
| 480 TestMinidumpContext no_memory_thread_context(no_memory_thread_raw_context); |
| 481 EXPECT_CALL(no_memory_thread, GetContext()). |
| 482 WillRepeatedly(Return(&no_memory_thread_context)); |
| 483 |
| 484 EXPECT_CALL(thread_list, thread_count()). |
| 485 WillRepeatedly(Return(1)); |
| 486 EXPECT_CALL(thread_list, GetThreadAtIndex(0)). |
| 487 WillOnce(Return(&no_memory_thread)); |
| 488 |
| 489 MinidumpProcessor processor((SymbolSupplier*)NULL, NULL); |
| 490 ProcessState state; |
| 491 EXPECT_EQ(processor.Process(&dump, &state), |
| 492 google_breakpad::PROCESS_OK); |
| 493 |
| 494 // Should have a single thread with a single frame in it. |
| 495 ASSERT_EQ(1, state.threads()->size()); |
| 496 ASSERT_EQ(1, state.threads()->at(0)->frames()->size()); |
| 497 ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction); |
| 498 } |
| 499 |
| 500 TEST_F(MinidumpProcessorTest, TestThreadMissingContext) { |
| 501 MockMinidump dump; |
| 502 EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); |
| 503 EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); |
| 504 |
| 505 MDRawHeader fake_header; |
| 506 fake_header.time_date_stamp = 0; |
| 507 EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); |
| 508 |
| 509 MDRawSystemInfo raw_system_info; |
| 510 memset(&raw_system_info, 0, sizeof(raw_system_info)); |
| 511 raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; |
| 512 raw_system_info.platform_id = MD_OS_WIN32_NT; |
| 513 TestMinidumpSystemInfo dump_system_info(raw_system_info); |
| 514 |
| 515 EXPECT_CALL(dump, GetSystemInfo()). |
| 516 WillRepeatedly(Return(&dump_system_info)); |
| 517 |
| 518 MockMinidumpThreadList thread_list; |
| 519 EXPECT_CALL(dump, GetThreadList()). |
| 520 WillOnce(Return(&thread_list)); |
| 521 |
| 522 // Return a thread missing a thread context. |
| 523 MockMinidumpThread no_context_thread; |
| 524 EXPECT_CALL(no_context_thread, GetThreadID(_)). |
| 525 WillRepeatedly(DoAll(SetArgumentPointee<0>(1), |
| 526 Return(true))); |
| 527 EXPECT_CALL(no_context_thread, GetContext()). |
| 528 WillRepeatedly(Return((MinidumpContext*)NULL)); |
| 529 |
| 530 // The memory contents don't really matter here, since it won't be used. |
| 531 MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx"); |
| 532 EXPECT_CALL(no_context_thread, GetMemory()). |
| 533 WillRepeatedly(Return(&no_context_thread_memory)); |
| 534 |
| 535 EXPECT_CALL(thread_list, thread_count()). |
| 536 WillRepeatedly(Return(1)); |
| 537 EXPECT_CALL(thread_list, GetThreadAtIndex(0)). |
| 538 WillOnce(Return(&no_context_thread)); |
| 539 |
| 540 MinidumpProcessor processor((SymbolSupplier*)NULL, NULL); |
| 541 ProcessState state; |
| 542 EXPECT_EQ(processor.Process(&dump, &state), |
| 543 google_breakpad::PROCESS_OK); |
| 544 |
| 545 // Should have a single thread with zero frames. |
| 546 ASSERT_EQ(1, state.threads()->size()); |
| 547 ASSERT_EQ(0, state.threads()->at(0)->frames()->size()); |
| 548 } |
| 549 |
375 } // namespace | 550 } // namespace |
376 | 551 |
377 int main(int argc, char *argv[]) { | 552 int main(int argc, char *argv[]) { |
378 ::testing::InitGoogleTest(&argc, argv); | 553 ::testing::InitGoogleTest(&argc, argv); |
379 return RUN_ALL_TESTS(); | 554 return RUN_ALL_TESTS(); |
380 } | 555 } |
LEFT | RIGHT |