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