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.
FlushInstructionCache(const char * memory,uint32_t memory_size)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
sigchld_handler(int signo)101 void sigchld_handler(int signo) { }
102
CreateTMPFile(const string & dir,string * path)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:
SetUp()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
TearDown()125 void TearDown() {
126 sigaction(SIGCHLD, &old_action, NULL);
127 }
128
129 struct sigaction old_action;
130 };
131
132
WaitForProcessToTerminate(pid_t process_id,int expected_status)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|.
ReadMinidumpPathFromPipe(int fd,string * 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
TEST(ExceptionHandlerTest,SimpleWithPath)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
TEST(ExceptionHandlerTest,SimpleWithFD)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
DoneCallback(const MinidumpDescriptor & descriptor,void * context,bool succeeded)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.
DoNullPointerDereference()210 static void DoNullPointerDereference() {
211 *p_null = 1;
212 }
213
ChildCrash(bool use_fd)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
TEST(ExceptionHandlerTest,ChildCrashWithPath)257 TEST(ExceptionHandlerTest, ChildCrashWithPath) {
258 ASSERT_NO_FATAL_FAILURE(ChildCrash(false));
259 }
260
TEST(ExceptionHandlerTest,ChildCrashWithFD)261 TEST(ExceptionHandlerTest, ChildCrashWithFD) {
262 ASSERT_NO_FATAL_FAILURE(ChildCrash(true));
263 }
264
265 #endif // !ADDRESS_SANITIZER
266
DoneCallbackReturnFalse(const MinidumpDescriptor & descriptor,void * context,bool succeeded)267 static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor,
268 void* context,
269 bool succeeded) {
270 return false;
271 }
272
DoneCallbackReturnTrue(const MinidumpDescriptor & descriptor,void * context,bool succeeded)273 static bool DoneCallbackReturnTrue(const MinidumpDescriptor& descriptor,
274 void* context,
275 bool succeeded) {
276 return true;
277 }
278
DoneCallbackRaiseSIGKILL(const MinidumpDescriptor & descriptor,void * context,bool succeeded)279 static bool DoneCallbackRaiseSIGKILL(const MinidumpDescriptor& descriptor,
280 void* context,
281 bool succeeded) {
282 raise(SIGKILL);
283 return true;
284 }
285
FilterCallbackReturnFalse(void * context)286 static bool FilterCallbackReturnFalse(void* context) {
287 return false;
288 }
289
FilterCallbackReturnTrue(void * context)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.
RaiseSIGKILL(int sig)297 static void RaiseSIGKILL(int sig) {
298 raise(SIGKILL);
299 }
300
InstallRaiseSIGKILL()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
CrashWithCallbacks(ExceptionHandler::FilterCallback filter,ExceptionHandler::MinidumpCallback done,string path)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
TEST(ExceptionHandlerTest,RedeliveryOnFilterCallbackFalse)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
TEST(ExceptionHandlerTest,RedeliveryOnDoneCallbackFalse)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
TEST(ExceptionHandlerTest,NoRedeliveryOnDoneCallbackTrue)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
TEST(ExceptionHandlerTest,NoRedeliveryOnFilterCallbackTrue)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
TEST(ExceptionHandlerTest,RedeliveryToDefaultHandler)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.
TEST(ExceptionHandlerTest,RedeliveryOnBadSignalHandlerFlag)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
TEST(ExceptionHandlerTest,StackedHandlersDeliveredToTop)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
TEST(ExceptionHandlerTest,StackedHandlersNotDeliveredToBottom)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
TEST(ExceptionHandlerTest,StackedHandlersFilteredToBottom)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
TEST(ExceptionHandlerTest,StackedHandlersUnhandledToBottom)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.
TEST(ExceptionHandlerTest,InstructionPointerMemory)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.
TEST(ExceptionHandlerTest,InstructionPointerMemoryMinBound)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.
TEST(ExceptionHandlerTest,InstructionPointerMemoryMaxBound)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.
TEST(ExceptionHandlerTest,InstructionPointerMemoryNullPointer)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.
TEST(ExceptionHandlerTest,ModuleInfo)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
CrashHandler(const void * crash_context,size_t crash_context_size,void * context)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
TEST(ExceptionHandlerTest,ExternalDumper)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
TEST(ExceptionHandlerTest,WriteMinidumpExceptionStream)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
TEST(ExceptionHandlerTest,GenerateMultipleDumpsWithFD)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
TEST(ExceptionHandlerTest,GenerateMultipleDumpsWithPath)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.
TEST(ExceptionHandlerTest,AdditionalMemory)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.
TEST(ExceptionHandlerTest,AdditionalMemoryRemove)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
SimpleCallback(const MinidumpDescriptor & descriptor,void * context,bool succeeded)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
TEST(ExceptionHandlerTest,WriteMinidumpForChild)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