// Copyright (c) 2014 Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> #include <string> #include "breakpad_googletest_includes.h" #include "client/linux/handler/exception_handler.h" #include "client/linux/microdump_writer/microdump_writer.h" #include "common/linux/eintr_wrapper.h" #include "common/linux/ignore_ret.h" #include "common/scoped_ptr.h" #include "common/tests/auto_tempdir.h" #include "common/using_std_string.h" using namespace google_breakpad; namespace { typedef testing::Test MicrodumpWriterTest; TEST(MicrodumpWriterTest, Setup) { int fds[2]; ASSERT_NE(-1, pipe(fds)); AutoTempDir temp_dir; string stderr_file = temp_dir.path() + "/stderr.log"; int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); ASSERT_NE(-1, err_fd); const pid_t child = fork(); if (child == 0) { close(fds[1]); char b; IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); close(fds[0]); syscall(__NR_exit); } close(fds[0]); ExceptionHandler::CrashContext context; memset(&context, 0, sizeof(context)); // Set a non-zero tid to avoid tripping asserts. context.tid = child; // Push some extra mapping to check the MappingList logic. const uint32_t memory_size = sysconf(_SC_PAGESIZE); const char* kMemoryName = "libfoo.so"; const uint8_t kModuleGUID[sizeof(MDGUID)] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; MappingInfo info; info.start_addr = memory_size; info.size = memory_size; info.offset = 42; strcpy(info.name, kMemoryName); MappingList mappings; MappingEntry mapping; mapping.first = info; memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); mappings.push_back(mapping); // Redirect temporarily stderr to the stderr.log file. int save_err = dup(STDERR_FILENO); ASSERT_NE(-1, save_err); ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings)); // Revert stderr back to the console. dup2(save_err, STDERR_FILENO); close(save_err); // Read back the stderr file and check for the microdump marker. fsync(err_fd); lseek(err_fd, 0, SEEK_SET); const size_t kBufSize = 64 * 1024; scoped_array<char> buf(new char[kBufSize]); ASSERT_GT(read(err_fd, buf.get(), kBufSize), 0); ASSERT_NE(static_cast<char*>(0), strstr( buf.get(), "-----BEGIN BREAKPAD MICRODUMP-----")); ASSERT_NE(static_cast<char*>(0), strstr( buf.get(), "-----END BREAKPAD MICRODUMP-----")); #ifdef __LP64__ ASSERT_NE(static_cast<char*>(0), strstr( buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " "33221100554477668899AABBCCDDEEFF0 libfoo.so")); #else ASSERT_NE(static_cast<char*>(0), strstr( buf.get(), "M 00001000 0000002A 00001000 " "33221100554477668899AABBCCDDEEFF0 libfoo.so")); #endif close(err_fd); close(fds[1]); } } // namespace