diff options
Diffstat (limited to 'src/client')
-rw-r--r-- | src/client/linux/microdump_writer/microdump_writer.cc | 30 | ||||
-rw-r--r-- | src/client/linux/microdump_writer/microdump_writer_unittest.cc | 130 |
2 files changed, 150 insertions, 10 deletions
diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc index 494e2a20..195255f7 100644 --- a/src/client/linux/microdump_writer/microdump_writer.cc +++ b/src/client/linux/microdump_writer/microdump_writer.cc @@ -38,9 +38,10 @@ #include "client/linux/dump_writer_common/thread_info.h" #include "client/linux/dump_writer_common/ucontext_reader.h" #include "client/linux/handler/exception_handler.h" +#include "client/linux/log/log.h" #include "client/linux/minidump_writer/linux_ptrace_dumper.h" #include "common/linux/linux_libc_support.h" -#include "client/linux/log/log.h" +#include "common/scoped_ptr.h" namespace { @@ -50,10 +51,13 @@ using google_breakpad::LinuxPtraceDumper; using google_breakpad::MappingInfo; using google_breakpad::MappingList; using google_breakpad::RawContextCPU; +using google_breakpad::scoped_array; using google_breakpad::SeccompUnwinder; using google_breakpad::ThreadInfo; using google_breakpad::UContextReader; +const size_t kLineBufferSize = 2048; + class MicrodumpWriter { public: MicrodumpWriter(const ExceptionHandler::CrashContext* context, @@ -64,7 +68,10 @@ class MicrodumpWriter { float_state_(context ? &context->float_state : NULL), #endif dumper_(dumper), - mapping_list_(mappings) { } + mapping_list_(mappings), + log_line_(new char[kLineBufferSize]) { + log_line_.get()[0] = '\0'; // Clear out the log line buffer. + } ~MicrodumpWriter() { dumper_->ThreadsResume(); } @@ -91,11 +98,14 @@ class MicrodumpWriter { // Writes one line to the system log. void LogLine(const char* msg) { logger::write(msg, my_strlen(msg)); +#if !defined(__ANDROID__) + logger::write("\n", 1); // Android logger appends the \n. Linux's doesn't. +#endif } // Stages the given string in the current line buffer. void LogAppend(const char* str) { - my_strlcat(log_line_, str, sizeof(log_line_)); + my_strlcat(log_line_.get(), str, kLineBufferSize); } // As above (required to take precedence over template specialization below). @@ -125,8 +135,8 @@ class MicrodumpWriter { // Writes out the current line buffer on the system log. void LogCommitLine() { - logger::write(log_line_, my_strlen(log_line_)); - my_strlcpy(log_line_, "", sizeof(log_line_)); + LogLine(log_line_.get()); + my_strlcpy(log_line_.get(), "", kLineBufferSize); } bool DumpOSInformation() { @@ -139,7 +149,6 @@ class MicrodumpWriter { #else const char kOSId[] = "L"; #endif - LogAppend("O "); LogAppend(kOSId); LogAppend(" \""); @@ -162,8 +171,9 @@ class MicrodumpWriter { size_t stack_len; if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { - assert(false); - return false; + // The stack pointer might not be available. In this case we don't hard + // fail, just produce a (almost useless) microdump w/o a stack section. + return true; } LogAppend("S 0 "); @@ -296,7 +306,7 @@ class MicrodumpWriter { LogAppend(module_identifier.data4[5]); LogAppend(module_identifier.data4[6]); LogAppend(module_identifier.data4[7]); - LogAppend(" "); + LogAppend("0 "); // Age is always 0 on Linux. LogAppend(file_name); LogCommitLine(); } @@ -334,7 +344,7 @@ class MicrodumpWriter { #endif LinuxDumper* dumper_; const MappingList& mapping_list_; - char log_line_[512]; + scoped_array<char> log_line_; }; } // namespace diff --git a/src/client/linux/microdump_writer/microdump_writer_unittest.cc b/src/client/linux/microdump_writer/microdump_writer_unittest.cc new file mode 100644 index 00000000..27b23a7d --- /dev/null +++ b/src/client/linux/microdump_writer/microdump_writer_unittest.cc @@ -0,0 +1,130 @@ +// 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; + +// Length of a formatted GUID string = +// sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator) +const int kGUIDStringSize = 37; + +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-----")); + ASSERT_NE(static_cast<char*>(0), strstr( + buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " + "33221100554477668899AABBCCDDEEFF0 libfoo.so")); + + close(err_fd); + close(fds[1]); +} + +} // namespace |