/thirdparty/breakpad/client/linux/handler/exception_handler_unittest.cc

http://github.com/tomahawk-player/tomahawk · C++ · 786 lines · 575 code · 113 blank · 98 comment · 39 complexity · 452ff11368949d81e1abfac83c4414d2 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. #include <stdint.h>
  30. #include <unistd.h>
  31. #include <signal.h>
  32. #include <sys/mman.h>
  33. #include <sys/poll.h>
  34. #include <sys/socket.h>
  35. #include <sys/uio.h>
  36. #include <sys/wait.h>
  37. #include <string>
  38. #include "breakpad_googletest_includes.h"
  39. #include "client/linux/handler/exception_handler.h"
  40. #include "client/linux/minidump_writer/minidump_writer.h"
  41. #include "common/linux/eintr_wrapper.h"
  42. #include "common/linux/file_id.h"
  43. #include "common/linux/linux_libc_support.h"
  44. #include "common/tests/auto_tempdir.h"
  45. #include "third_party/lss/linux_syscall_support.h"
  46. #include "google_breakpad/processor/minidump.h"
  47. using namespace google_breakpad;
  48. // Length of a formatted GUID string =
  49. // sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator)
  50. const int kGUIDStringSize = 37;
  51. static void sigchld_handler(int signo) { }
  52. class ExceptionHandlerTest : public ::testing::Test {
  53. protected:
  54. void SetUp() {
  55. // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
  56. struct sigaction sa;
  57. memset(&sa, 0, sizeof(sa));
  58. sa.sa_handler = sigchld_handler;
  59. ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1);
  60. }
  61. void TearDown() {
  62. sigaction(SIGCHLD, &old_action, NULL);
  63. }
  64. struct sigaction old_action;
  65. };
  66. TEST(ExceptionHandlerTest, Simple) {
  67. AutoTempDir temp_dir;
  68. ExceptionHandler handler(temp_dir.path(), NULL, NULL, NULL, true);
  69. }
  70. static bool DoneCallback(const char* dump_path,
  71. const char* minidump_id,
  72. void* context,
  73. bool succeeded) {
  74. if (!succeeded)
  75. return succeeded;
  76. int fd = (intptr_t) context;
  77. uint32_t len = my_strlen(minidump_id);
  78. HANDLE_EINTR(sys_write(fd, &len, sizeof(len)));
  79. HANDLE_EINTR(sys_write(fd, minidump_id, len));
  80. sys_close(fd);
  81. return true;
  82. }
  83. TEST(ExceptionHandlerTest, ChildCrash) {
  84. AutoTempDir temp_dir;
  85. int fds[2];
  86. ASSERT_NE(pipe(fds), -1);
  87. const pid_t child = fork();
  88. if (child == 0) {
  89. close(fds[0]);
  90. ExceptionHandler handler(temp_dir.path(), NULL, DoneCallback, (void*) fds[1],
  91. true);
  92. *reinterpret_cast<volatile int*>(NULL) = 0;
  93. }
  94. close(fds[1]);
  95. int status;
  96. ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
  97. ASSERT_TRUE(WIFSIGNALED(status));
  98. ASSERT_EQ(WTERMSIG(status), SIGSEGV);
  99. struct pollfd pfd;
  100. memset(&pfd, 0, sizeof(pfd));
  101. pfd.fd = fds[0];
  102. pfd.events = POLLIN | POLLERR;
  103. const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
  104. ASSERT_EQ(r, 1);
  105. ASSERT_TRUE(pfd.revents & POLLIN);
  106. uint32_t len;
  107. ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
  108. ASSERT_LT(len, (uint32_t)2048);
  109. char* filename = reinterpret_cast<char*>(malloc(len + 1));
  110. ASSERT_EQ(read(fds[0], filename, len), len);
  111. filename[len] = 0;
  112. close(fds[0]);
  113. const std::string minidump_filename = temp_dir.path() + "/" + filename +
  114. ".dmp";
  115. struct stat st;
  116. ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
  117. ASSERT_GT(st.st_size, 0u);
  118. unlink(minidump_filename.c_str());
  119. }
  120. // Test that memory around the instruction pointer is written
  121. // to the dump as a MinidumpMemoryRegion.
  122. TEST(ExceptionHandlerTest, InstructionPointerMemory) {
  123. AutoTempDir temp_dir;
  124. int fds[2];
  125. ASSERT_NE(pipe(fds), -1);
  126. // These are defined here so the parent can use them to check the
  127. // data from the minidump afterwards.
  128. const u_int32_t kMemorySize = 256; // bytes
  129. const int kOffset = kMemorySize / 2;
  130. // This crashes with SIGILL on x86/x86-64/arm.
  131. const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
  132. const pid_t child = fork();
  133. if (child == 0) {
  134. close(fds[0]);
  135. ExceptionHandler handler(temp_dir.path(), NULL, DoneCallback,
  136. (void*) fds[1], true);
  137. // Get some executable memory.
  138. char* memory =
  139. reinterpret_cast<char*>(mmap(NULL,
  140. kMemorySize,
  141. PROT_READ | PROT_WRITE | PROT_EXEC,
  142. MAP_PRIVATE | MAP_ANON,
  143. -1,
  144. 0));
  145. if (!memory)
  146. exit(0);
  147. // Write some instructions that will crash. Put them in the middle
  148. // of the block of memory, because the minidump should contain 128
  149. // bytes on either side of the instruction pointer.
  150. memcpy(memory + kOffset, instructions, sizeof(instructions));
  151. // Now execute the instructions, which should crash.
  152. typedef void (*void_function)(void);
  153. void_function memory_function =
  154. reinterpret_cast<void_function>(memory + kOffset);
  155. memory_function();
  156. }
  157. close(fds[1]);
  158. int status;
  159. ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
  160. ASSERT_TRUE(WIFSIGNALED(status));
  161. ASSERT_EQ(WTERMSIG(status), SIGILL);
  162. struct pollfd pfd;
  163. memset(&pfd, 0, sizeof(pfd));
  164. pfd.fd = fds[0];
  165. pfd.events = POLLIN | POLLERR;
  166. const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
  167. ASSERT_EQ(r, 1);
  168. ASSERT_TRUE(pfd.revents & POLLIN);
  169. uint32_t len;
  170. ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
  171. ASSERT_LT(len, (uint32_t)2048);
  172. char* filename = reinterpret_cast<char*>(malloc(len + 1));
  173. ASSERT_EQ(read(fds[0], filename, len), len);
  174. filename[len] = 0;
  175. close(fds[0]);
  176. const std::string minidump_filename = temp_dir.path() + "/" + filename +
  177. ".dmp";
  178. struct stat st;
  179. ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
  180. ASSERT_GT(st.st_size, 0u);
  181. // Read the minidump. Locate the exception record and the
  182. // memory list, and then ensure that there is a memory region
  183. // in the memory list that covers the instruction pointer from
  184. // the exception record.
  185. Minidump minidump(minidump_filename);
  186. ASSERT_TRUE(minidump.Read());
  187. MinidumpException* exception = minidump.GetException();
  188. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  189. ASSERT_TRUE(exception);
  190. ASSERT_TRUE(memory_list);
  191. ASSERT_LT(0, memory_list->region_count());
  192. MinidumpContext* context = exception->GetContext();
  193. ASSERT_TRUE(context);
  194. u_int64_t instruction_pointer;
  195. switch (context->GetContextCPU()) {
  196. case MD_CONTEXT_X86:
  197. instruction_pointer = context->GetContextX86()->eip;
  198. break;
  199. case MD_CONTEXT_AMD64:
  200. instruction_pointer = context->GetContextAMD64()->rip;
  201. break;
  202. case MD_CONTEXT_ARM:
  203. instruction_pointer = context->GetContextARM()->iregs[15];
  204. break;
  205. default:
  206. FAIL() << "Unknown context CPU: " << context->GetContextCPU();
  207. break;
  208. }
  209. MinidumpMemoryRegion* region =
  210. memory_list->GetMemoryRegionForAddress(instruction_pointer);
  211. ASSERT_TRUE(region);
  212. EXPECT_EQ(kMemorySize, region->GetSize());
  213. const u_int8_t* bytes = region->GetMemory();
  214. ASSERT_TRUE(bytes);
  215. u_int8_t prefix_bytes[kOffset];
  216. u_int8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)];
  217. memset(prefix_bytes, 0, sizeof(prefix_bytes));
  218. memset(suffix_bytes, 0, sizeof(suffix_bytes));
  219. EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
  220. EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
  221. EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
  222. suffix_bytes, sizeof(suffix_bytes)) == 0);
  223. unlink(minidump_filename.c_str());
  224. free(filename);
  225. }
  226. // Test that the memory region around the instruction pointer is
  227. // bounded correctly on the low end.
  228. TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
  229. AutoTempDir temp_dir;
  230. int fds[2];
  231. ASSERT_NE(pipe(fds), -1);
  232. // These are defined here so the parent can use them to check the
  233. // data from the minidump afterwards.
  234. const u_int32_t kMemorySize = 256; // bytes
  235. const int kOffset = 0;
  236. // This crashes with SIGILL on x86/x86-64/arm.
  237. const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
  238. const pid_t child = fork();
  239. if (child == 0) {
  240. close(fds[0]);
  241. ExceptionHandler handler(temp_dir.path(), NULL, DoneCallback,
  242. (void*) fds[1], true);
  243. // Get some executable memory.
  244. char* memory =
  245. reinterpret_cast<char*>(mmap(NULL,
  246. kMemorySize,
  247. PROT_READ | PROT_WRITE | PROT_EXEC,
  248. MAP_PRIVATE | MAP_ANON,
  249. -1,
  250. 0));
  251. if (!memory)
  252. exit(0);
  253. // Write some instructions that will crash. Put them in the middle
  254. // of the block of memory, because the minidump should contain 128
  255. // bytes on either side of the instruction pointer.
  256. memcpy(memory + kOffset, instructions, sizeof(instructions));
  257. // Now execute the instructions, which should crash.
  258. typedef void (*void_function)(void);
  259. void_function memory_function =
  260. reinterpret_cast<void_function>(memory + kOffset);
  261. memory_function();
  262. }
  263. close(fds[1]);
  264. int status;
  265. ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
  266. ASSERT_TRUE(WIFSIGNALED(status));
  267. ASSERT_EQ(WTERMSIG(status), SIGILL);
  268. struct pollfd pfd;
  269. memset(&pfd, 0, sizeof(pfd));
  270. pfd.fd = fds[0];
  271. pfd.events = POLLIN | POLLERR;
  272. const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
  273. ASSERT_EQ(r, 1);
  274. ASSERT_TRUE(pfd.revents & POLLIN);
  275. uint32_t len;
  276. ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
  277. ASSERT_LT(len, (uint32_t)2048);
  278. char* filename = reinterpret_cast<char*>(malloc(len + 1));
  279. ASSERT_EQ(read(fds[0], filename, len), len);
  280. filename[len] = 0;
  281. close(fds[0]);
  282. const std::string minidump_filename = temp_dir.path() + "/" + filename +
  283. ".dmp";
  284. struct stat st;
  285. ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
  286. ASSERT_GT(st.st_size, 0u);
  287. // Read the minidump. Locate the exception record and the
  288. // memory list, and then ensure that there is a memory region
  289. // in the memory list that covers the instruction pointer from
  290. // the exception record.
  291. Minidump minidump(minidump_filename);
  292. ASSERT_TRUE(minidump.Read());
  293. MinidumpException* exception = minidump.GetException();
  294. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  295. ASSERT_TRUE(exception);
  296. ASSERT_TRUE(memory_list);
  297. ASSERT_LT(0, memory_list->region_count());
  298. MinidumpContext* context = exception->GetContext();
  299. ASSERT_TRUE(context);
  300. u_int64_t instruction_pointer;
  301. switch (context->GetContextCPU()) {
  302. case MD_CONTEXT_X86:
  303. instruction_pointer = context->GetContextX86()->eip;
  304. break;
  305. case MD_CONTEXT_AMD64:
  306. instruction_pointer = context->GetContextAMD64()->rip;
  307. break;
  308. case MD_CONTEXT_ARM:
  309. instruction_pointer = context->GetContextARM()->iregs[15];
  310. break;
  311. default:
  312. FAIL() << "Unknown context CPU: " << context->GetContextCPU();
  313. break;
  314. }
  315. MinidumpMemoryRegion* region =
  316. memory_list->GetMemoryRegionForAddress(instruction_pointer);
  317. ASSERT_TRUE(region);
  318. EXPECT_EQ(kMemorySize / 2, region->GetSize());
  319. const u_int8_t* bytes = region->GetMemory();
  320. ASSERT_TRUE(bytes);
  321. u_int8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)];
  322. memset(suffix_bytes, 0, sizeof(suffix_bytes));
  323. EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0);
  324. EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions),
  325. suffix_bytes, sizeof(suffix_bytes)) == 0);
  326. unlink(minidump_filename.c_str());
  327. free(filename);
  328. }
  329. // Test that the memory region around the instruction pointer is
  330. // bounded correctly on the high end.
  331. TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) {
  332. AutoTempDir temp_dir;
  333. int fds[2];
  334. ASSERT_NE(pipe(fds), -1);
  335. // These are defined here so the parent can use them to check the
  336. // data from the minidump afterwards.
  337. // Use 4k here because the OS will hand out a single page even
  338. // if a smaller size is requested, and this test wants to
  339. // test the upper bound of the memory range.
  340. const u_int32_t kMemorySize = 4096; // bytes
  341. // This crashes with SIGILL on x86/x86-64/arm.
  342. const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
  343. const int kOffset = kMemorySize - sizeof(instructions);
  344. const pid_t child = fork();
  345. if (child == 0) {
  346. close(fds[0]);
  347. ExceptionHandler handler(temp_dir.path(), NULL, DoneCallback,
  348. (void*) fds[1], true);
  349. // Get some executable memory.
  350. char* memory =
  351. reinterpret_cast<char*>(mmap(NULL,
  352. kMemorySize,
  353. PROT_READ | PROT_WRITE | PROT_EXEC,
  354. MAP_PRIVATE | MAP_ANON,
  355. -1,
  356. 0));
  357. if (!memory)
  358. exit(0);
  359. // Write some instructions that will crash. Put them in the middle
  360. // of the block of memory, because the minidump should contain 128
  361. // bytes on either side of the instruction pointer.
  362. memcpy(memory + kOffset, instructions, sizeof(instructions));
  363. // Now execute the instructions, which should crash.
  364. typedef void (*void_function)(void);
  365. void_function memory_function =
  366. reinterpret_cast<void_function>(memory + kOffset);
  367. memory_function();
  368. }
  369. close(fds[1]);
  370. int status;
  371. ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
  372. ASSERT_TRUE(WIFSIGNALED(status));
  373. ASSERT_EQ(WTERMSIG(status), SIGILL);
  374. struct pollfd pfd;
  375. memset(&pfd, 0, sizeof(pfd));
  376. pfd.fd = fds[0];
  377. pfd.events = POLLIN | POLLERR;
  378. const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
  379. ASSERT_EQ(r, 1);
  380. ASSERT_TRUE(pfd.revents & POLLIN);
  381. uint32_t len;
  382. ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
  383. ASSERT_LT(len, (uint32_t)2048);
  384. char* filename = reinterpret_cast<char*>(malloc(len + 1));
  385. ASSERT_EQ(read(fds[0], filename, len), len);
  386. filename[len] = 0;
  387. close(fds[0]);
  388. const std::string minidump_filename = temp_dir.path() + "/" + filename +
  389. ".dmp";
  390. struct stat st;
  391. ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
  392. ASSERT_GT(st.st_size, 0u);
  393. // Read the minidump. Locate the exception record and the
  394. // memory list, and then ensure that there is a memory region
  395. // in the memory list that covers the instruction pointer from
  396. // the exception record.
  397. Minidump minidump(minidump_filename);
  398. ASSERT_TRUE(minidump.Read());
  399. MinidumpException* exception = minidump.GetException();
  400. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  401. ASSERT_TRUE(exception);
  402. ASSERT_TRUE(memory_list);
  403. ASSERT_LT(0, memory_list->region_count());
  404. MinidumpContext* context = exception->GetContext();
  405. ASSERT_TRUE(context);
  406. u_int64_t instruction_pointer;
  407. switch (context->GetContextCPU()) {
  408. case MD_CONTEXT_X86:
  409. instruction_pointer = context->GetContextX86()->eip;
  410. break;
  411. case MD_CONTEXT_AMD64:
  412. instruction_pointer = context->GetContextAMD64()->rip;
  413. break;
  414. case MD_CONTEXT_ARM:
  415. instruction_pointer = context->GetContextARM()->iregs[15];
  416. break;
  417. default:
  418. FAIL() << "Unknown context CPU: " << context->GetContextCPU();
  419. break;
  420. }
  421. MinidumpMemoryRegion* region =
  422. memory_list->GetMemoryRegionForAddress(instruction_pointer);
  423. ASSERT_TRUE(region);
  424. const size_t kPrefixSize = 128; // bytes
  425. EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize());
  426. const u_int8_t* bytes = region->GetMemory();
  427. ASSERT_TRUE(bytes);
  428. u_int8_t prefix_bytes[kPrefixSize];
  429. memset(prefix_bytes, 0, sizeof(prefix_bytes));
  430. EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
  431. EXPECT_TRUE(memcmp(bytes + kPrefixSize,
  432. instructions, sizeof(instructions)) == 0);
  433. unlink(minidump_filename.c_str());
  434. free(filename);
  435. }
  436. // Ensure that an extra memory block doesn't get added when the
  437. // instruction pointer is not in mapped memory.
  438. TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
  439. AutoTempDir temp_dir;
  440. int fds[2];
  441. ASSERT_NE(pipe(fds), -1);
  442. const pid_t child = fork();
  443. if (child == 0) {
  444. close(fds[0]);
  445. ExceptionHandler handler(temp_dir.path(), NULL, DoneCallback,
  446. (void*) fds[1], true);
  447. // Try calling a NULL pointer.
  448. typedef void (*void_function)(void);
  449. void_function memory_function =
  450. reinterpret_cast<void_function>(NULL);
  451. memory_function();
  452. }
  453. close(fds[1]);
  454. int status;
  455. ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
  456. ASSERT_TRUE(WIFSIGNALED(status));
  457. ASSERT_EQ(WTERMSIG(status), SIGSEGV);
  458. struct pollfd pfd;
  459. memset(&pfd, 0, sizeof(pfd));
  460. pfd.fd = fds[0];
  461. pfd.events = POLLIN | POLLERR;
  462. const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
  463. ASSERT_EQ(r, 1);
  464. ASSERT_TRUE(pfd.revents & POLLIN);
  465. uint32_t len;
  466. ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
  467. ASSERT_LT(len, (uint32_t)2048);
  468. char* filename = reinterpret_cast<char*>(malloc(len + 1));
  469. ASSERT_EQ(read(fds[0], filename, len), len);
  470. filename[len] = 0;
  471. close(fds[0]);
  472. const std::string minidump_filename = temp_dir.path() + "/" + filename +
  473. ".dmp";
  474. struct stat st;
  475. ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
  476. ASSERT_GT(st.st_size, 0u);
  477. // Read the minidump. Locate the exception record and the
  478. // memory list, and then ensure that there is a memory region
  479. // in the memory list that covers the instruction pointer from
  480. // the exception record.
  481. Minidump minidump(minidump_filename);
  482. ASSERT_TRUE(minidump.Read());
  483. MinidumpException* exception = minidump.GetException();
  484. MinidumpMemoryList* memory_list = minidump.GetMemoryList();
  485. ASSERT_TRUE(exception);
  486. ASSERT_TRUE(memory_list);
  487. ASSERT_EQ((unsigned int)1, memory_list->region_count());
  488. unlink(minidump_filename.c_str());
  489. free(filename);
  490. }
  491. static bool SimpleCallback(const char* dump_path,
  492. const char* minidump_id,
  493. void* context,
  494. bool succeeded) {
  495. if (!succeeded)
  496. return succeeded;
  497. string* minidump_file = reinterpret_cast<string*>(context);
  498. minidump_file->append(dump_path);
  499. minidump_file->append("/");
  500. minidump_file->append(minidump_id);
  501. minidump_file->append(".dmp");
  502. return true;
  503. }
  504. // Test that anonymous memory maps can be annotated with names and IDs.
  505. TEST(ExceptionHandlerTest, ModuleInfo) {
  506. // These are defined here so the parent can use them to check the
  507. // data from the minidump afterwards.
  508. const u_int32_t kMemorySize = sysconf(_SC_PAGESIZE);
  509. const char* kMemoryName = "a fake module";
  510. const u_int8_t kModuleGUID[sizeof(MDGUID)] = {
  511. 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
  512. 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
  513. };
  514. char module_identifier_buffer[kGUIDStringSize];
  515. FileID::ConvertIdentifierToString(kModuleGUID,
  516. module_identifier_buffer,
  517. sizeof(module_identifier_buffer));
  518. string module_identifier(module_identifier_buffer);
  519. // Strip out dashes
  520. size_t pos;
  521. while ((pos = module_identifier.find('-')) != string::npos) {
  522. module_identifier.erase(pos, 1);
  523. }
  524. // And append a zero, because module IDs include an "age" field
  525. // which is always zero on Linux.
  526. module_identifier += "0";
  527. // Get some memory.
  528. char* memory =
  529. reinterpret_cast<char*>(mmap(NULL,
  530. kMemorySize,
  531. PROT_READ | PROT_WRITE,
  532. MAP_PRIVATE | MAP_ANON,
  533. -1,
  534. 0));
  535. const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
  536. ASSERT_TRUE(memory);
  537. string minidump_filename;
  538. AutoTempDir temp_dir;
  539. ExceptionHandler handler(temp_dir.path(), NULL, SimpleCallback,
  540. (void*)&minidump_filename, true);
  541. // Add info about the anonymous memory mapping.
  542. handler.AddMappingInfo(kMemoryName,
  543. kModuleGUID,
  544. kMemoryAddress,
  545. kMemorySize,
  546. 0);
  547. handler.WriteMinidump();
  548. // Read the minidump. Load the module list, and ensure that
  549. // the mmap'ed |memory| is listed with the given module name
  550. // and debug ID.
  551. Minidump minidump(minidump_filename);
  552. ASSERT_TRUE(minidump.Read());
  553. MinidumpModuleList* module_list = minidump.GetModuleList();
  554. ASSERT_TRUE(module_list);
  555. const MinidumpModule* module =
  556. module_list->GetModuleForAddress(kMemoryAddress);
  557. ASSERT_TRUE(module);
  558. EXPECT_EQ(kMemoryAddress, module->base_address());
  559. EXPECT_EQ(kMemorySize, module->size());
  560. EXPECT_EQ(kMemoryName, module->code_file());
  561. EXPECT_EQ(module_identifier, module->debug_identifier());
  562. unlink(minidump_filename.c_str());
  563. }
  564. static const unsigned kControlMsgSize =
  565. CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
  566. static bool
  567. CrashHandler(const void* crash_context, size_t crash_context_size,
  568. void* context) {
  569. const int fd = (intptr_t) context;
  570. int fds[2];
  571. if (pipe(fds) == -1) {
  572. // There doesn't seem to be any way to reliably handle
  573. // this failure without the parent process hanging
  574. // At least make sure that this process doesn't access
  575. // unexpected file descriptors
  576. fds[0] = -1;
  577. fds[1] = -1;
  578. }
  579. struct kernel_msghdr msg = {0};
  580. struct kernel_iovec iov;
  581. iov.iov_base = const_cast<void*>(crash_context);
  582. iov.iov_len = crash_context_size;
  583. msg.msg_iov = &iov;
  584. msg.msg_iovlen = 1;
  585. char cmsg[kControlMsgSize];
  586. memset(cmsg, 0, kControlMsgSize);
  587. msg.msg_control = cmsg;
  588. msg.msg_controllen = sizeof(cmsg);
  589. struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
  590. hdr->cmsg_level = SOL_SOCKET;
  591. hdr->cmsg_type = SCM_RIGHTS;
  592. hdr->cmsg_len = CMSG_LEN(sizeof(int));
  593. *((int*) CMSG_DATA(hdr)) = fds[1];
  594. hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr);
  595. hdr->cmsg_level = SOL_SOCKET;
  596. hdr->cmsg_type = SCM_CREDENTIALS;
  597. hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
  598. struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
  599. cred->uid = getuid();
  600. cred->gid = getgid();
  601. cred->pid = getpid();
  602. HANDLE_EINTR(sys_sendmsg(fd, &msg, 0));
  603. sys_close(fds[1]);
  604. char b;
  605. HANDLE_EINTR(sys_read(fds[0], &b, 1));
  606. return true;
  607. }
  608. TEST(ExceptionHandlerTest, ExternalDumper) {
  609. int fds[2];
  610. ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
  611. static const int on = 1;
  612. setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
  613. setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
  614. const pid_t child = fork();
  615. if (child == 0) {
  616. close(fds[0]);
  617. ExceptionHandler handler("/tmp1", NULL, NULL, (void*) fds[1], true);
  618. handler.set_crash_handler(CrashHandler);
  619. *reinterpret_cast<volatile int*>(NULL) = 0;
  620. }
  621. close(fds[1]);
  622. struct msghdr msg = {0};
  623. struct iovec iov;
  624. static const unsigned kCrashContextSize =
  625. sizeof(ExceptionHandler::CrashContext);
  626. char context[kCrashContextSize];
  627. char control[kControlMsgSize];
  628. iov.iov_base = context;
  629. iov.iov_len = kCrashContextSize;
  630. msg.msg_iov = &iov;
  631. msg.msg_iovlen = 1;
  632. msg.msg_control = control;
  633. msg.msg_controllen = kControlMsgSize;
  634. const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
  635. ASSERT_EQ(n, kCrashContextSize);
  636. ASSERT_EQ(msg.msg_controllen, kControlMsgSize);
  637. ASSERT_EQ(msg.msg_flags, 0);
  638. ASSERT_EQ(close(fds[0]), 0);
  639. pid_t crashing_pid = -1;
  640. int signal_fd = -1;
  641. for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
  642. hdr = CMSG_NXTHDR(&msg, hdr)) {
  643. if (hdr->cmsg_level != SOL_SOCKET)
  644. continue;
  645. if (hdr->cmsg_type == SCM_RIGHTS) {
  646. const unsigned len = hdr->cmsg_len -
  647. (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
  648. ASSERT_EQ(len, sizeof(int));
  649. signal_fd = *((int *) CMSG_DATA(hdr));
  650. } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
  651. const struct ucred *cred =
  652. reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
  653. crashing_pid = cred->pid;
  654. }
  655. }
  656. ASSERT_NE(crashing_pid, -1);
  657. ASSERT_NE(signal_fd, -1);
  658. AutoTempDir temp_dir;
  659. std::string templ = temp_dir.path() + "/exception-handler-unittest";
  660. ASSERT_TRUE(WriteMinidump(templ.c_str(), crashing_pid, context,
  661. kCrashContextSize));
  662. static const char b = 0;
  663. HANDLE_EINTR(write(signal_fd, &b, 1));
  664. ASSERT_EQ(close(signal_fd), 0);
  665. int status;
  666. ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
  667. ASSERT_TRUE(WIFSIGNALED(status));
  668. ASSERT_EQ(WTERMSIG(status), SIGSEGV);
  669. struct stat st;
  670. ASSERT_EQ(stat(templ.c_str(), &st), 0);
  671. ASSERT_GT(st.st_size, 0u);
  672. unlink(templ.c_str());
  673. }