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