/thirdparty/breakpad/client/mac/tests/exception_handler_test.cc

http://github.com/tomahawk-player/tomahawk · C++ · 716 lines · 474 code · 96 blank · 146 comment · 33 complexity · c02635f07421bb5d778fa709fc6b3631 MD5 · raw file

  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. // exception_handler_test.cc: Unit tests for google_breakpad::ExceptionHandler
  30. #include <pthread.h>
  31. #include <sys/mman.h>
  32. #include <sys/stat.h>
  33. #include <unistd.h>
  34. #include "breakpad_googletest_includes.h"
  35. #include "client/mac/handler/exception_handler.h"
  36. #include "common/mac/MachIPC.h"
  37. #include "common/tests/auto_tempdir.h"
  38. #include "google_breakpad/processor/minidump.h"
  39. namespace google_breakpad {
  40. // This acts as the log sink for INFO logging from the processor
  41. // logging code. The logging output confuses XCode and makes it think
  42. // there are unit test failures. testlogging.h handles the overriding.
  43. std::ostringstream info_log;
  44. }
  45. namespace {
  46. using std::string;
  47. using google_breakpad::AutoTempDir;
  48. using google_breakpad::ExceptionHandler;
  49. using google_breakpad::MachPortSender;
  50. using google_breakpad::MachReceiveMessage;
  51. using google_breakpad::MachSendMessage;
  52. using google_breakpad::Minidump;
  53. using google_breakpad::MinidumpContext;
  54. using google_breakpad::MinidumpException;
  55. using google_breakpad::MinidumpMemoryList;
  56. using google_breakpad::MinidumpMemoryRegion;
  57. using google_breakpad::ReceivePort;
  58. using testing::Test;
  59. class ExceptionHandlerTest : public Test {
  60. public:
  61. void InProcessCrash(bool aborting);
  62. AutoTempDir tempDir;
  63. string lastDumpName;
  64. };
  65. static void Crasher() {
  66. int *a = (int*)0x42;
  67. fprintf(stdout, "Going to crash...\n");
  68. fprintf(stdout, "A = %d", *a);
  69. }
  70. static void AbortCrasher() {
  71. fprintf(stdout, "Going to crash...\n");
  72. abort();
  73. }
  74. static void SoonToCrash(void(*crasher)()) {
  75. crasher();
  76. }
  77. static bool MDCallback(const char *dump_dir, const char *file_name,
  78. void *context, bool success) {
  79. string path(dump_dir);
  80. path.append("/");
  81. path.append(file_name);
  82. path.append(".dmp");
  83. int fd = *reinterpret_cast<int*>(context);
  84. (void)write(fd, path.c_str(), path.length() + 1);
  85. close(fd);
  86. exit(0);
  87. // not reached
  88. return true;
  89. }
  90. void ExceptionHandlerTest::InProcessCrash(bool aborting) {
  91. // Give the child process a pipe to report back on.
  92. int fds[2];
  93. ASSERT_EQ(0, pipe(fds));
  94. // Fork off a child process so it can crash.
  95. pid_t pid = fork();
  96. if (pid == 0) {
  97. // In the child process.
  98. close(fds[0]);
  99. ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
  100. // crash
  101. SoonToCrash(aborting ? &AbortCrasher : &Crasher);
  102. // not reached
  103. exit(1);
  104. }
  105. // In the parent process.
  106. ASSERT_NE(-1, pid);
  107. // Wait for the background process to return the minidump file.
  108. close(fds[1]);
  109. char minidump_file[PATH_MAX];
  110. ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
  111. ASSERT_NE(0, nbytes);
  112. // Ensure that minidump file exists and is > 0 bytes.
  113. struct stat st;
  114. ASSERT_EQ(0, stat(minidump_file, &st));
  115. ASSERT_LT(0, st.st_size);
  116. // Child process should have exited with a zero status.
  117. int ret;
  118. ASSERT_EQ(pid, waitpid(pid, &ret, 0));
  119. EXPECT_NE(0, WIFEXITED(ret));
  120. EXPECT_EQ(0, WEXITSTATUS(ret));
  121. }
  122. TEST_F(ExceptionHandlerTest, InProcess) {
  123. InProcessCrash(false);
  124. }
  125. #if TARGET_OS_IPHONE
  126. TEST_F(ExceptionHandlerTest, InProcessAbort) {
  127. InProcessCrash(true);
  128. }
  129. #endif
  130. static bool DumpNameMDCallback(const char *dump_dir, const char *file_name,
  131. void *context, bool success) {
  132. ExceptionHandlerTest *self = reinterpret_cast<ExceptionHandlerTest*>(context);
  133. if (dump_dir && file_name) {
  134. self->lastDumpName = dump_dir;
  135. self->lastDumpName += "/";
  136. self->lastDumpName += file_name;
  137. self->lastDumpName += ".dmp";
  138. }
  139. return true;
  140. }
  141. TEST_F(ExceptionHandlerTest, WriteMinidump) {
  142. ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true,
  143. NULL);
  144. ASSERT_TRUE(eh.WriteMinidump());
  145. // Ensure that minidump file exists and is > 0 bytes.
  146. ASSERT_FALSE(lastDumpName.empty());
  147. struct stat st;
  148. ASSERT_EQ(0, stat(lastDumpName.c_str(), &st));
  149. ASSERT_LT(0, st.st_size);
  150. // The minidump should not contain an exception stream.
  151. Minidump minidump(lastDumpName);
  152. ASSERT_TRUE(minidump.Read());
  153. MinidumpException* exception = minidump.GetException();
  154. EXPECT_FALSE(exception);
  155. }
  156. TEST_F(ExceptionHandlerTest, WriteMinidumpWithException) {
  157. ExceptionHandler eh(tempDir.path(), NULL, DumpNameMDCallback, this, true,
  158. NULL);
  159. ASSERT_TRUE(eh.WriteMinidump(true));
  160. // Ensure that minidump file exists and is > 0 bytes.
  161. ASSERT_FALSE(lastDumpName.empty());
  162. struct stat st;
  163. ASSERT_EQ(0, stat(lastDumpName.c_str(), &st));
  164. ASSERT_LT(0, st.st_size);
  165. // The minidump should contain an exception stream.
  166. Minidump minidump(lastDumpName);
  167. ASSERT_TRUE(minidump.Read());
  168. MinidumpException* exception = minidump.GetException();
  169. ASSERT_TRUE(exception);
  170. const MDRawExceptionStream* raw_exception = exception->exception();
  171. ASSERT_TRUE(raw_exception);
  172. EXPECT_EQ(MD_EXCEPTION_MAC_BREAKPOINT,
  173. raw_exception->exception_record.exception_code);
  174. }
  175. TEST_F(ExceptionHandlerTest, DumpChildProcess) {
  176. const int kTimeoutMs = 2000;
  177. // Create a mach port to receive the child task on.
  178. char machPortName[128];
  179. sprintf(machPortName, "ExceptionHandlerTest.%d", getpid());
  180. ReceivePort parent_recv_port(machPortName);
  181. // Give the child process a pipe to block on.
  182. int fds[2];
  183. ASSERT_EQ(0, pipe(fds));
  184. // Fork off a child process to dump.
  185. pid_t pid = fork();
  186. if (pid == 0) {
  187. // In the child process
  188. close(fds[1]);
  189. // Send parent process the task and thread ports.
  190. MachSendMessage child_message(0);
  191. child_message.AddDescriptor(mach_task_self());
  192. child_message.AddDescriptor(mach_thread_self());
  193. MachPortSender child_sender(machPortName);
  194. if (child_sender.SendMessage(child_message, kTimeoutMs) != KERN_SUCCESS)
  195. exit(1);
  196. // Wait for the parent process.
  197. uint8_t data;
  198. read(fds[0], &data, 1);
  199. exit(0);
  200. }
  201. // In the parent process.
  202. ASSERT_NE(-1, pid);
  203. close(fds[0]);
  204. // Read the child's task and thread ports.
  205. MachReceiveMessage child_message;
  206. ASSERT_EQ(KERN_SUCCESS,
  207. parent_recv_port.WaitForMessage(&child_message, kTimeoutMs));
  208. mach_port_t child_task = child_message.GetTranslatedPort(0);
  209. mach_port_t child_thread = child_message.GetTranslatedPort(1);
  210. ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_task);
  211. ASSERT_NE((mach_port_t)MACH_PORT_NULL, child_thread);
  212. // Write a minidump of the child process.
  213. bool result = ExceptionHandler::WriteMinidumpForChild(child_task,
  214. child_thread,
  215. tempDir.path(),
  216. DumpNameMDCallback,
  217. this);
  218. ASSERT_EQ(true, result);
  219. // Ensure that minidump file exists and is > 0 bytes.
  220. ASSERT_FALSE(lastDumpName.empty());
  221. struct stat st;
  222. ASSERT_EQ(0, stat(lastDumpName.c_str(), &st));
  223. ASSERT_LT(0, st.st_size);
  224. // Unblock child process
  225. uint8_t data = 1;
  226. (void)write(fds[1], &data, 1);
  227. // Child process should have exited with a zero status.
  228. int ret;
  229. ASSERT_EQ(pid, waitpid(pid, &ret, 0));
  230. EXPECT_NE(0, WIFEXITED(ret));
  231. EXPECT_EQ(0, WEXITSTATUS(ret));
  232. }
  233. // Test that memory around the instruction pointer is written
  234. // to the dump as a MinidumpMemoryRegion.
  235. TEST_F(ExceptionHandlerTest, InstructionPointerMemory) {
  236. // Give the child process a pipe to report back on.
  237. int fds[2];
  238. ASSERT_EQ(0, pipe(fds));
  239. // These are defined here so the parent can use them to check the
  240. // data from the minidump afterwards.
  241. const u_int32_t kMemorySize = 256; // bytes
  242. const int kOffset = kMemorySize / 2;
  243. // This crashes with SIGILL on x86/x86-64/arm.
  244. const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
  245. pid_t pid = fork();
  246. if (pid == 0) {
  247. close(fds[0]);
  248. ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
  249. // Get some executable memory.
  250. char* memory =
  251. reinterpret_cast<char*>(mmap(NULL,
  252. kMemorySize,
  253. PROT_READ | PROT_WRITE | PROT_EXEC,
  254. MAP_PRIVATE | MAP_ANON,
  255. -1,
  256. 0));
  257. if (!memory)
  258. exit(0);
  259. // Write some instructions that will crash. Put them in the middle
  260. // of the block of memory, because the minidump should contain 128
  261. // bytes on either side of the instruction pointer.
  262. memcpy(memory + kOffset, instructions, sizeof(instructions));
  263. // Now execute the instructions, which should crash.
  264. typedef void (*void_function)(void);
  265. void_function memory_function =
  266. reinterpret_cast<void_function>(memory + kOffset);
  267. memory_function();
  268. // not reached
  269. exit(1);
  270. }
  271. // In the parent process.
  272. ASSERT_NE(-1, pid);
  273. close(fds[1]);
  274. // Wait for the background process to return the minidump file.
  275. close(fds[1]);
  276. char minidump_file[PATH_MAX];
  277. ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
  278. ASSERT_NE(0, nbytes);
  279. // Ensure that minidump file exists and is > 0 bytes.
  280. struct stat st;
  281. ASSERT_EQ(0, stat(minidump_file, &st));
  282. ASSERT_LT(0, st.st_size);
  283. // Child process should have exited with a zero status.
  284. int ret;
  285. ASSERT_EQ(pid, waitpid(pid, &ret, 0));
  286. EXPECT_NE(0, WIFEXITED(ret));
  287. EXPECT_EQ(0, WEXITSTATUS(ret));
  288. // Read the minidump. Locate the exception record and the
  289. // memory list, and then ensure that there is a memory region
  290. // in the memory list that covers the instruction pointer from
  291. // the exception record.
  292. Minidump minidump(minidump_file);
  293. ASSERT_TRUE(minidump.Read());
  294. MinidumpException* exception = minidump.GetException();
  295. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  296. ASSERT_TRUE(exception);
  297. ASSERT_TRUE(memory_list);
  298. ASSERT_NE((unsigned int)0, memory_list->region_count());
  299. MinidumpContext* context = exception->GetContext();
  300. ASSERT_TRUE(context);
  301. u_int64_t instruction_pointer;
  302. switch (context->GetContextCPU()) {
  303. case MD_CONTEXT_X86:
  304. instruction_pointer = context->GetContextX86()->eip;
  305. break;
  306. case MD_CONTEXT_AMD64:
  307. instruction_pointer = context->GetContextAMD64()->rip;
  308. break;
  309. case MD_CONTEXT_ARM:
  310. instruction_pointer = context->GetContextARM()->iregs[15];
  311. break;
  312. default:
  313. FAIL() << "Unknown context CPU: " << context->GetContextCPU();
  314. break;
  315. }
  316. MinidumpMemoryRegion* region =
  317. memory_list->GetMemoryRegionForAddress(instruction_pointer);
  318. EXPECT_TRUE(region);
  319. EXPECT_EQ(kMemorySize, region->GetSize());
  320. const u_int8_t* bytes = region->GetMemory();
  321. ASSERT_TRUE(bytes);
  322. u_int8_t prefix_bytes[kOffset];
  323. u_int8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)];
  324. memset(prefix_bytes, 0, sizeof(prefix_bytes));
  325. memset(suffix_bytes, 0, sizeof(suffix_bytes));
  326. EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
  327. EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
  328. EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
  329. suffix_bytes, sizeof(suffix_bytes)) == 0);
  330. }
  331. // Test that the memory region around the instruction pointer is
  332. // bounded correctly on the low end.
  333. TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
  334. // Give the child process a pipe to report back on.
  335. int fds[2];
  336. ASSERT_EQ(0, pipe(fds));
  337. // These are defined here so the parent can use them to check the
  338. // data from the minidump afterwards.
  339. const u_int32_t kMemorySize = 256; // bytes
  340. const int kOffset = 0;
  341. // This crashes with SIGILL on x86/x86-64/arm.
  342. const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
  343. pid_t pid = fork();
  344. if (pid == 0) {
  345. close(fds[0]);
  346. ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
  347. // Get some executable memory.
  348. char* memory =
  349. reinterpret_cast<char*>(mmap(NULL,
  350. kMemorySize,
  351. PROT_READ | PROT_WRITE | PROT_EXEC,
  352. MAP_PRIVATE | MAP_ANON,
  353. -1,
  354. 0));
  355. if (!memory)
  356. exit(0);
  357. // Write some instructions that will crash. Put them at the start
  358. // of the block of memory, to ensure that the memory bounding
  359. // works properly.
  360. memcpy(memory + kOffset, instructions, sizeof(instructions));
  361. // Now execute the instructions, which should crash.
  362. typedef void (*void_function)(void);
  363. void_function memory_function =
  364. reinterpret_cast<void_function>(memory + kOffset);
  365. memory_function();
  366. // not reached
  367. exit(1);
  368. }
  369. // In the parent process.
  370. ASSERT_NE(-1, pid);
  371. close(fds[1]);
  372. // Wait for the background process to return the minidump file.
  373. close(fds[1]);
  374. char minidump_file[PATH_MAX];
  375. ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
  376. ASSERT_NE(0, nbytes);
  377. // Ensure that minidump file exists and is > 0 bytes.
  378. struct stat st;
  379. ASSERT_EQ(0, stat(minidump_file, &st));
  380. ASSERT_LT(0, st.st_size);
  381. // Child process should have exited with a zero status.
  382. int ret;
  383. ASSERT_EQ(pid, waitpid(pid, &ret, 0));
  384. EXPECT_NE(0, WIFEXITED(ret));
  385. EXPECT_EQ(0, WEXITSTATUS(ret));
  386. // Read the minidump. Locate the exception record and the
  387. // memory list, and then ensure that there is a memory region
  388. // in the memory list that covers the instruction pointer from
  389. // the exception record.
  390. Minidump minidump(minidump_file);
  391. ASSERT_TRUE(minidump.Read());
  392. MinidumpException* exception = minidump.GetException();
  393. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  394. ASSERT_TRUE(exception);
  395. ASSERT_TRUE(memory_list);
  396. ASSERT_NE((unsigned int)0, memory_list->region_count());
  397. MinidumpContext* context = exception->GetContext();
  398. ASSERT_TRUE(context);
  399. u_int64_t instruction_pointer;
  400. switch (context->GetContextCPU()) {
  401. case MD_CONTEXT_X86:
  402. instruction_pointer = context->GetContextX86()->eip;
  403. break;
  404. case MD_CONTEXT_AMD64:
  405. instruction_pointer = context->GetContextAMD64()->rip;
  406. break;
  407. case MD_CONTEXT_ARM:
  408. instruction_pointer = context->GetContextARM()->iregs[15];
  409. break;
  410. default:
  411. FAIL() << "Unknown context CPU: " << context->GetContextCPU();
  412. break;
  413. }
  414. MinidumpMemoryRegion* region =
  415. memory_list->GetMemoryRegionForAddress(instruction_pointer);
  416. EXPECT_TRUE(region);
  417. EXPECT_EQ(kMemorySize / 2, region->GetSize());
  418. const u_int8_t* bytes = region->GetMemory();
  419. ASSERT_TRUE(bytes);
  420. u_int8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)];
  421. memset(suffix_bytes, 0, sizeof(suffix_bytes));
  422. EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
  423. EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
  424. suffix_bytes, sizeof(suffix_bytes)) == 0);
  425. }
  426. // Test that the memory region around the instruction pointer is
  427. // bounded correctly on the high end.
  428. TEST_F(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) {
  429. // Give the child process a pipe to report back on.
  430. int fds[2];
  431. ASSERT_EQ(0, pipe(fds));
  432. // These are defined here so the parent can use them to check the
  433. // data from the minidump afterwards.
  434. // Use 4k here because the OS will hand out a single page even
  435. // if a smaller size is requested, and this test wants to
  436. // test the upper bound of the memory range.
  437. const u_int32_t kMemorySize = 4096; // bytes
  438. // This crashes with SIGILL on x86/x86-64/arm.
  439. const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
  440. const int kOffset = kMemorySize - sizeof(instructions);
  441. pid_t pid = fork();
  442. if (pid == 0) {
  443. close(fds[0]);
  444. ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
  445. // Get some executable memory.
  446. char* memory =
  447. reinterpret_cast<char*>(mmap(NULL,
  448. kMemorySize,
  449. PROT_READ | PROT_WRITE | PROT_EXEC,
  450. MAP_PRIVATE | MAP_ANON,
  451. -1,
  452. 0));
  453. if (!memory)
  454. exit(0);
  455. // Write some instructions that will crash. Put them at the start
  456. // of the block of memory, to ensure that the memory bounding
  457. // works properly.
  458. memcpy(memory + kOffset, instructions, sizeof(instructions));
  459. // Now execute the instructions, which should crash.
  460. typedef void (*void_function)(void);
  461. void_function memory_function =
  462. reinterpret_cast<void_function>(memory + kOffset);
  463. memory_function();
  464. // not reached
  465. exit(1);
  466. }
  467. // In the parent process.
  468. ASSERT_NE(-1, pid);
  469. close(fds[1]);
  470. // Wait for the background process to return the minidump file.
  471. close(fds[1]);
  472. char minidump_file[PATH_MAX];
  473. ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
  474. ASSERT_NE(0, nbytes);
  475. // Ensure that minidump file exists and is > 0 bytes.
  476. struct stat st;
  477. ASSERT_EQ(0, stat(minidump_file, &st));
  478. ASSERT_LT(0, st.st_size);
  479. // Child process should have exited with a zero status.
  480. int ret;
  481. ASSERT_EQ(pid, waitpid(pid, &ret, 0));
  482. EXPECT_NE(0, WIFEXITED(ret));
  483. EXPECT_EQ(0, WEXITSTATUS(ret));
  484. // Read the minidump. Locate the exception record and the
  485. // memory list, and then ensure that there is a memory region
  486. // in the memory list that covers the instruction pointer from
  487. // the exception record.
  488. Minidump minidump(minidump_file);
  489. ASSERT_TRUE(minidump.Read());
  490. MinidumpException* exception = minidump.GetException();
  491. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  492. ASSERT_TRUE(exception);
  493. ASSERT_TRUE(memory_list);
  494. ASSERT_NE((unsigned int)0, memory_list->region_count());
  495. MinidumpContext* context = exception->GetContext();
  496. ASSERT_TRUE(context);
  497. u_int64_t instruction_pointer;
  498. switch (context->GetContextCPU()) {
  499. case MD_CONTEXT_X86:
  500. instruction_pointer = context->GetContextX86()->eip;
  501. break;
  502. case MD_CONTEXT_AMD64:
  503. instruction_pointer = context->GetContextAMD64()->rip;
  504. break;
  505. case MD_CONTEXT_ARM:
  506. instruction_pointer = context->GetContextARM()->iregs[15];
  507. break;
  508. default:
  509. FAIL() << "Unknown context CPU: " << context->GetContextCPU();
  510. break;
  511. }
  512. MinidumpMemoryRegion* region =
  513. memory_list->GetMemoryRegionForAddress(instruction_pointer);
  514. EXPECT_TRUE(region);
  515. const size_t kPrefixSize = 128; // bytes
  516. EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize());
  517. const u_int8_t* bytes = region->GetMemory();
  518. ASSERT_TRUE(bytes);
  519. u_int8_t prefix_bytes[kPrefixSize];
  520. memset(prefix_bytes, 0, sizeof(prefix_bytes));
  521. EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
  522. EXPECT_TRUE(memcmp(bytes + kPrefixSize,
  523. instructions, sizeof(instructions)) == 0);
  524. }
  525. // Ensure that an extra memory block doesn't get added when the
  526. // instruction pointer is not in mapped memory.
  527. TEST_F(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
  528. // Give the child process a pipe to report back on.
  529. int fds[2];
  530. ASSERT_EQ(0, pipe(fds));
  531. pid_t pid = fork();
  532. if (pid == 0) {
  533. close(fds[0]);
  534. ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
  535. // Try calling a NULL pointer.
  536. typedef void (*void_function)(void);
  537. void_function memory_function =
  538. reinterpret_cast<void_function>(NULL);
  539. memory_function();
  540. // not reached
  541. exit(1);
  542. }
  543. // In the parent process.
  544. ASSERT_NE(-1, pid);
  545. close(fds[1]);
  546. // Wait for the background process to return the minidump file.
  547. close(fds[1]);
  548. char minidump_file[PATH_MAX];
  549. ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
  550. ASSERT_NE(0, nbytes);
  551. // Ensure that minidump file exists and is > 0 bytes.
  552. struct stat st;
  553. ASSERT_EQ(0, stat(minidump_file, &st));
  554. ASSERT_LT(0, st.st_size);
  555. // Child process should have exited with a zero status.
  556. int ret;
  557. ASSERT_EQ(pid, waitpid(pid, &ret, 0));
  558. EXPECT_NE(0, WIFEXITED(ret));
  559. EXPECT_EQ(0, WEXITSTATUS(ret));
  560. // Read the minidump. Locate the exception record and the
  561. // memory list, and then ensure that there is only one memory region
  562. // in the memory list (the thread memory from the single thread).
  563. Minidump minidump(minidump_file);
  564. ASSERT_TRUE(minidump.Read());
  565. MinidumpException* exception = minidump.GetException();
  566. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  567. ASSERT_TRUE(exception);
  568. ASSERT_TRUE(memory_list);
  569. ASSERT_EQ((unsigned int)1, memory_list->region_count());
  570. }
  571. static void *Junk(void *) {
  572. sleep(1000000);
  573. return NULL;
  574. }
  575. // Test that the memory list gets written correctly when multiple
  576. // threads are running.
  577. TEST_F(ExceptionHandlerTest, MemoryListMultipleThreads) {
  578. // Give the child process a pipe to report back on.
  579. int fds[2];
  580. ASSERT_EQ(0, pipe(fds));
  581. pid_t pid = fork();
  582. if (pid == 0) {
  583. close(fds[0]);
  584. ExceptionHandler eh(tempDir.path(), NULL, MDCallback, &fds[1], true, NULL);
  585. // Run an extra thread so >2 memory regions will be written.
  586. pthread_t junk_thread;
  587. if (pthread_create(&junk_thread, NULL, Junk, NULL) == 0)
  588. pthread_detach(junk_thread);
  589. // Just crash.
  590. Crasher();
  591. // not reached
  592. exit(1);
  593. }
  594. // In the parent process.
  595. ASSERT_NE(-1, pid);
  596. close(fds[1]);
  597. // Wait for the background process to return the minidump file.
  598. close(fds[1]);
  599. char minidump_file[PATH_MAX];
  600. ssize_t nbytes = read(fds[0], minidump_file, sizeof(minidump_file));
  601. ASSERT_NE(0, nbytes);
  602. // Ensure that minidump file exists and is > 0 bytes.
  603. struct stat st;
  604. ASSERT_EQ(0, stat(minidump_file, &st));
  605. ASSERT_LT(0, st.st_size);
  606. // Child process should have exited with a zero status.
  607. int ret;
  608. ASSERT_EQ(pid, waitpid(pid, &ret, 0));
  609. EXPECT_NE(0, WIFEXITED(ret));
  610. EXPECT_EQ(0, WEXITSTATUS(ret));
  611. // Read the minidump, and verify that the memory list can be read.
  612. Minidump minidump(minidump_file);
  613. ASSERT_TRUE(minidump.Read());
  614. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  615. ASSERT_TRUE(memory_list);
  616. // Verify that there are three memory regions:
  617. // one per thread, and one for the instruction pointer memory.
  618. ASSERT_EQ((unsigned int)3, memory_list->region_count());
  619. }
  620. }