• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 <fcntl.h>
31 #include <poll.h>
32 #include <sys/stat.h>
33 #include <sys/syscall.h>
34 #include <sys/types.h>
35 #include <ucontext.h>
36 #include <unistd.h>
37 
38 #include <string>
39 
40 #include "breakpad_googletest_includes.h"
41 #include "client/linux/handler/exception_handler.h"
42 #include "client/linux/minidump_writer/linux_dumper.h"
43 #include "client/linux/minidump_writer/minidump_writer.h"
44 #include "client/linux/minidump_writer/minidump_writer_unittest_utils.h"
45 #include "common/linux/breakpad_getcontext.h"
46 #include "common/linux/eintr_wrapper.h"
47 #include "common/linux/file_id.h"
48 #include "common/linux/ignore_ret.h"
49 #include "common/linux/safe_readlink.h"
50 #include "common/scoped_ptr.h"
51 #include "common/tests/auto_tempdir.h"
52 #include "common/tests/file_utils.h"
53 #include "common/using_std_string.h"
54 #include "google_breakpad/processor/minidump.h"
55 
56 using namespace google_breakpad;
57 
58 namespace {
59 
60 typedef testing::Test MinidumpWriterTest;
61 
62 const char kMDWriterUnitTestFileName[] = "/minidump-writer-unittest";
63 
TEST(MinidumpWriterTest,SetupWithPath)64 TEST(MinidumpWriterTest, SetupWithPath) {
65   int fds[2];
66   ASSERT_NE(-1, pipe(fds));
67 
68   const pid_t child = fork();
69   if (child == 0) {
70     close(fds[1]);
71     char b;
72     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
73     close(fds[0]);
74     syscall(__NR_exit_group);
75   }
76   close(fds[0]);
77 
78   ExceptionHandler::CrashContext context;
79   memset(&context, 0, sizeof(context));
80 
81   AutoTempDir temp_dir;
82   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
83   // Set a non-zero tid to avoid tripping asserts.
84   context.tid = child;
85   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context)));
86   struct stat st;
87   ASSERT_EQ(0, stat(templ.c_str(), &st));
88   ASSERT_GT(st.st_size, 0);
89 
90   close(fds[1]);
91   IGNORE_EINTR(waitpid(child, nullptr, 0));
92 }
93 
TEST(MinidumpWriterTest,SetupWithFD)94 TEST(MinidumpWriterTest, SetupWithFD) {
95   int fds[2];
96   ASSERT_NE(-1, pipe(fds));
97 
98   const pid_t child = fork();
99   if (child == 0) {
100     close(fds[1]);
101     char b;
102     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
103     close(fds[0]);
104     syscall(__NR_exit_group);
105   }
106   close(fds[0]);
107 
108   ExceptionHandler::CrashContext context;
109   memset(&context, 0, sizeof(context));
110 
111   AutoTempDir temp_dir;
112   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
113   int fd = open(templ.c_str(), O_CREAT | O_WRONLY, S_IRWXU);
114   // Set a non-zero tid to avoid tripping asserts.
115   context.tid = child;
116   ASSERT_TRUE(WriteMinidump(fd, child, &context, sizeof(context)));
117   struct stat st;
118   ASSERT_EQ(0, stat(templ.c_str(), &st));
119   ASSERT_GT(st.st_size, 0);
120 
121   close(fds[1]);
122   IGNORE_EINTR(waitpid(child, nullptr, 0));
123 }
124 
125 // Test that mapping info can be specified when writing a minidump,
126 // and that it ends up in the module list of the minidump.
TEST(MinidumpWriterTest,MappingInfo)127 TEST(MinidumpWriterTest, MappingInfo) {
128   int fds[2];
129   ASSERT_NE(-1, pipe(fds));
130 
131   // These are defined here so the parent can use them to check the
132   // data from the minidump afterwards.
133   const uint32_t memory_size = sysconf(_SC_PAGESIZE);
134   const char* kMemoryName = "a fake module";
135   const uint8_t kModuleGUID[sizeof(MDGUID)] = {
136     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
137     0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
138   };
139   const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
140 
141   // Get some memory.
142   char* memory =
143     reinterpret_cast<char*>(mmap(NULL,
144                                  memory_size,
145                                  PROT_READ | PROT_WRITE,
146                                  MAP_PRIVATE | MAP_ANON,
147                                  -1,
148                                  0));
149   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
150   ASSERT_TRUE(memory);
151 
152   const pid_t child = fork();
153   if (child == 0) {
154     close(fds[1]);
155     char b;
156     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
157     close(fds[0]);
158     syscall(__NR_exit_group);
159   }
160   close(fds[0]);
161 
162   ExceptionHandler::CrashContext context;
163   memset(&context, 0, sizeof(context));
164   ASSERT_EQ(0, getcontext(&context.context));
165   context.tid = child;
166 
167   AutoTempDir temp_dir;
168   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
169 
170   // Add information about the mapped memory.
171   MappingInfo info;
172   info.start_addr = kMemoryAddress;
173   info.size = memory_size;
174   info.offset = 0;
175   info.exec = false;
176   strcpy(info.name, kMemoryName);
177 
178   MappingList mappings;
179   AppMemoryList memory_list;
180   MappingEntry mapping;
181   mapping.first = info;
182   memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
183   mappings.push_back(mapping);
184   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
185                             mappings, memory_list, false, 0, false));
186 
187   // Read the minidump. Load the module list, and ensure that
188   // the mmap'ed |memory| is listed with the given module name
189   // and debug ID.
190   Minidump minidump(templ);
191   ASSERT_TRUE(minidump.Read());
192 
193   MinidumpModuleList* module_list = minidump.GetModuleList();
194   ASSERT_TRUE(module_list);
195   const MinidumpModule* module =
196     module_list->GetModuleForAddress(kMemoryAddress);
197   ASSERT_TRUE(module);
198 
199   EXPECT_EQ(kMemoryAddress, module->base_address());
200   EXPECT_EQ(memory_size, module->size());
201   EXPECT_EQ(kMemoryName, module->code_file());
202   EXPECT_EQ(module_identifier, module->debug_identifier());
203 
204   uint32_t len;
205   // These streams are expected to be there
206   EXPECT_TRUE(minidump.SeekToStreamType(MD_THREAD_LIST_STREAM, &len));
207   EXPECT_TRUE(minidump.SeekToStreamType(MD_MEMORY_LIST_STREAM, &len));
208   EXPECT_TRUE(minidump.SeekToStreamType(MD_EXCEPTION_STREAM, &len));
209   EXPECT_TRUE(minidump.SeekToStreamType(MD_SYSTEM_INFO_STREAM, &len));
210   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CPU_INFO, &len));
211   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_PROC_STATUS, &len));
212   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CMD_LINE, &len));
213   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_ENVIRON, &len));
214   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_AUXV, &len));
215   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_MAPS, &len));
216   EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_DSO_DEBUG, &len));
217 
218   close(fds[1]);
219   IGNORE_EINTR(waitpid(child, nullptr, 0));
220 }
221 
222 // Test that minidumping is skipped while writing minidumps if principal mapping
223 // is not referenced.
TEST(MinidumpWriterTest,MinidumpSkippedIfRequested)224 TEST(MinidumpWriterTest, MinidumpSkippedIfRequested) {
225   int fds[2];
226   ASSERT_NE(-1, pipe(fds));
227 
228   const pid_t child = fork();
229   if (child == 0) {
230     close(fds[1]);
231     char b;
232     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
233     close(fds[0]);
234     syscall(__NR_exit_group);
235   }
236   close(fds[0]);
237 
238   ExceptionHandler::CrashContext context;
239   memset(&context, 0, sizeof(context));
240   ASSERT_EQ(0, getcontext(&context.context));
241   context.tid = child;
242 
243   AutoTempDir temp_dir;
244   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
245 
246   // pass an invalid principal mapping address, which will force
247   // WriteMinidump to not write a minidump.
248   ASSERT_FALSE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
249                             true, static_cast<uintptr_t>(0x0102030405060708ull),
250                             false));
251   close(fds[1]);
252   IGNORE_EINTR(waitpid(child, nullptr, 0));
253 }
254 
255 // Test that minidumping is skipped while writing minidumps if principal mapping
256 // is not referenced.
TEST(MinidumpWriterTest,MinidumpStacksSkippedIfRequested)257 TEST(MinidumpWriterTest, MinidumpStacksSkippedIfRequested) {
258   int fds[2];
259   ASSERT_NE(-1, pipe(fds));
260 
261   const pid_t child = fork();
262   if (child == 0) {
263     close(fds[1]);
264 
265     // Create a thread that does not return, and only references libc (not the
266     // current executable). This thread should not be captured in the minidump.
267     pthread_t thread;
268     pthread_attr_t thread_attributes;
269     pthread_attr_init(&thread_attributes);
270     pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
271     sigset_t sigset;
272     sigemptyset(&sigset);
273     pthread_create(&thread, &thread_attributes,
274                    reinterpret_cast<void* (*)(void*)>(&sigsuspend), &sigset);
275 
276     char b;
277     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
278     close(fds[0]);
279     syscall(__NR_exit_group);
280   }
281   close(fds[0]);
282 
283   ExceptionHandler::CrashContext context;
284   memset(&context, 0, sizeof(context));
285   ASSERT_EQ(0, getcontext(&context.context));
286   context.tid = child;
287 
288   AutoTempDir temp_dir;
289   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
290 
291   // Pass an invalid principal mapping address, which will force
292   // WriteMinidump to not dump any thread stacks.
293   ASSERT_TRUE(WriteMinidump(
294       templ.c_str(), child, &context, sizeof(context), true,
295       reinterpret_cast<uintptr_t>(google_breakpad::WriteFile), false));
296 
297   // Read the minidump. And ensure that thread memory was dumped only for the
298   // main thread.
299   Minidump minidump(templ);
300   ASSERT_TRUE(minidump.Read());
301 
302   MinidumpThreadList *threads = minidump.GetThreadList();
303   int threads_with_stacks = 0;
304   for (unsigned int i = 0; i < threads->thread_count(); ++i) {
305     MinidumpThread *thread = threads->GetThreadAtIndex(i);
306     if (thread->GetMemory()) {
307       ++threads_with_stacks;
308     }
309   }
310 #if defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER)
311   ASSERT_GE(threads_with_stacks, 1);
312 #else
313   ASSERT_EQ(threads_with_stacks, 1);
314 #endif
315   close(fds[1]);
316   IGNORE_EINTR(waitpid(child, nullptr, 0));
317 }
318 
319 // Test that stacks can be sanitized while writing minidumps.
TEST(MinidumpWriterTest,StacksAreSanitizedIfRequested)320 TEST(MinidumpWriterTest, StacksAreSanitizedIfRequested) {
321   int fds[2];
322   ASSERT_NE(-1, pipe(fds));
323 
324   const pid_t child = fork();
325   if (child == 0) {
326     close(fds[1]);
327     char b;
328     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
329     close(fds[0]);
330     syscall(__NR_exit_group);
331   }
332   close(fds[0]);
333 
334   ExceptionHandler::CrashContext context;
335   memset(&context, 0, sizeof(context));
336   ASSERT_EQ(0, getcontext(&context.context));
337   context.tid = child;
338 
339   AutoTempDir temp_dir;
340   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
341   // pass an invalid principal mapping address, which will force
342   // WriteMinidump to not dump any thread stacks.
343   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
344                             false, 0, true));
345 
346   // Read the minidump. And ensure that thread memory contains a defaced value.
347   Minidump minidump(templ);
348   ASSERT_TRUE(minidump.Read());
349 
350   const uintptr_t defaced =
351 #if defined(__LP64__)
352       0x0defaced0defaced;
353 #else
354       0x0defaced;
355 #endif
356   MinidumpThreadList *threads = minidump.GetThreadList();
357   for (unsigned int i = 0; i < threads->thread_count(); ++i) {
358     MinidumpThread *thread = threads->GetThreadAtIndex(i);
359     MinidumpMemoryRegion *mem = thread->GetMemory();
360     ASSERT_TRUE(mem != nullptr);
361     uint32_t sz = mem->GetSize();
362     const uint8_t *data = mem->GetMemory();
363     ASSERT_TRUE(memmem(data, sz, &defaced, sizeof(defaced)) != nullptr);
364   }
365   close(fds[1]);
366   IGNORE_EINTR(waitpid(child, nullptr, 0));
367 }
368 
369 // Test that a binary with a longer-than-usual build id note
370 // makes its way all the way through to the minidump unscathed.
371 // The linux_client_unittest is linked with an explicit --build-id
372 // in Makefile.am.
TEST(MinidumpWriterTest,BuildIDLong)373 TEST(MinidumpWriterTest, BuildIDLong) {
374   int fds[2];
375   ASSERT_NE(-1, pipe(fds));
376 
377   const pid_t child = fork();
378   if (child == 0) {
379     close(fds[1]);
380     char b;
381     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
382     close(fds[0]);
383     syscall(__NR_exit_group);
384   }
385   close(fds[0]);
386 
387   ExceptionHandler::CrashContext context;
388   memset(&context, 0, sizeof(context));
389   ASSERT_EQ(0, getcontext(&context.context));
390   context.tid = child;
391 
392   AutoTempDir temp_dir;
393   const string dump_path = temp_dir.path() + kMDWriterUnitTestFileName;
394 
395   EXPECT_TRUE(WriteMinidump(dump_path.c_str(),
396                             child, &context, sizeof(context)));
397   close(fds[1]);
398 
399   // Read the minidump. Load the module list, and ensure that
400   // the main module has the correct debug id and code id.
401   Minidump minidump(dump_path);
402   ASSERT_TRUE(minidump.Read());
403 
404   MinidumpModuleList* module_list = minidump.GetModuleList();
405   ASSERT_TRUE(module_list);
406   const MinidumpModule* module = module_list->GetMainModule();
407   ASSERT_TRUE(module);
408   const string module_identifier = "030201000504070608090A0B0C0D0E0F0";
409   // This is passed explicitly to the linker in Makefile.am
410   const string build_id =
411       "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
412   EXPECT_EQ(module_identifier, module->debug_identifier());
413   EXPECT_EQ(build_id, module->code_identifier());
414 
415   IGNORE_EINTR(waitpid(child, nullptr, 0));
416 }
417 
418 // Test that mapping info can be specified, and that it overrides
419 // existing mappings that are wholly contained within the specified
420 // range.
TEST(MinidumpWriterTest,MappingInfoContained)421 TEST(MinidumpWriterTest, MappingInfoContained) {
422   int fds[2];
423   ASSERT_NE(-1, pipe(fds));
424 
425   // These are defined here so the parent can use them to check the
426   // data from the minidump afterwards.
427   const int32_t memory_size = sysconf(_SC_PAGESIZE);
428   const char* kMemoryName = "a fake module";
429   const uint8_t kModuleGUID[sizeof(MDGUID)] = {
430     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
431     0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
432   };
433   const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
434 
435   // mmap a file
436   AutoTempDir temp_dir;
437   string tempfile = temp_dir.path() + "/minidump-writer-unittest-temp";
438   int fd = open(tempfile.c_str(), O_RDWR | O_CREAT, 0);
439   ASSERT_NE(-1, fd);
440   unlink(tempfile.c_str());
441   // fill with zeros
442   google_breakpad::scoped_array<char> buffer(new char[memory_size]);
443   memset(buffer.get(), 0, memory_size);
444   ASSERT_EQ(memory_size, write(fd, buffer.get(), memory_size));
445   lseek(fd, 0, SEEK_SET);
446 
447   char* memory =
448     reinterpret_cast<char*>(mmap(NULL,
449                                  memory_size,
450                                  PROT_READ | PROT_WRITE,
451                                  MAP_PRIVATE,
452                                  fd,
453                                  0));
454   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
455   ASSERT_TRUE(memory);
456   close(fd);
457 
458   const pid_t child = fork();
459   if (child == 0) {
460     close(fds[1]);
461     char b;
462     IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
463     close(fds[0]);
464     syscall(__NR_exit_group);
465   }
466   close(fds[0]);
467 
468   ExceptionHandler::CrashContext context;
469   memset(&context, 0, sizeof(context));
470   context.tid = 1;
471 
472   string dumpfile = temp_dir.path() + kMDWriterUnitTestFileName;
473 
474   // Add information about the mapped memory. Report it as being larger than
475   // it actually is.
476   MappingInfo info;
477   info.start_addr = kMemoryAddress - memory_size;
478   info.size = memory_size * 3;
479   info.offset = 0;
480   info.exec = false;
481   strcpy(info.name, kMemoryName);
482 
483   MappingList mappings;
484   AppMemoryList memory_list;
485   MappingEntry mapping;
486   mapping.first = info;
487   memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
488   mappings.push_back(mapping);
489   ASSERT_TRUE(WriteMinidump(dumpfile.c_str(), child, &context, sizeof(context),
490                             mappings, memory_list));
491 
492   // Read the minidump. Load the module list, and ensure that
493   // the mmap'ed |memory| is listed with the given module name
494   // and debug ID.
495   Minidump minidump(dumpfile);
496   ASSERT_TRUE(minidump.Read());
497 
498   MinidumpModuleList* module_list = minidump.GetModuleList();
499   ASSERT_TRUE(module_list);
500   const MinidumpModule* module =
501     module_list->GetModuleForAddress(kMemoryAddress);
502   ASSERT_TRUE(module);
503 
504   EXPECT_EQ(info.start_addr, module->base_address());
505   EXPECT_EQ(info.size, module->size());
506   EXPECT_EQ(kMemoryName, module->code_file());
507   EXPECT_EQ(module_identifier, module->debug_identifier());
508 
509   close(fds[1]);
510   IGNORE_EINTR(waitpid(child, nullptr, 0));
511 }
512 
TEST(MinidumpWriterTest,DeletedBinary)513 TEST(MinidumpWriterTest, DeletedBinary) {
514   const string kNumberOfThreadsArgument = "1";
515   const string helper_path(GetHelperBinary());
516   if (helper_path.empty()) {
517     FAIL() << "Couldn't find helper binary";
518     exit(1);
519   }
520 
521   // Copy binary to a temp file.
522   AutoTempDir temp_dir;
523   string binpath = temp_dir.path() + "/linux-dumper-unittest-helper";
524   ASSERT_TRUE(CopyFile(helper_path.c_str(), binpath.c_str()))
525       << "Failed to copy " << helper_path << " to " << binpath;
526   ASSERT_EQ(0, chmod(binpath.c_str(), 0755));
527 
528   int fds[2];
529   ASSERT_NE(-1, pipe(fds));
530 
531   pid_t child_pid = fork();
532   if (child_pid == 0) {
533     // In child process.
534     close(fds[0]);
535 
536     // Pass the pipe fd and the number of threads as arguments.
537     char pipe_fd_string[8];
538     sprintf(pipe_fd_string, "%d", fds[1]);
539     execl(binpath.c_str(),
540           binpath.c_str(),
541           pipe_fd_string,
542           kNumberOfThreadsArgument.c_str(),
543           NULL);
544   }
545   close(fds[1]);
546   // Wait for the child process to signal that it's ready.
547   struct pollfd pfd;
548   memset(&pfd, 0, sizeof(pfd));
549   pfd.fd = fds[0];
550   pfd.events = POLLIN | POLLERR;
551 
552   const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
553   ASSERT_EQ(1, r);
554   ASSERT_TRUE(pfd.revents & POLLIN);
555   uint8_t junk;
556   const int nr = HANDLE_EINTR(read(fds[0], &junk, sizeof(junk)));
557   ASSERT_EQ(static_cast<ssize_t>(sizeof(junk)), nr);
558   close(fds[0]);
559 
560   // Child is ready now.
561   // Unlink the test binary.
562   unlink(binpath.c_str());
563 
564   ExceptionHandler::CrashContext context;
565   memset(&context, 0, sizeof(context));
566 
567   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
568   // Set a non-zero tid to avoid tripping asserts.
569   context.tid = child_pid;
570   ASSERT_TRUE(WriteMinidump(templ.c_str(), child_pid, &context,
571                             sizeof(context)));
572   kill(child_pid, SIGKILL);
573 
574   struct stat st;
575   ASSERT_EQ(0, stat(templ.c_str(), &st));
576   ASSERT_GT(st.st_size, 0);
577 
578   Minidump minidump(templ);
579   ASSERT_TRUE(minidump.Read());
580 
581   // Check that the main module filename is correct.
582   MinidumpModuleList* module_list = minidump.GetModuleList();
583   ASSERT_TRUE(module_list);
584   const MinidumpModule* module = module_list->GetMainModule();
585   EXPECT_STREQ(binpath.c_str(), module->code_file().c_str());
586   // Check that the file ID is correct.
587   FileID fileid(helper_path.c_str());
588   PageAllocator allocator;
589   wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
590   EXPECT_TRUE(fileid.ElfFileIdentifier(identifier));
591   string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
592   string module_identifier(identifier_string);
593   // Strip out dashes
594   size_t pos;
595   while ((pos = module_identifier.find('-')) != string::npos) {
596     module_identifier.erase(pos, 1);
597   }
598   // And append a zero, because module IDs include an "age" field
599   // which is always zero on Linux.
600   module_identifier += "0";
601   EXPECT_EQ(module_identifier, module->debug_identifier());
602 
603   IGNORE_EINTR(waitpid(child_pid, nullptr, 0));
604 }
605 
606 // Test that an additional memory region can be added to the minidump.
TEST(MinidumpWriterTest,AdditionalMemory)607 TEST(MinidumpWriterTest, AdditionalMemory) {
608   int fds[2];
609   ASSERT_NE(-1, pipe(fds));
610 
611   // These are defined here so the parent can use them to check the
612   // data from the minidump afterwards.
613   const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
614 
615   // Get some heap memory.
616   uint8_t* memory = new uint8_t[kMemorySize];
617   const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
618   ASSERT_TRUE(memory);
619 
620   // Stick some data into the memory so the contents can be verified.
621   for (uint32_t i = 0; i < kMemorySize; ++i) {
622     memory[i] = i % 255;
623   }
624 
625   const pid_t child = fork();
626   if (child == 0) {
627     close(fds[1]);
628     char b;
629     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
630     close(fds[0]);
631     syscall(__NR_exit_group);
632   }
633   close(fds[0]);
634 
635   ExceptionHandler::CrashContext context;
636 
637   // This needs a valid context for minidump writing to work, but getting
638   // a useful one from the child is too much work, so just use one from
639   // the parent since the child is just a forked copy anyway.
640   ASSERT_EQ(0, getcontext(&context.context));
641   context.tid = child;
642 
643   AutoTempDir temp_dir;
644   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
645   unlink(templ.c_str());
646 
647   MappingList mappings;
648   AppMemoryList memory_list;
649 
650   // Add the memory region to the list of memory to be included.
651   AppMemory app_memory;
652   app_memory.ptr = memory;
653   app_memory.length = kMemorySize;
654   memory_list.push_back(app_memory);
655   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
656                             mappings, memory_list));
657 
658   // Read the minidump. Ensure that the memory region is present
659   Minidump minidump(templ);
660   ASSERT_TRUE(minidump.Read());
661 
662   MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
663   ASSERT_TRUE(dump_memory_list);
664   const MinidumpMemoryRegion* region =
665     dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
666   ASSERT_TRUE(region);
667 
668   EXPECT_EQ(kMemoryAddress, region->GetBase());
669   EXPECT_EQ(kMemorySize, region->GetSize());
670 
671   // Verify memory contents.
672   EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize));
673 
674   delete[] memory;
675   close(fds[1]);
676   IGNORE_EINTR(waitpid(child, nullptr, 0));
677 }
678 
679 // Test that an invalid thread stack pointer still results in a minidump.
TEST(MinidumpWriterTest,InvalidStackPointer)680 TEST(MinidumpWriterTest, InvalidStackPointer) {
681   int fds[2];
682   ASSERT_NE(-1, pipe(fds));
683 
684   const pid_t child = fork();
685   if (child == 0) {
686     close(fds[1]);
687     char b;
688     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
689     close(fds[0]);
690     syscall(__NR_exit_group);
691   }
692   close(fds[0]);
693 
694   ExceptionHandler::CrashContext context;
695 
696   // This needs a valid context for minidump writing to work, but getting
697   // a useful one from the child is too much work, so just use one from
698   // the parent since the child is just a forked copy anyway.
699   ASSERT_EQ(0, getcontext(&context.context));
700   context.tid = child;
701 
702   // Fake the child's stack pointer for its crashing thread.  NOTE: This must
703   // be an invalid memory address for the child process (stack or otherwise).
704   // Try 1MB below the current stack.
705   uintptr_t invalid_stack_pointer =
706       reinterpret_cast<uintptr_t>(&context) - 1024*1024;
707 #if defined(__i386)
708   context.context.uc_mcontext.gregs[REG_ESP] = invalid_stack_pointer;
709 #elif defined(__x86_64)
710   context.context.uc_mcontext.gregs[REG_RSP] = invalid_stack_pointer;
711 #elif defined(__ARM_EABI__)
712   context.context.uc_mcontext.arm_sp = invalid_stack_pointer;
713 #elif defined(__aarch64__)
714   context.context.uc_mcontext.sp = invalid_stack_pointer;
715 #elif defined(__mips__)
716   context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] =
717       invalid_stack_pointer;
718 #else
719 # error "This code has not been ported to your platform yet."
720 #endif
721 
722   AutoTempDir temp_dir;
723   string templ = temp_dir.path() + kMDWriterUnitTestFileName;
724   // NOTE: In previous versions of Breakpad, WriteMinidump() would fail if
725   // presented with an invalid stack pointer.
726   ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context)));
727 
728   // Read the minidump. Ensure that the memory region is present
729   Minidump minidump(templ);
730   ASSERT_TRUE(minidump.Read());
731 
732   // TODO(ted.mielczarek,mkrebs): Enable this part of the test once
733   // https://breakpad.appspot.com/413002/ is committed.
734 #if 0
735   // Make sure there's a thread without a stack.  NOTE: It's okay if
736   // GetThreadList() shows the error: "ERROR: MinidumpThread has a memory
737   // region problem".
738   MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
739   ASSERT_TRUE(dump_thread_list);
740   bool found_empty_stack = false;
741   for (int i = 0; i < dump_thread_list->thread_count(); i++) {
742     MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
743     ASSERT_TRUE(thread->thread() != NULL);
744     // When the stack size is zero bytes, GetMemory() returns NULL.
745     if (thread->GetMemory() == NULL) {
746       found_empty_stack = true;
747       break;
748     }
749   }
750   // NOTE: If you fail this, first make sure that "invalid_stack_pointer"
751   // above is indeed set to an invalid address.
752   ASSERT_TRUE(found_empty_stack);
753 #endif
754 
755   close(fds[1]);
756   IGNORE_EINTR(waitpid(child, nullptr, 0));
757 }
758 
759 // Test that limiting the size of the minidump works.
TEST(MinidumpWriterTest,MinidumpSizeLimit)760 TEST(MinidumpWriterTest, MinidumpSizeLimit) {
761   static const int kNumberOfThreadsInHelperProgram = 40;
762 
763   char number_of_threads_arg[3];
764   sprintf(number_of_threads_arg, "%d", kNumberOfThreadsInHelperProgram);
765 
766   string helper_path(GetHelperBinary());
767   if (helper_path.empty()) {
768     FAIL() << "Couldn't find helper binary";
769     exit(1);
770   }
771 
772   int fds[2];
773   ASSERT_NE(-1, pipe(fds));
774 
775   pid_t child_pid = fork();
776   if (child_pid == 0) {
777     // In child process.
778     close(fds[0]);
779 
780     // Pass the pipe fd and the number of threads as arguments.
781     char pipe_fd_string[8];
782     sprintf(pipe_fd_string, "%d", fds[1]);
783     execl(helper_path.c_str(),
784           helper_path.c_str(),
785           pipe_fd_string,
786           number_of_threads_arg,
787           NULL);
788   }
789   close(fds[1]);
790 
791   // Wait for all child threads to indicate that they have started
792   for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) {
793     struct pollfd pfd;
794     memset(&pfd, 0, sizeof(pfd));
795     pfd.fd = fds[0];
796     pfd.events = POLLIN | POLLERR;
797 
798     const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
799     ASSERT_EQ(1, r);
800     ASSERT_TRUE(pfd.revents & POLLIN);
801     uint8_t junk;
802     ASSERT_EQ(read(fds[0], &junk, sizeof(junk)),
803               static_cast<ssize_t>(sizeof(junk)));
804   }
805   close(fds[0]);
806 
807   // There is a race here because we may stop a child thread before
808   // it is actually running the busy loop. Empirically this sleep
809   // is sufficient to avoid the race.
810   usleep(100000);
811 
812   // Child and its threads are ready now.
813 
814 
815   off_t normal_file_size;
816   int total_normal_stack_size = 0;
817   AutoTempDir temp_dir;
818 
819   // First, write a minidump with no size limit.
820   {
821     string normal_dump = temp_dir.path() +
822         "/minidump-writer-unittest.dmp";
823     ASSERT_TRUE(WriteMinidump(normal_dump.c_str(), -1,
824                               child_pid, NULL, 0,
825                               MappingList(), AppMemoryList()));
826     struct stat st;
827     ASSERT_EQ(0, stat(normal_dump.c_str(), &st));
828     ASSERT_GT(st.st_size, 0);
829     normal_file_size = st.st_size;
830 
831     Minidump minidump(normal_dump);
832     ASSERT_TRUE(minidump.Read());
833     MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
834     ASSERT_TRUE(dump_thread_list);
835     for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) {
836       MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
837       ASSERT_TRUE(thread->thread() != NULL);
838       // When the stack size is zero bytes, GetMemory() returns NULL.
839       MinidumpMemoryRegion* memory = thread->GetMemory();
840       ASSERT_TRUE(memory != NULL);
841       total_normal_stack_size += memory->GetSize();
842     }
843   }
844 
845   // Second, write a minidump with a size limit big enough to not trigger
846   // anything.
847   {
848     // Set size limit arbitrarily 1MB larger than the normal file size -- such
849     // that the limiting code will not kick in.
850     const off_t minidump_size_limit = normal_file_size + 1024*1024;
851 
852     string same_dump = temp_dir.path() +
853         "/minidump-writer-unittest-same.dmp";
854     ASSERT_TRUE(WriteMinidump(same_dump.c_str(), minidump_size_limit,
855                               child_pid, NULL, 0,
856                               MappingList(), AppMemoryList()));
857     struct stat st;
858     ASSERT_EQ(0, stat(same_dump.c_str(), &st));
859     // Make sure limiting wasn't actually triggered.  NOTE: If you fail this,
860     // first make sure that "minidump_size_limit" above is indeed set to a
861     // large enough value -- the limit-checking code in minidump_writer.cc
862     // does just a rough estimate.
863     ASSERT_EQ(normal_file_size, st.st_size);
864   }
865 
866   // Third, write a minidump with a size limit small enough to be triggered.
867   {
868     // Set size limit to some arbitrary amount, such that the limiting code
869     // will kick in.  The equation used to set this value was determined by
870     // simply reversing the size-limit logic a little bit in order to pick a
871     // size we know will trigger it.  The definition of
872     // kLimitAverageThreadStackLength here was copied from class
873     // MinidumpWriter in minidump_writer.cc.
874     static const unsigned kLimitAverageThreadStackLength = 8 * 1024;
875     off_t minidump_size_limit = kNumberOfThreadsInHelperProgram *
876         kLimitAverageThreadStackLength;
877     // If, in reality, each of the threads' stack is *smaller* than
878     // kLimitAverageThreadStackLength, the normal file size could very well be
879     // smaller than the arbitrary limit that was just set.  In that case,
880     // either of these numbers should trigger the size-limiting code, but we
881     // might as well pick the smallest.
882     if (normal_file_size < minidump_size_limit)
883       minidump_size_limit = normal_file_size;
884 
885     string limit_dump = temp_dir.path() +
886         "/minidump-writer-unittest-limit.dmp";
887     ASSERT_TRUE(WriteMinidump(limit_dump.c_str(), minidump_size_limit,
888                               child_pid, NULL, 0,
889                               MappingList(), AppMemoryList()));
890     struct stat st;
891     ASSERT_EQ(0, stat(limit_dump.c_str(), &st));
892     ASSERT_GT(st.st_size, 0);
893     // Make sure the file size is at least smaller than the original.  If this
894     // fails because it's the same size, then the size-limit logic didn't kick
895     // in like it was supposed to.
896     EXPECT_LT(st.st_size, normal_file_size);
897 
898     Minidump minidump(limit_dump);
899     ASSERT_TRUE(minidump.Read());
900     MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
901     ASSERT_TRUE(dump_thread_list);
902     int total_limit_stack_size = 0;
903     for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) {
904       MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
905       ASSERT_TRUE(thread->thread() != NULL);
906       // When the stack size is zero bytes, GetMemory() returns NULL.
907       MinidumpMemoryRegion* memory = thread->GetMemory();
908       ASSERT_TRUE(memory != NULL);
909       total_limit_stack_size += memory->GetSize();
910     }
911 
912     // Make sure stack size shrunk by at least 1KB per extra thread.  The
913     // definition of kLimitBaseThreadCount here was copied from class
914     // MinidumpWriter in minidump_writer.cc.
915     // Note: The 1KB is arbitrary, and assumes that the thread stacks are big
916     // enough to shrink by that much.  For example, if each thread stack was
917     // originally only 2KB, the current size-limit logic wouldn't actually
918     // shrink them because that's the size to which it tries to shrink.  If
919     // you fail this part of the test due to something like that, the test
920     // logic should probably be improved to account for your situation.
921     const unsigned kLimitBaseThreadCount = 20;
922     const unsigned kMinPerExtraThreadStackReduction = 1024;
923     const int min_expected_reduction = (kNumberOfThreadsInHelperProgram -
924         kLimitBaseThreadCount) * kMinPerExtraThreadStackReduction;
925     EXPECT_LT(total_limit_stack_size,
926               total_normal_stack_size - min_expected_reduction);
927   }
928 
929   // Kill the helper program.
930   kill(child_pid, SIGKILL);
931   IGNORE_EINTR(waitpid(child_pid, nullptr, 0));
932 }
933 
934 }  // namespace
935