michael@0: // Copyright (c) 2006, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // minidump_dump.cc: Print the contents of a minidump file in somewhat michael@0: // readable text. michael@0: // michael@0: // Author: Mark Mentovai michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "common/scoped_ptr.h" michael@0: #include "google_breakpad/processor/minidump.h" michael@0: #include "processor/logging.h" michael@0: michael@0: namespace { michael@0: michael@0: using google_breakpad::Minidump; michael@0: using google_breakpad::MinidumpThreadList; michael@0: using google_breakpad::MinidumpModuleList; michael@0: using google_breakpad::MinidumpMemoryInfoList; michael@0: using google_breakpad::MinidumpMemoryList; michael@0: using google_breakpad::MinidumpException; michael@0: using google_breakpad::MinidumpAssertion; michael@0: using google_breakpad::MinidumpSystemInfo; michael@0: using google_breakpad::MinidumpMiscInfo; michael@0: using google_breakpad::MinidumpBreakpadInfo; michael@0: michael@0: static void DumpRawStream(Minidump *minidump, michael@0: uint32_t stream_type, michael@0: const char *stream_name, michael@0: int *errors) { michael@0: uint32_t length = 0; michael@0: if (!minidump->SeekToStreamType(stream_type, &length)) { michael@0: return; michael@0: } michael@0: michael@0: printf("Stream %s:\n", stream_name); michael@0: michael@0: if (length == 0) { michael@0: printf("\n"); michael@0: return; michael@0: } michael@0: std::vector contents(length); michael@0: if (!minidump->ReadBytes(&contents[0], length)) { michael@0: ++*errors; michael@0: BPLOG(ERROR) << "minidump.ReadBytes failed"; michael@0: return; michael@0: } michael@0: size_t current_offset = 0; michael@0: while (current_offset < length) { michael@0: size_t remaining = length - current_offset; michael@0: // Printf requires an int and direct casting from size_t results michael@0: // in compatibility warnings. michael@0: uint32_t int_remaining = remaining; michael@0: printf("%.*s", int_remaining, &contents[current_offset]); michael@0: char *next_null = reinterpret_cast( michael@0: memchr(&contents[current_offset], 0, remaining)); michael@0: if (next_null == NULL) michael@0: break; michael@0: printf("\\0\n"); michael@0: size_t null_offset = next_null - &contents[0]; michael@0: current_offset = null_offset + 1; michael@0: } michael@0: printf("\n\n"); michael@0: } michael@0: michael@0: static bool PrintMinidumpDump(const char *minidump_file) { michael@0: Minidump minidump(minidump_file); michael@0: if (!minidump.Read()) { michael@0: BPLOG(ERROR) << "minidump.Read() failed"; michael@0: return false; michael@0: } michael@0: minidump.Print(); michael@0: michael@0: int errors = 0; michael@0: michael@0: MinidumpThreadList *thread_list = minidump.GetThreadList(); michael@0: if (!thread_list) { michael@0: ++errors; michael@0: BPLOG(ERROR) << "minidump.GetThreadList() failed"; michael@0: } else { michael@0: thread_list->Print(); michael@0: } michael@0: michael@0: MinidumpModuleList *module_list = minidump.GetModuleList(); michael@0: if (!module_list) { michael@0: ++errors; michael@0: BPLOG(ERROR) << "minidump.GetModuleList() failed"; michael@0: } else { michael@0: module_list->Print(); michael@0: } michael@0: michael@0: MinidumpMemoryList *memory_list = minidump.GetMemoryList(); michael@0: if (!memory_list) { michael@0: ++errors; michael@0: BPLOG(ERROR) << "minidump.GetMemoryList() failed"; michael@0: } else { michael@0: memory_list->Print(); michael@0: } michael@0: michael@0: MinidumpException *exception = minidump.GetException(); michael@0: if (!exception) { michael@0: BPLOG(INFO) << "minidump.GetException() failed"; michael@0: } else { michael@0: exception->Print(); michael@0: } michael@0: michael@0: MinidumpAssertion *assertion = minidump.GetAssertion(); michael@0: if (!assertion) { michael@0: BPLOG(INFO) << "minidump.GetAssertion() failed"; michael@0: } else { michael@0: assertion->Print(); michael@0: } michael@0: michael@0: MinidumpSystemInfo *system_info = minidump.GetSystemInfo(); michael@0: if (!system_info) { michael@0: ++errors; michael@0: BPLOG(ERROR) << "minidump.GetSystemInfo() failed"; michael@0: } else { michael@0: system_info->Print(); michael@0: } michael@0: michael@0: MinidumpMiscInfo *misc_info = minidump.GetMiscInfo(); michael@0: if (!misc_info) { michael@0: ++errors; michael@0: BPLOG(ERROR) << "minidump.GetMiscInfo() failed"; michael@0: } else { michael@0: misc_info->Print(); michael@0: } michael@0: michael@0: MinidumpBreakpadInfo *breakpad_info = minidump.GetBreakpadInfo(); michael@0: if (!breakpad_info) { michael@0: // Breakpad info is optional, so don't treat this as an error. michael@0: BPLOG(INFO) << "minidump.GetBreakpadInfo() failed"; michael@0: } else { michael@0: breakpad_info->Print(); michael@0: } michael@0: michael@0: MinidumpMemoryInfoList *memory_info_list = minidump.GetMemoryInfoList(); michael@0: if (!memory_info_list) { michael@0: ++errors; michael@0: BPLOG(ERROR) << "minidump.GetMemoryInfoList() failed"; michael@0: } else { michael@0: memory_info_list->Print(); michael@0: } michael@0: michael@0: DumpRawStream(&minidump, michael@0: MD_LINUX_CMD_LINE, michael@0: "MD_LINUX_CMD_LINE", michael@0: &errors); michael@0: DumpRawStream(&minidump, michael@0: MD_LINUX_ENVIRON, michael@0: "MD_LINUX_ENVIRON", michael@0: &errors); michael@0: DumpRawStream(&minidump, michael@0: MD_LINUX_LSB_RELEASE, michael@0: "MD_LINUX_LSB_RELEASE", michael@0: &errors); michael@0: DumpRawStream(&minidump, michael@0: MD_LINUX_PROC_STATUS, michael@0: "MD_LINUX_PROC_STATUS", michael@0: &errors); michael@0: DumpRawStream(&minidump, michael@0: MD_LINUX_CPU_INFO, michael@0: "MD_LINUX_CPU_INFO", michael@0: &errors); michael@0: DumpRawStream(&minidump, michael@0: MD_LINUX_MAPS, michael@0: "MD_LINUX_MAPS", michael@0: &errors); michael@0: michael@0: return errors == 0; michael@0: } michael@0: michael@0: } // namespace michael@0: michael@0: int main(int argc, char **argv) { michael@0: BPLOG_INIT(&argc, &argv); michael@0: michael@0: if (argc != 2) { michael@0: fprintf(stderr, "usage: %s \n", argv[0]); michael@0: return 1; michael@0: } michael@0: michael@0: return PrintMinidumpDump(argv[1]) ? 0 : 1; michael@0: }