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