exception_handler_unittest.cc
1 // Copyright 2010 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #ifdef HAVE_CONFIG_H 30 #include <config.h> // Must come first 31 #endif 32 33 #include <poll.h> 34 #include <pthread.h> 35 #include <stdint.h> 36 #include <unistd.h> 37 #include <signal.h> 38 #include <sys/mman.h> 39 #include <sys/socket.h> 40 #include <sys/uio.h> 41 #include <sys/wait.h> 42 #if defined(__mips__) 43 #include <sys/cachectl.h> 44 #endif 45 46 #include <string> 47 48 #include "breakpad_googletest_includes.h" 49 #include "client/linux/handler/exception_handler.h" 50 #include "client/linux/minidump_writer/minidump_writer.h" 51 #include "common/linux/eintr_wrapper.h" 52 #include "common/linux/ignore_ret.h" 53 #include "common/linux/linux_libc_support.h" 54 #include "common/tests/auto_tempdir.h" 55 #include "common/using_std_string.h" 56 #include "third_party/lss/linux_syscall_support.h" 57 #include "google_breakpad/processor/minidump.h" 58 59 using namespace google_breakpad; 60 61 namespace { 62 63 // Flush the instruction cache for a given memory range. 64 // Only required on ARM and mips. 65 void FlushInstructionCache(const char* memory, uint32_t memory_size) { 66 #if defined(__arm__) 67 long begin = reinterpret_cast<long>(memory); 68 long end = begin + static_cast<long>(memory_size); 69 # if defined(__ANDROID__) 70 // Provided by Android's <unistd.h> 71 cacheflush(begin, end, 0); 72 # elif defined(__linux__) 73 // GLibc/ARM doesn't provide a wrapper for it, do a direct syscall. 74 # ifndef __ARM_NR_cacheflush 75 # define __ARM_NR_cacheflush 0xf0002 76 # endif 77 syscall(__ARM_NR_cacheflush, begin, end, 0); 78 # else 79 # error "Your operating system is not supported yet" 80 # endif 81 #elif defined(__mips__) 82 # if defined(__ANDROID__) 83 // Provided by Android's <unistd.h> 84 long begin = reinterpret_cast<long>(memory); 85 long end = begin + static_cast<long>(memory_size); 86 #if _MIPS_SIM == _ABIO32 87 cacheflush(begin, end, 0); 88 #else 89 syscall(__NR_cacheflush, begin, end, ICACHE); 90 #endif 91 # elif defined(__linux__) 92 // See http://www.linux-mips.org/wiki/Cacheflush_Syscall. 93 cacheflush(const_cast<char*>(memory), memory_size, ICACHE); 94 # else 95 # error "Your operating system is not supported yet" 96 # endif 97 #endif 98 } 99 100 void sigchld_handler(int signo) { } 101 102 int CreateTMPFile(const string& dir, string* path) { 103 string file = dir + "/exception-handler-unittest.XXXXXX"; 104 const char* c_file = file.c_str(); 105 // Copy that string, mkstemp needs a C string it can modify. 106 char* c_path = strdup(c_file); 107 const int fd = mkstemp(c_path); 108 if (fd >= 0) 109 *path = c_path; 110 free(c_path); 111 return fd; 112 } 113 114 class ExceptionHandlerTest : public ::testing::Test { 115 protected: 116 void SetUp() { 117 // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN. 118 struct sigaction sa; 119 memset(&sa, 0, sizeof(sa)); 120 sa.sa_handler = sigchld_handler; 121 ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1); 122 } 123 124 void TearDown() { 125 sigaction(SIGCHLD, &old_action, NULL); 126 } 127 128 struct sigaction old_action; 129 }; 130 131 132 void WaitForProcessToTerminate(pid_t process_id, int expected_status) { 133 int status; 134 ASSERT_NE(HANDLE_EINTR(waitpid(process_id, &status, 0)), -1); 135 ASSERT_TRUE(WIFSIGNALED(status)); 136 ASSERT_EQ(expected_status, WTERMSIG(status)); 137 } 138 139 // Reads the minidump path sent over the pipe |fd| and sets it in |path|. 140 void ReadMinidumpPathFromPipe(int fd, string* path) { 141 struct pollfd pfd; 142 memset(&pfd, 0, sizeof(pfd)); 143 pfd.fd = fd; 144 pfd.events = POLLIN | POLLERR; 145 146 const int r = HANDLE_EINTR(poll(&pfd, 1, 0)); 147 ASSERT_EQ(1, r); 148 ASSERT_TRUE(pfd.revents & POLLIN); 149 150 int32_t len; 151 ASSERT_EQ(static_cast<ssize_t>(sizeof(len)), read(fd, &len, sizeof(len))); 152 ASSERT_LT(len, 2048); 153 char* filename = static_cast<char*>(malloc(len + 1)); 154 ASSERT_EQ(len, read(fd, filename, len)); 155 filename[len] = 0; 156 close(fd); 157 *path = filename; 158 free(filename); 159 } 160 161 } // namespace 162 163 TEST(ExceptionHandlerTest, SimpleWithPath) { 164 AutoTempDir temp_dir; 165 ExceptionHandler handler( 166 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); 167 EXPECT_EQ(temp_dir.path(), handler.minidump_descriptor().directory()); 168 string temp_subdir = temp_dir.path() + "/subdir"; 169 handler.set_minidump_descriptor(MinidumpDescriptor(temp_subdir)); 170 EXPECT_EQ(temp_subdir, handler.minidump_descriptor().directory()); 171 } 172 173 TEST(ExceptionHandlerTest, SimpleWithFD) { 174 AutoTempDir temp_dir; 175 string path; 176 const int fd = CreateTMPFile(temp_dir.path(), &path); 177 ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, true, -1); 178 close(fd); 179 } 180 181 static bool DoneCallback(const MinidumpDescriptor& descriptor, 182 void* context, 183 bool succeeded) { 184 if (!succeeded) 185 return false; 186 187 if (!descriptor.IsFD()) { 188 int fd = reinterpret_cast<intptr_t>(context); 189 uint32_t len = 0; 190 len = my_strlen(descriptor.path()); 191 IGNORE_RET(HANDLE_EINTR(sys_write(fd, &len, sizeof(len)))); 192 IGNORE_RET(HANDLE_EINTR(sys_write(fd, descriptor.path(), len))); 193 } 194 return true; 195 } 196 197 #ifndef ADDRESS_SANITIZER 198 199 // This is a replacement for "*reinterpret_cast<volatile int*>(NULL) = 0;" 200 // It is needed because GCC is allowed to assume that the program will 201 // not execute any undefined behavior (UB) operation. Further, when GCC 202 // observes that UB statement is reached, it can assume that all statements 203 // leading to the UB one are never executed either, and can completely 204 // optimize them out. In the case of ExceptionHandlerTest::ExternalDumper, 205 // GCC-4.9 optimized out the entire set up of ExceptionHandler, causing 206 // test failure. 207 volatile int* p_null; // external linkage, so GCC can't tell that it 208 // remains NULL. Volatile just for a good measure. 209 static void DoNullPointerDereference() { 210 *p_null = 1; 211 } 212 213 void ChildCrash(bool use_fd) { 214 AutoTempDir temp_dir; 215 int fds[2] = {0}; 216 int minidump_fd = -1; 217 string minidump_path; 218 if (use_fd) { 219 minidump_fd = CreateTMPFile(temp_dir.path(), &minidump_path); 220 } else { 221 ASSERT_NE(pipe(fds), -1); 222 } 223 224 const pid_t child = fork(); 225 if (child == 0) { 226 { 227 google_breakpad::scoped_ptr<ExceptionHandler> handler; 228 if (use_fd) { 229 handler.reset(new ExceptionHandler(MinidumpDescriptor(minidump_fd), 230 NULL, NULL, NULL, true, -1)); 231 } else { 232 close(fds[0]); // Close the reading end. 233 void* fd_param = reinterpret_cast<void*>(fds[1]); 234 handler.reset(new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), 235 NULL, DoneCallback, fd_param, 236 true, -1)); 237 } 238 // Crash with the exception handler in scope. 239 DoNullPointerDereference(); 240 } 241 } 242 if (!use_fd) 243 close(fds[1]); // Close the writting end. 244 245 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 246 247 if (!use_fd) 248 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); 249 250 struct stat st; 251 ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); 252 ASSERT_GT(st.st_size, 0); 253 unlink(minidump_path.c_str()); 254 } 255 256 TEST(ExceptionHandlerTest, ChildCrashWithPath) { 257 ASSERT_NO_FATAL_FAILURE(ChildCrash(false)); 258 } 259 260 TEST(ExceptionHandlerTest, ChildCrashWithFD) { 261 ASSERT_NO_FATAL_FAILURE(ChildCrash(true)); 262 } 263 264 #if !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__ 265 static void* SleepFunction(void* unused) { 266 while (true) usleep(1000000); 267 return NULL; 268 } 269 270 static void* CrashFunction(void* b_ptr) { 271 pthread_barrier_t* b = reinterpret_cast<pthread_barrier_t*>(b_ptr); 272 pthread_barrier_wait(b); 273 DoNullPointerDereference(); 274 return NULL; 275 } 276 277 // Tests that concurrent crashes do not enter a loop by alternately triggering 278 // the signal handler. 279 TEST(ExceptionHandlerTest, ParallelChildCrashesDontHang) { 280 AutoTempDir temp_dir; 281 const pid_t child = fork(); 282 if (child == 0) { 283 google_breakpad::scoped_ptr<ExceptionHandler> handler( 284 new ExceptionHandler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, 285 NULL, true, -1)); 286 287 // We start a number of threads to make sure handling the signal takes 288 // enough time for the second thread to enter the signal handler. 289 int num_sleep_threads = 100; 290 google_breakpad::scoped_array<pthread_t> sleep_threads( 291 new pthread_t[num_sleep_threads]); 292 for (int i = 0; i < num_sleep_threads; ++i) { 293 ASSERT_EQ(0, pthread_create(&sleep_threads[i], NULL, SleepFunction, 294 NULL)); 295 } 296 297 int num_crash_threads = 2; 298 google_breakpad::scoped_array<pthread_t> crash_threads( 299 new pthread_t[num_crash_threads]); 300 // Barrier to synchronize crashing both threads at the same time. 301 pthread_barrier_t b; 302 ASSERT_EQ(0, pthread_barrier_init(&b, NULL, num_crash_threads + 1)); 303 for (int i = 0; i < num_crash_threads; ++i) { 304 ASSERT_EQ(0, pthread_create(&crash_threads[i], NULL, CrashFunction, &b)); 305 } 306 pthread_barrier_wait(&b); 307 for (int i = 0; i < num_crash_threads; ++i) { 308 ASSERT_EQ(0, pthread_join(crash_threads[i], NULL)); 309 } 310 } 311 312 // Poll the child to see if it crashed. 313 int status, wp_pid; 314 for (int i = 0; i < 100; i++) { 315 wp_pid = HANDLE_EINTR(waitpid(child, &status, WNOHANG)); 316 ASSERT_NE(-1, wp_pid); 317 if (wp_pid > 0) { 318 ASSERT_TRUE(WIFSIGNALED(status)); 319 // If the child process terminated by itself, 320 // it will have returned SIGSEGV. 321 ASSERT_EQ(SIGSEGV, WTERMSIG(status)); 322 return; 323 } else { 324 usleep(100000); 325 } 326 } 327 328 // Kill the child if it is still running. 329 kill(child, SIGKILL); 330 331 // If the child process terminated by itself, it will have returned SIGSEGV. 332 // If however it got stuck in a loop, it will have been killed by the 333 // SIGKILL. 334 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 335 } 336 #endif // !defined(__ANDROID_API__) || __ANDROID_API__ >= __ANDROID_API_N__ 337 338 static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor, 339 void* context, 340 bool succeeded) { 341 return false; 342 } 343 344 static bool DoneCallbackReturnTrue(const MinidumpDescriptor& descriptor, 345 void* context, 346 bool succeeded) { 347 return true; 348 } 349 350 static bool DoneCallbackRaiseSIGKILL(const MinidumpDescriptor& descriptor, 351 void* context, 352 bool succeeded) { 353 raise(SIGKILL); 354 return true; 355 } 356 357 static bool FilterCallbackReturnFalse(void* context) { 358 return false; 359 } 360 361 static bool FilterCallbackReturnTrue(void* context) { 362 return true; 363 } 364 365 // SIGKILL cannot be blocked and a handler cannot be installed for it. In the 366 // following tests, if the child dies with signal SIGKILL, then the signal was 367 // redelivered to this handler. If the child dies with SIGSEGV then it wasn't. 368 static void RaiseSIGKILL(int sig) { 369 raise(SIGKILL); 370 } 371 372 static bool InstallRaiseSIGKILL() { 373 struct sigaction sa; 374 memset(&sa, 0, sizeof(sa)); 375 sa.sa_handler = RaiseSIGKILL; 376 return sigaction(SIGSEGV, &sa, NULL) != -1; 377 } 378 379 static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter, 380 ExceptionHandler::MinidumpCallback done, 381 string path) { 382 ExceptionHandler handler( 383 MinidumpDescriptor(path), filter, done, NULL, true, -1); 384 // Crash with the exception handler in scope. 385 DoNullPointerDereference(); 386 } 387 388 TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) { 389 AutoTempDir temp_dir; 390 391 const pid_t child = fork(); 392 if (child == 0) { 393 ASSERT_TRUE(InstallRaiseSIGKILL()); 394 CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); 395 } 396 397 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); 398 } 399 400 TEST(ExceptionHandlerTest, RedeliveryOnDoneCallbackFalse) { 401 AutoTempDir temp_dir; 402 403 const pid_t child = fork(); 404 if (child == 0) { 405 ASSERT_TRUE(InstallRaiseSIGKILL()); 406 CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path()); 407 } 408 409 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); 410 } 411 412 TEST(ExceptionHandlerTest, NoRedeliveryOnDoneCallbackTrue) { 413 AutoTempDir temp_dir; 414 415 const pid_t child = fork(); 416 if (child == 0) { 417 ASSERT_TRUE(InstallRaiseSIGKILL()); 418 CrashWithCallbacks(NULL, DoneCallbackReturnTrue, temp_dir.path()); 419 } 420 421 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 422 } 423 424 TEST(ExceptionHandlerTest, NoRedeliveryOnFilterCallbackTrue) { 425 AutoTempDir temp_dir; 426 427 const pid_t child = fork(); 428 if (child == 0) { 429 ASSERT_TRUE(InstallRaiseSIGKILL()); 430 CrashWithCallbacks(FilterCallbackReturnTrue, NULL, temp_dir.path()); 431 } 432 433 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 434 } 435 436 TEST(ExceptionHandlerTest, RedeliveryToDefaultHandler) { 437 AutoTempDir temp_dir; 438 439 const pid_t child = fork(); 440 if (child == 0) { 441 // Custom signal handlers, which may have been installed by a test launcher, 442 // are undesirable in this child. 443 signal(SIGSEGV, SIG_DFL); 444 445 CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); 446 } 447 448 // As RaiseSIGKILL wasn't installed, the redelivery should just kill the child 449 // with SIGSEGV. 450 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 451 } 452 453 // Check that saving and restoring the signal handler with 'signal' 454 // instead of 'sigaction' doesn't make the Breakpad signal handler 455 // crash. See comments in ExceptionHandler::SignalHandler for full 456 // details. 457 TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) { 458 AutoTempDir temp_dir; 459 const pid_t child = fork(); 460 if (child == 0) { 461 // Install the RaiseSIGKILL handler for SIGSEGV. 462 ASSERT_TRUE(InstallRaiseSIGKILL()); 463 464 // Create a new exception handler, this installs a new SIGSEGV 465 // handler, after saving the old one. 466 ExceptionHandler handler( 467 MinidumpDescriptor(temp_dir.path()), NULL, 468 DoneCallbackReturnFalse, NULL, true, -1); 469 470 // Install the default SIGSEGV handler, saving the current one. 471 // Then re-install the current one with 'signal', this loses the 472 // SA_SIGINFO flag associated with the Breakpad handler. 473 sighandler_t old_handler = signal(SIGSEGV, SIG_DFL); 474 ASSERT_NE(reinterpret_cast<void*>(old_handler), 475 reinterpret_cast<void*>(SIG_ERR)); 476 ASSERT_NE(reinterpret_cast<void*>(signal(SIGSEGV, old_handler)), 477 reinterpret_cast<void*>(SIG_ERR)); 478 479 // Crash with the exception handler in scope. 480 DoNullPointerDereference(); 481 } 482 // SIGKILL means Breakpad's signal handler didn't crash. 483 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); 484 } 485 486 TEST(ExceptionHandlerTest, StackedHandlersDeliveredToTop) { 487 AutoTempDir temp_dir; 488 489 const pid_t child = fork(); 490 if (child == 0) { 491 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), 492 NULL, 493 NULL, 494 NULL, 495 true, 496 -1); 497 CrashWithCallbacks(NULL, DoneCallbackRaiseSIGKILL, temp_dir.path()); 498 } 499 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); 500 } 501 502 TEST(ExceptionHandlerTest, StackedHandlersNotDeliveredToBottom) { 503 AutoTempDir temp_dir; 504 505 const pid_t child = fork(); 506 if (child == 0) { 507 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), 508 NULL, 509 DoneCallbackRaiseSIGKILL, 510 NULL, 511 true, 512 -1); 513 CrashWithCallbacks(NULL, NULL, temp_dir.path()); 514 } 515 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 516 } 517 518 TEST(ExceptionHandlerTest, StackedHandlersFilteredToBottom) { 519 AutoTempDir temp_dir; 520 521 const pid_t child = fork(); 522 if (child == 0) { 523 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), 524 NULL, 525 DoneCallbackRaiseSIGKILL, 526 NULL, 527 true, 528 -1); 529 CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path()); 530 } 531 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); 532 } 533 534 TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) { 535 AutoTempDir temp_dir; 536 537 const pid_t child = fork(); 538 if (child == 0) { 539 ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()), 540 NULL, 541 DoneCallbackRaiseSIGKILL, 542 NULL, 543 true, 544 -1); 545 CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path()); 546 } 547 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); 548 } 549 550 namespace { 551 const int kSimpleFirstChanceReturnStatus = 42; 552 bool SimpleFirstChanceHandler(int, siginfo_t*, void*) { 553 _exit(kSimpleFirstChanceReturnStatus); 554 } 555 } 556 557 TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) { 558 AutoTempDir temp_dir; 559 560 const pid_t child = fork(); 561 if (child == 0) { 562 ExceptionHandler handler( 563 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); 564 google_breakpad::SetFirstChanceExceptionHandler(SimpleFirstChanceHandler); 565 DoNullPointerDereference(); 566 } 567 int status; 568 ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1); 569 ASSERT_TRUE(WIFEXITED(status)); 570 ASSERT_EQ(kSimpleFirstChanceReturnStatus, WEXITSTATUS(status)); 571 } 572 573 #endif // !ADDRESS_SANITIZER 574 575 const unsigned char kIllegalInstruction[] = { 576 #if defined(__mips__) 577 // mfc2 zero,Impl - usually illegal in userspace. 578 0x48, 0x00, 0x00, 0x48 579 #else 580 // This crashes with SIGILL on x86/x86-64/arm. 581 0xff, 0xff, 0xff, 0xff 582 #endif 583 }; 584 585 // Test that memory around the instruction pointer is written 586 // to the dump as a MinidumpMemoryRegion. 587 TEST(ExceptionHandlerTest, InstructionPointerMemory) { 588 AutoTempDir temp_dir; 589 int fds[2]; 590 ASSERT_NE(pipe(fds), -1); 591 592 // These are defined here so the parent can use them to check the 593 // data from the minidump afterwards. 594 const uint32_t kMemorySize = 256; // bytes 595 const int kOffset = kMemorySize / 2; 596 597 const pid_t child = fork(); 598 if (child == 0) { 599 close(fds[0]); 600 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, 601 DoneCallback, reinterpret_cast<void*>(fds[1]), 602 true, -1); 603 // Get some executable memory. 604 char* memory = 605 reinterpret_cast<char*>(mmap(NULL, 606 kMemorySize, 607 PROT_READ | PROT_WRITE | PROT_EXEC, 608 MAP_PRIVATE | MAP_ANON, 609 -1, 610 0)); 611 if (!memory) 612 exit(0); 613 614 // Write some instructions that will crash. Put them in the middle 615 // of the block of memory, because the minidump should contain 128 616 // bytes on either side of the instruction pointer. 617 memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); 618 FlushInstructionCache(memory, kMemorySize); 619 620 // Now execute the instructions, which should crash. 621 typedef void (*void_function)(void); 622 void_function memory_function = 623 reinterpret_cast<void_function>(memory + kOffset); 624 memory_function(); 625 } 626 close(fds[1]); 627 628 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL)); 629 630 string minidump_path; 631 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); 632 633 struct stat st; 634 ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); 635 ASSERT_GT(st.st_size, 0); 636 637 // Read the minidump. Locate the exception record and the 638 // memory list, and then ensure that there is a memory region 639 // in the memory list that covers the instruction pointer from 640 // the exception record. 641 Minidump minidump(minidump_path); 642 ASSERT_TRUE(minidump.Read()); 643 644 MinidumpException* exception = minidump.GetException(); 645 MinidumpMemoryList* memory_list = minidump.GetMemoryList(); 646 ASSERT_TRUE(exception); 647 ASSERT_TRUE(memory_list); 648 ASSERT_LT(0U, memory_list->region_count()); 649 650 MinidumpContext* context = exception->GetContext(); 651 ASSERT_TRUE(context); 652 653 uint64_t instruction_pointer; 654 ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); 655 656 MinidumpMemoryRegion* region = 657 memory_list->GetMemoryRegionForAddress(instruction_pointer); 658 ASSERT_TRUE(region); 659 660 EXPECT_EQ(kMemorySize, region->GetSize()); 661 const uint8_t* bytes = region->GetMemory(); 662 ASSERT_TRUE(bytes); 663 664 uint8_t prefix_bytes[kOffset]; 665 uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(kIllegalInstruction)]; 666 memset(prefix_bytes, 0, sizeof(prefix_bytes)); 667 memset(suffix_bytes, 0, sizeof(suffix_bytes)); 668 EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); 669 EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, 670 sizeof(kIllegalInstruction)) == 0); 671 EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), 672 suffix_bytes, sizeof(suffix_bytes)) == 0); 673 674 unlink(minidump_path.c_str()); 675 } 676 677 // Test that the memory region around the instruction pointer is 678 // bounded correctly on the low end. 679 TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { 680 AutoTempDir temp_dir; 681 int fds[2]; 682 ASSERT_NE(pipe(fds), -1); 683 684 // These are defined here so the parent can use them to check the 685 // data from the minidump afterwards. 686 const uint32_t kMemorySize = 256; // bytes 687 const int kOffset = 0; 688 689 const pid_t child = fork(); 690 if (child == 0) { 691 close(fds[0]); 692 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, 693 DoneCallback, reinterpret_cast<void*>(fds[1]), 694 true, -1); 695 // Get some executable memory. 696 char* memory = 697 reinterpret_cast<char*>(mmap(NULL, 698 kMemorySize, 699 PROT_READ | PROT_WRITE | PROT_EXEC, 700 MAP_PRIVATE | MAP_ANON, 701 -1, 702 0)); 703 if (!memory) 704 exit(0); 705 706 // Write some instructions that will crash. Put them in the middle 707 // of the block of memory, because the minidump should contain 128 708 // bytes on either side of the instruction pointer. 709 memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); 710 FlushInstructionCache(memory, kMemorySize); 711 712 // Now execute the instructions, which should crash. 713 typedef void (*void_function)(void); 714 void_function memory_function = 715 reinterpret_cast<void_function>(memory + kOffset); 716 memory_function(); 717 } 718 close(fds[1]); 719 720 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL)); 721 722 string minidump_path; 723 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); 724 725 struct stat st; 726 ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); 727 ASSERT_GT(st.st_size, 0); 728 729 // Read the minidump. Locate the exception record and the 730 // memory list, and then ensure that there is a memory region 731 // in the memory list that covers the instruction pointer from 732 // the exception record. 733 Minidump minidump(minidump_path); 734 ASSERT_TRUE(minidump.Read()); 735 736 MinidumpException* exception = minidump.GetException(); 737 MinidumpMemoryList* memory_list = minidump.GetMemoryList(); 738 ASSERT_TRUE(exception); 739 ASSERT_TRUE(memory_list); 740 ASSERT_LT(0U, memory_list->region_count()); 741 742 MinidumpContext* context = exception->GetContext(); 743 ASSERT_TRUE(context); 744 745 uint64_t instruction_pointer; 746 ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); 747 748 MinidumpMemoryRegion* region = 749 memory_list->GetMemoryRegionForAddress(instruction_pointer); 750 ASSERT_TRUE(region); 751 752 EXPECT_EQ(kMemorySize / 2, region->GetSize()); 753 const uint8_t* bytes = region->GetMemory(); 754 ASSERT_TRUE(bytes); 755 756 uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)]; 757 memset(suffix_bytes, 0, sizeof(suffix_bytes)); 758 EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, 759 sizeof(kIllegalInstruction)) == 0); 760 EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), 761 suffix_bytes, sizeof(suffix_bytes)) == 0); 762 unlink(minidump_path.c_str()); 763 } 764 765 // Test that the memory region around the instruction pointer is 766 // bounded correctly on the high end. 767 TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { 768 AutoTempDir temp_dir; 769 int fds[2]; 770 ASSERT_NE(pipe(fds), -1); 771 772 // These are defined here so the parent can use them to check the 773 // data from the minidump afterwards. 774 // Use 4k here because the OS will hand out a single page even 775 // if a smaller size is requested, and this test wants to 776 // test the upper bound of the memory range. 777 const uint32_t kMemorySize = 4096; // bytes 778 const int kOffset = kMemorySize - sizeof(kIllegalInstruction); 779 780 const pid_t child = fork(); 781 if (child == 0) { 782 close(fds[0]); 783 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, 784 DoneCallback, reinterpret_cast<void*>(fds[1]), 785 true, -1); 786 // Get some executable memory. 787 char* memory = 788 reinterpret_cast<char*>(mmap(NULL, 789 kMemorySize, 790 PROT_READ | PROT_WRITE | PROT_EXEC, 791 MAP_PRIVATE | MAP_ANON, 792 -1, 793 0)); 794 if (!memory) 795 exit(0); 796 797 // Write some instructions that will crash. Put them in the middle 798 // of the block of memory, because the minidump should contain 128 799 // bytes on either side of the instruction pointer. 800 memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); 801 FlushInstructionCache(memory, kMemorySize); 802 803 // Now execute the instructions, which should crash. 804 typedef void (*void_function)(void); 805 void_function memory_function = 806 reinterpret_cast<void_function>(memory + kOffset); 807 memory_function(); 808 } 809 close(fds[1]); 810 811 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL)); 812 813 string minidump_path; 814 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); 815 816 struct stat st; 817 ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); 818 ASSERT_GT(st.st_size, 0); 819 820 // Read the minidump. Locate the exception record and the memory list, and 821 // then ensure that there is a memory region in the memory list that covers 822 // the instruction pointer from the exception record. 823 Minidump minidump(minidump_path); 824 ASSERT_TRUE(minidump.Read()); 825 826 MinidumpException* exception = minidump.GetException(); 827 MinidumpMemoryList* memory_list = minidump.GetMemoryList(); 828 ASSERT_TRUE(exception); 829 ASSERT_TRUE(memory_list); 830 ASSERT_LT(0U, memory_list->region_count()); 831 832 MinidumpContext* context = exception->GetContext(); 833 ASSERT_TRUE(context); 834 835 uint64_t instruction_pointer; 836 ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer)); 837 838 MinidumpMemoryRegion* region = 839 memory_list->GetMemoryRegionForAddress(instruction_pointer); 840 ASSERT_TRUE(region); 841 842 const size_t kPrefixSize = 128; // bytes 843 EXPECT_EQ(kPrefixSize + sizeof(kIllegalInstruction), region->GetSize()); 844 const uint8_t* bytes = region->GetMemory(); 845 ASSERT_TRUE(bytes); 846 847 uint8_t prefix_bytes[kPrefixSize]; 848 memset(prefix_bytes, 0, sizeof(prefix_bytes)); 849 EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); 850 EXPECT_TRUE(memcmp(bytes + kPrefixSize, 851 kIllegalInstruction, sizeof(kIllegalInstruction)) == 0); 852 853 unlink(minidump_path.c_str()); 854 } 855 856 #ifndef ADDRESS_SANITIZER 857 858 // Ensure that an extra memory block doesn't get added when the instruction 859 // pointer is not in mapped memory. 860 TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) { 861 AutoTempDir temp_dir; 862 int fds[2]; 863 ASSERT_NE(pipe(fds), -1); 864 865 const pid_t child = fork(); 866 if (child == 0) { 867 close(fds[0]); 868 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, 869 DoneCallback, reinterpret_cast<void*>(fds[1]), 870 true, -1); 871 // Try calling a NULL pointer. 872 typedef void (*void_function)(void); 873 // Volatile markings are needed to keep Clang from generating invalid 874 // opcodes. See http://crbug.com/498354 for details. 875 volatile void_function memory_function = 876 reinterpret_cast<void_function>(NULL); 877 memory_function(); 878 // not reached 879 exit(1); 880 } 881 close(fds[1]); 882 883 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 884 885 string minidump_path; 886 ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path)); 887 888 struct stat st; 889 ASSERT_EQ(0, stat(minidump_path.c_str(), &st)); 890 ASSERT_GT(st.st_size, 0); 891 892 // Read the minidump. Locate the exception record and the 893 // memory list, and then ensure that there is no memory region 894 // in the memory list that covers the instruction pointer from 895 // the exception record. 896 Minidump minidump(minidump_path); 897 ASSERT_TRUE(minidump.Read()); 898 899 MinidumpException* exception = minidump.GetException(); 900 ASSERT_TRUE(exception); 901 902 MinidumpContext* exception_context = exception->GetContext(); 903 ASSERT_TRUE(exception_context); 904 905 uint64_t instruction_pointer; 906 ASSERT_TRUE(exception_context->GetInstructionPointer(&instruction_pointer)); 907 EXPECT_EQ(instruction_pointer, 0u); 908 909 MinidumpMemoryList* memory_list = minidump.GetMemoryList(); 910 ASSERT_TRUE(memory_list); 911 912 unsigned int region_count = memory_list->region_count(); 913 ASSERT_GE(region_count, 1u); 914 915 for (unsigned int region_index = 0; 916 region_index < region_count; 917 ++region_index) { 918 MinidumpMemoryRegion* region = 919 memory_list->GetMemoryRegionAtIndex(region_index); 920 uint64_t region_base = region->GetBase(); 921 EXPECT_FALSE(instruction_pointer >= region_base && 922 instruction_pointer < region_base + region->GetSize()); 923 } 924 925 unlink(minidump_path.c_str()); 926 } 927 928 #endif // !ADDRESS_SANITIZER 929 930 // Test that anonymous memory maps can be annotated with names and IDs. 931 TEST(ExceptionHandlerTest, ModuleInfo) { 932 // These are defined here so the parent can use them to check the 933 // data from the minidump afterwards. 934 const uint32_t kMemorySize = sysconf(_SC_PAGESIZE); 935 const char* kMemoryName = "a fake module"; 936 const uint8_t kModuleGUID[sizeof(MDGUID)] = { 937 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 938 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF 939 }; 940 const string module_identifier = "33221100554477668899AABBCCDDEEFF0"; 941 942 // Get some memory. 943 char* memory = 944 reinterpret_cast<char*>(mmap(NULL, 945 kMemorySize, 946 PROT_READ | PROT_WRITE, 947 MAP_PRIVATE | MAP_ANON, 948 -1, 949 0)); 950 const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory); 951 ASSERT_TRUE(memory); 952 953 AutoTempDir temp_dir; 954 ExceptionHandler handler( 955 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); 956 957 // Add info about the anonymous memory mapping. 958 handler.AddMappingInfo(kMemoryName, 959 kModuleGUID, 960 kMemoryAddress, 961 kMemorySize, 962 0); 963 ASSERT_TRUE(handler.WriteMinidump()); 964 965 const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor(); 966 // Read the minidump. Load the module list, and ensure that the mmap'ed 967 // |memory| is listed with the given module name and debug ID. 968 Minidump minidump(minidump_desc.path()); 969 ASSERT_TRUE(minidump.Read()); 970 971 MinidumpModuleList* module_list = minidump.GetModuleList(); 972 ASSERT_TRUE(module_list); 973 const MinidumpModule* module = 974 module_list->GetModuleForAddress(kMemoryAddress); 975 ASSERT_TRUE(module); 976 977 EXPECT_EQ(kMemoryAddress, module->base_address()); 978 EXPECT_EQ(kMemorySize, module->size()); 979 EXPECT_EQ(kMemoryName, module->code_file()); 980 EXPECT_EQ(module_identifier, module->debug_identifier()); 981 982 unlink(minidump_desc.path()); 983 } 984 985 #ifndef ADDRESS_SANITIZER 986 987 static const unsigned kControlMsgSize = 988 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); 989 990 static bool 991 CrashHandler(const void* crash_context, size_t crash_context_size, 992 void* context) { 993 const int fd = (intptr_t) context; 994 int fds[2]; 995 if (pipe(fds) == -1) { 996 // There doesn't seem to be any way to reliably handle 997 // this failure without the parent process hanging 998 // At least make sure that this process doesn't access 999 // unexpected file descriptors 1000 fds[0] = -1; 1001 fds[1] = -1; 1002 } 1003 struct kernel_msghdr msg = {0}; 1004 struct kernel_iovec iov; 1005 iov.iov_base = const_cast<void*>(crash_context); 1006 iov.iov_len = crash_context_size; 1007 msg.msg_iov = &iov; 1008 msg.msg_iovlen = 1; 1009 char cmsg[kControlMsgSize]; 1010 memset(cmsg, 0, kControlMsgSize); 1011 msg.msg_control = cmsg; 1012 msg.msg_controllen = sizeof(cmsg); 1013 1014 struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); 1015 hdr->cmsg_level = SOL_SOCKET; 1016 hdr->cmsg_type = SCM_RIGHTS; 1017 hdr->cmsg_len = CMSG_LEN(sizeof(int)); 1018 *((int*) CMSG_DATA(hdr)) = fds[1]; 1019 hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr); 1020 hdr->cmsg_level = SOL_SOCKET; 1021 hdr->cmsg_type = SCM_CREDENTIALS; 1022 hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred)); 1023 struct ucred* cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); 1024 cred->uid = getuid(); 1025 cred->gid = getgid(); 1026 cred->pid = getpid(); 1027 1028 ssize_t ret = HANDLE_EINTR(sys_sendmsg(fd, &msg, 0)); 1029 sys_close(fds[1]); 1030 if (ret <= 0) 1031 return false; 1032 1033 char b; 1034 IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1))); 1035 1036 return true; 1037 } 1038 1039 TEST(ExceptionHandlerTest, ExternalDumper) { 1040 int fds[2]; 1041 ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1); 1042 static const int on = 1; 1043 setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 1044 setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 1045 1046 const pid_t child = fork(); 1047 if (child == 0) { 1048 close(fds[0]); 1049 ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL, 1050 reinterpret_cast<void*>(fds[1]), true, -1); 1051 handler.set_crash_handler(CrashHandler); 1052 DoNullPointerDereference(); 1053 } 1054 close(fds[1]); 1055 struct msghdr msg = {0}; 1056 struct iovec iov; 1057 static const unsigned kCrashContextSize = 1058 sizeof(ExceptionHandler::CrashContext); 1059 char context[kCrashContextSize]; 1060 char control[kControlMsgSize]; 1061 iov.iov_base = context; 1062 iov.iov_len = kCrashContextSize; 1063 msg.msg_iov = &iov; 1064 msg.msg_iovlen = 1; 1065 msg.msg_control = control; 1066 msg.msg_controllen = kControlMsgSize; 1067 1068 const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0)); 1069 ASSERT_EQ(static_cast<ssize_t>(kCrashContextSize), n); 1070 ASSERT_EQ(kControlMsgSize, msg.msg_controllen); 1071 ASSERT_EQ(static_cast<__typeof__(msg.msg_flags)>(0), msg.msg_flags); 1072 ASSERT_EQ(0, close(fds[0])); 1073 1074 pid_t crashing_pid = -1; 1075 int signal_fd = -1; 1076 for (struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); hdr; 1077 hdr = CMSG_NXTHDR(&msg, hdr)) { 1078 if (hdr->cmsg_level != SOL_SOCKET) 1079 continue; 1080 if (hdr->cmsg_type == SCM_RIGHTS) { 1081 const unsigned len = hdr->cmsg_len - 1082 (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr); 1083 ASSERT_EQ(sizeof(int), len); 1084 signal_fd = *(reinterpret_cast<int*>(CMSG_DATA(hdr))); 1085 } else if (hdr->cmsg_type == SCM_CREDENTIALS) { 1086 const struct ucred* cred = 1087 reinterpret_cast<struct ucred*>(CMSG_DATA(hdr)); 1088 crashing_pid = cred->pid; 1089 } 1090 } 1091 1092 ASSERT_NE(crashing_pid, -1); 1093 ASSERT_NE(signal_fd, -1); 1094 1095 AutoTempDir temp_dir; 1096 string templ = temp_dir.path() + "/exception-handler-unittest"; 1097 ASSERT_TRUE(WriteMinidump(templ.c_str(), crashing_pid, context, 1098 kCrashContextSize)); 1099 static const char b = 0; 1100 ASSERT_EQ(1, (HANDLE_EINTR(write(signal_fd, &b, 1)))); 1101 ASSERT_EQ(0, close(signal_fd)); 1102 1103 ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV)); 1104 1105 struct stat st; 1106 ASSERT_EQ(0, stat(templ.c_str(), &st)); 1107 ASSERT_GT(st.st_size, 0); 1108 unlink(templ.c_str()); 1109 } 1110 1111 #endif // !ADDRESS_SANITIZER 1112 1113 TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) { 1114 AutoTempDir temp_dir; 1115 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, 1116 NULL, false, -1); 1117 ASSERT_TRUE(handler.WriteMinidump()); 1118 1119 string minidump_path = handler.minidump_descriptor().path(); 1120 1121 // Read the minidump and check the exception stream. 1122 Minidump minidump(minidump_path); 1123 ASSERT_TRUE(minidump.Read()); 1124 MinidumpException* exception = minidump.GetException(); 1125 ASSERT_TRUE(exception); 1126 const MDRawExceptionStream* raw = exception->exception(); 1127 ASSERT_TRUE(raw); 1128 EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED, 1129 raw->exception_record.exception_code); 1130 } 1131 1132 TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) { 1133 AutoTempDir temp_dir; 1134 string path; 1135 const int fd = CreateTMPFile(temp_dir.path(), &path); 1136 ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, false, -1); 1137 ASSERT_TRUE(handler.WriteMinidump()); 1138 // Check by the size of the data written to the FD that a minidump was 1139 // generated. 1140 off_t size = lseek(fd, 0, SEEK_CUR); 1141 ASSERT_GT(size, 0); 1142 1143 // Generate another minidump. 1144 ASSERT_TRUE(handler.WriteMinidump()); 1145 size = lseek(fd, 0, SEEK_CUR); 1146 ASSERT_GT(size, 0); 1147 } 1148 1149 TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) { 1150 AutoTempDir temp_dir; 1151 ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL, 1152 NULL, false, -1); 1153 ASSERT_TRUE(handler.WriteMinidump()); 1154 1155 const MinidumpDescriptor& minidump_1 = handler.minidump_descriptor(); 1156 struct stat st; 1157 ASSERT_EQ(0, stat(minidump_1.path(), &st)); 1158 ASSERT_GT(st.st_size, 0); 1159 string minidump_1_path(minidump_1.path()); 1160 // Check it is a valid minidump. 1161 Minidump minidump1(minidump_1_path); 1162 ASSERT_TRUE(minidump1.Read()); 1163 unlink(minidump_1.path()); 1164 1165 // Generate another minidump, it should go to a different file. 1166 ASSERT_TRUE(handler.WriteMinidump()); 1167 const MinidumpDescriptor& minidump_2 = handler.minidump_descriptor(); 1168 ASSERT_EQ(0, stat(minidump_2.path(), &st)); 1169 ASSERT_GT(st.st_size, 0); 1170 string minidump_2_path(minidump_2.path()); 1171 // Check it is a valid minidump. 1172 Minidump minidump2(minidump_2_path); 1173 ASSERT_TRUE(minidump2.Read()); 1174 unlink(minidump_2.path()); 1175 1176 // 2 distinct files should be produced. 1177 ASSERT_STRNE(minidump_1_path.c_str(), minidump_2_path.c_str()); 1178 } 1179 1180 // Test that an additional memory region can be added to the minidump. 1181 TEST(ExceptionHandlerTest, AdditionalMemory) { 1182 const uint32_t kMemorySize = sysconf(_SC_PAGESIZE); 1183 1184 // Get some heap memory. 1185 uint8_t* memory = new uint8_t[kMemorySize]; 1186 const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory); 1187 ASSERT_TRUE(memory); 1188 1189 // Stick some data into the memory so the contents can be verified. 1190 for (uint32_t i = 0; i < kMemorySize; ++i) { 1191 memory[i] = i % 255; 1192 } 1193 1194 AutoTempDir temp_dir; 1195 ExceptionHandler handler( 1196 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); 1197 1198 // Add the memory region to the list of memory to be included. 1199 handler.RegisterAppMemory(memory, kMemorySize); 1200 handler.WriteMinidump(); 1201 1202 const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor(); 1203 1204 // Read the minidump. Ensure that the memory region is present 1205 Minidump minidump(minidump_desc.path()); 1206 ASSERT_TRUE(minidump.Read()); 1207 1208 MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList(); 1209 ASSERT_TRUE(dump_memory_list); 1210 const MinidumpMemoryRegion* region = 1211 dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress); 1212 ASSERT_TRUE(region); 1213 1214 EXPECT_EQ(kMemoryAddress, region->GetBase()); 1215 EXPECT_EQ(kMemorySize, region->GetSize()); 1216 1217 // Verify memory contents. 1218 EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize)); 1219 1220 delete[] memory; 1221 } 1222 1223 // Test that a memory region that was previously registered 1224 // can be unregistered. 1225 TEST(ExceptionHandlerTest, AdditionalMemoryRemove) { 1226 const uint32_t kMemorySize = sysconf(_SC_PAGESIZE); 1227 1228 // Get some heap memory. 1229 uint8_t* memory = new uint8_t[kMemorySize]; 1230 const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory); 1231 ASSERT_TRUE(memory); 1232 1233 AutoTempDir temp_dir; 1234 ExceptionHandler handler( 1235 MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1); 1236 1237 // Add the memory region to the list of memory to be included. 1238 handler.RegisterAppMemory(memory, kMemorySize); 1239 1240 // ...and then remove it 1241 handler.UnregisterAppMemory(memory); 1242 handler.WriteMinidump(); 1243 1244 const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor(); 1245 1246 // Read the minidump. Ensure that the memory region is not present. 1247 Minidump minidump(minidump_desc.path()); 1248 ASSERT_TRUE(minidump.Read()); 1249 1250 MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList(); 1251 ASSERT_TRUE(dump_memory_list); 1252 const MinidumpMemoryRegion* region = 1253 dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress); 1254 EXPECT_FALSE(region); 1255 1256 delete[] memory; 1257 } 1258 1259 static bool SimpleCallback(const MinidumpDescriptor& descriptor, 1260 void* context, 1261 bool succeeded) { 1262 string* filename = reinterpret_cast<string*>(context); 1263 *filename = descriptor.path(); 1264 return true; 1265 } 1266 1267 TEST(ExceptionHandlerTest, WriteMinidumpForChild) { 1268 int fds[2]; 1269 ASSERT_NE(-1, pipe(fds)); 1270 1271 const pid_t child = fork(); 1272 if (child == 0) { 1273 close(fds[1]); 1274 char b; 1275 HANDLE_EINTR(read(fds[0], &b, sizeof(b))); 1276 close(fds[0]); 1277 syscall(__NR_exit); 1278 } 1279 close(fds[0]); 1280 1281 AutoTempDir temp_dir; 1282 string minidump_filename; 1283 ASSERT_TRUE( 1284 ExceptionHandler::WriteMinidumpForChild(child, child, 1285 temp_dir.path(), SimpleCallback, 1286 (void*)&minidump_filename)); 1287 1288 Minidump minidump(minidump_filename); 1289 ASSERT_TRUE(minidump.Read()); 1290 // Check that the crashing thread is the main thread of |child| 1291 MinidumpException* exception = minidump.GetException(); 1292 ASSERT_TRUE(exception); 1293 uint32_t thread_id; 1294 ASSERT_TRUE(exception->GetThreadID(&thread_id)); 1295 EXPECT_EQ(child, static_cast<int32_t>(thread_id)); 1296 1297 const MDRawExceptionStream* raw = exception->exception(); 1298 ASSERT_TRUE(raw); 1299 EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED, 1300 raw->exception_record.exception_code); 1301 1302 close(fds[1]); 1303 unlink(minidump_filename.c_str()); 1304 }