cpw.caseyho.crashreporter: 22e2010a: Adding rudimentary structure required fo...
caseyho at pidgin.im
caseyho at pidgin.im
Wed Feb 11 22:45:45 EST 2009
-----------------------------------------------------------------
Revision: 22e2010ab722926fcff0c34397e7b6b9e5e8d5d2
Ancestor: d22596ca08b991a75972575ceba943ee6664fac5
Author: caseyho at pidgin.im
Date: 2009-02-12T01:23:05
Branch: im.pidgin.cpw.caseyho.crashreporter
URL: http://d.pidgin.im/viewmtn/revision/info/22e2010ab722926fcff0c34397e7b6b9e5e8d5d2
Added files:
pidgin/crash/Makefile.am pidgin/crash/crashhandler.cpp
pidgin/crash/crashhandler.h pidgin/crash/crashreporter.c
pidgin/crash/minidump_stackwalk.cc
Added directories:
pidgin/crash
Modified files:
COPYRIGHT configure.ac pidgin/Makefile.am pidgin/gtkmain.c
ChangeLog:
Adding rudimentary structure required for crash reporting. This commit is incomplete and breakpad itself is not included.
-------------- next part --------------
============================================================
--- pidgin/crash/Makefile.am cb617f30b93bf4130f88b89784e030117d8cb701
+++ pidgin/crash/Makefile.am cb617f30b93bf4130f88b89784e030117d8cb701
@@ -0,0 +1,71 @@
+if ENABLE_CRASHREPORTER
+
+bin_PROGRAMS = crashreporter
+
+crashreporter_SOURCES = \
+ crashreporter.c \
+ minidump_stackwalk.cc
+
+crashreporter_LDADD = libbreakpad.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/pidgin/crash/google-breakpad
+
+
+## Libraries
+lib_LTLIBRARIES = libbreakpad.la
+
+libbreakpad_la_SOURCES = \
+ google-breakpad/google_breakpad/common/breakpad_types.h \
+ google-breakpad/google_breakpad/common/minidump_format.h \
+ google-breakpad/google_breakpad/common/minidump_size.h \
+ google-breakpad/google_breakpad/processor/basic_source_line_resolver.h \
+ google-breakpad/google_breakpad/processor/call_stack.h \
+ google-breakpad/google_breakpad/processor/code_module.h \
+ google-breakpad/google_breakpad/processor/code_modules.h \
+ google-breakpad/google_breakpad/processor/memory_region.h \
+ google-breakpad/google_breakpad/processor/minidump.h \
+ google-breakpad/google_breakpad/processor/minidump_processor.h \
+ google-breakpad/google_breakpad/processor/process_state.h \
+ google-breakpad/google_breakpad/processor/source_line_resolver_interface.h \
+ google-breakpad/google_breakpad/processor/stack_frame.h \
+ google-breakpad/google_breakpad/processor/stack_frame_cpu.h \
+ google-breakpad/google_breakpad/processor/stackwalker.h \
+ google-breakpad/google_breakpad/processor/symbol_supplier.h \
+ google-breakpad/google_breakpad/processor/system_info.h \
+ google-breakpad/processor/address_map-inl.h \
+ google-breakpad/processor/address_map.h \
+ google-breakpad/processor/basic_code_module.h \
+ google-breakpad/processor/basic_code_modules.cc \
+ google-breakpad/processor/basic_code_modules.h \
+ google-breakpad/processor/basic_source_line_resolver.cc \
+ google-breakpad/processor/call_stack.cc \
+ google-breakpad/processor/contained_range_map-inl.h \
+ google-breakpad/processor/contained_range_map.h \
+ google-breakpad/processor/linked_ptr.h \
+ google-breakpad/processor/logging.h \
+ google-breakpad/processor/logging.cc \
+ google-breakpad/processor/minidump.cc \
+ google-breakpad/processor/minidump_processor.cc \
+ google-breakpad/processor/pathname_stripper.cc \
+ google-breakpad/processor/pathname_stripper.h \
+ google-breakpad/processor/postfix_evaluator-inl.h \
+ google-breakpad/processor/postfix_evaluator.h \
+ google-breakpad/processor/process_state.cc \
+ google-breakpad/processor/range_map-inl.h \
+ google-breakpad/processor/range_map.h \
+ google-breakpad/processor/scoped_ptr.h \
+ google-breakpad/processor/simple_symbol_supplier.cc \
+ google-breakpad/processor/simple_symbol_supplier.h \
+ google-breakpad/processor/stack_frame_info.h \
+ google-breakpad/processor/stackwalker.cc \
+ google-breakpad/processor/stackwalker_amd64.cc \
+ google-breakpad/processor/stackwalker_amd64.h \
+ google-breakpad/processor/stackwalker_ppc.cc \
+ google-breakpad/processor/stackwalker_ppc.h \
+ google-breakpad/processor/stackwalker_sparc.cc \
+ google-breakpad/processor/stackwalker_sparc.h \
+ google-breakpad/processor/stackwalker_x86.cc \
+ google-breakpad/processor/stackwalker_x86.h
+
+endif
============================================================
--- pidgin/crash/crashhandler.cpp a3d3acb62c8110773c0d6c59e2f44050f038994e
+++ pidgin/crash/crashhandler.cpp a3d3acb62c8110773c0d6c59e2f44050f038994e
@@ -0,0 +1,58 @@
+/*
+ * pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ */
+
+#include "client/linux/handler/exception_handler.h"
+#include "internal.h"
+
+extern "C" void pidgin_crash_init ();
+
+using namespace google_breakpad;
+
+// Callback when minidump written.
+static bool MinidumpCallback(
+ const char *dump_path,
+ const char *minidump_id,
+ void *context,
+ bool succeeded)
+{
+
+ printf("%s is dumped\n", minidump_id);
+/*
+ char *crash_argv[2];
+ crash_argv[0] = "crashreporter";
+ // Casting like this is bad. But at the same time, the heap
+ // is in a fubar'ed state here so allocating a copy is a really bad idea.
+ crash_argv[1] = (char *)minidump_id;
+ g_spawn_async(NULL, crash_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, NULL, NULL);
+*/
+ return true;
+}
+
+static ExceptionHandler* handler_process;
+
+void pidgin_crash_init () {
+ /* TODO: This is a minor memory leak. Clean this stuff up, yo */
+ handler_process = new ExceptionHandler(".", NULL, MinidumpCallback, NULL, true);
+}
+
+
============================================================
--- pidgin/crash/crashhandler.h 1de927fbe47b033d6f4ef2acbbfad4d077f13a7a
+++ pidgin/crash/crashhandler.h 1de927fbe47b033d6f4ef2acbbfad4d077f13a7a
@@ -0,0 +1,25 @@
+/*
+ * pidgin
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ */
+
+void pidgin_crash_init ();
+
============================================================
--- pidgin/crash/crashreporter.c 0eb9bcb318a89b23d9a65b538d791f1d6c7c2559
+++ pidgin/crash/crashreporter.c 0eb9bcb318a89b23d9a65b538d791f1d6c7c2559
@@ -0,0 +1,22 @@
+
+int pidgin_crash_minidump_print(const char *);
+
+#include <stdio.h>
+
+int main (int argc, char **argv) {
+
+ printf("dumping a file!\n");
+
+ if (argc <= 0) {
+ printf("no crash file");
+ return 1;
+ }
+
+ const char *minidump_file = argv[1];
+
+
+ printf("file name is %s\n", minidump_file);
+
+ return pidgin_crash_minidump_print(minidump_file);
+}
+
============================================================
--- pidgin/crash/minidump_stackwalk.cc 7e4a81d7dce4f654f84b647b9aaa56e9c223f2d6
+++ pidgin/crash/minidump_stackwalk.cc 7e4a81d7dce4f654f84b647b9aaa56e9c223f2d6
@@ -0,0 +1,472 @@
+// Copyright (c) 2006, 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.
+
+// minidump_stackwalk.cc: Process a minidump with MinidumpProcessor, printing
+// the results, including stack traces.
+//
+// Author: Mark Mentovai
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "google_breakpad/processor/basic_source_line_resolver.h"
+#include "google_breakpad/processor/call_stack.h"
+#include "google_breakpad/processor/code_module.h"
+#include "google_breakpad/processor/code_modules.h"
+#include "google_breakpad/processor/minidump.h"
+#include "google_breakpad/processor/minidump_processor.h"
+#include "google_breakpad/processor/process_state.h"
+#include "google_breakpad/processor/stack_frame_cpu.h"
+#include "processor/logging.h"
+#include "processor/pathname_stripper.h"
+#include "processor/scoped_ptr.h"
+#include "processor/simple_symbol_supplier.h"
+
+namespace {
+
+using std::string;
+using std::vector;
+using google_breakpad::BasicSourceLineResolver;
+using google_breakpad::CallStack;
+using google_breakpad::CodeModule;
+using google_breakpad::CodeModules;
+using google_breakpad::MinidumpModule;
+using google_breakpad::MinidumpProcessor;
+using google_breakpad::PathnameStripper;
+using google_breakpad::ProcessState;
+using google_breakpad::scoped_ptr;
+using google_breakpad::SimpleSymbolSupplier;
+using google_breakpad::StackFrame;
+using google_breakpad::StackFramePPC;
+using google_breakpad::StackFrameSPARC;
+using google_breakpad::StackFrameX86;
+using google_breakpad::StackFrameAMD64;
+
+// Separator character for machine readable output.
+static const char kOutputSeparator = '|';
+
+// PrintRegister prints a register's name and value to stdout. It will
+// print four registers on a line. For the first register in a set,
+// pass 0 for |sequence|. For registers in a set, pass the most recent
+// return value of PrintRegister. Note that PrintRegister will print a
+// newline before the first register (with |sequence| set to 0) is printed.
+// The caller is responsible for printing the final newline after a set
+// of registers is completely printed, regardless of the number of calls
+// to PrintRegister.
+static int PrintRegister(const char *name, u_int32_t value, int sequence) {
+ if (sequence % 4 == 0) {
+ printf("\n ");
+ }
+ printf(" %5s = 0x%08x", name, value);
+ return ++sequence;
+}
+
+// StripSeparator takes a string |original| and returns a copy
+// of the string with all occurences of |kOutputSeparator| removed.
+static string StripSeparator(const string &original) {
+ string result = original;
+ string::size_type position = 0;
+ while ((position = result.find(kOutputSeparator, position)) != string::npos) {
+ result.erase(position, 1);
+ }
+ return result;
+}
+
+// PrintStack prints the call stack in |stack| to stdout, in a reasonably
+// useful form. Module, function, and source file names are displayed if
+// they are available. The code offset to the base code address of the
+// source line, function, or module is printed, preferring them in that
+// order. If no source line, function, or module information is available,
+// an absolute code offset is printed.
+//
+// If |cpu| is a recognized CPU name, relevant register state for each stack
+// frame printed is also output, if available.
+static void PrintStack(const CallStack *stack, const string &cpu) {
+ int frame_count = stack->frames()->size();
+ for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
+ const StackFrame *frame = stack->frames()->at(frame_index);
+ printf("%2d ", frame_index);
+
+ if (frame->module) {
+ printf("%s", PathnameStripper::File(frame->module->code_file()).c_str());
+ if (!frame->function_name.empty()) {
+ printf("!%s", frame->function_name.c_str());
+ if (!frame->source_file_name.empty()) {
+ string source_file = PathnameStripper::File(frame->source_file_name);
+ printf(" [%s : %d + 0x%" PRIx64 "]",
+ source_file.c_str(),
+ frame->source_line,
+ frame->instruction - frame->source_line_base);
+ } else {
+ printf(" + 0x%" PRIx64, frame->instruction - frame->function_base);
+ }
+ } else {
+ printf(" + 0x%" PRIx64,
+ frame->instruction - frame->module->base_address());
+ }
+ } else {
+ printf("0x%" PRIx64, frame->instruction);
+ }
+
+ int sequence = 0;
+ if (cpu == "x86") {
+ const StackFrameX86 *frame_x86 =
+ reinterpret_cast<const StackFrameX86*>(frame);
+
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP)
+ sequence = PrintRegister("eip", frame_x86->context.eip, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)
+ sequence = PrintRegister("esp", frame_x86->context.esp, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP)
+ sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX)
+ sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI)
+ sequence = PrintRegister("esi", frame_x86->context.esi, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI)
+ sequence = PrintRegister("edi", frame_x86->context.edi, sequence);
+ if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) {
+ sequence = PrintRegister("eax", frame_x86->context.eax, sequence);
+ sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence);
+ sequence = PrintRegister("edx", frame_x86->context.edx, sequence);
+ sequence = PrintRegister("efl", frame_x86->context.eflags, sequence);
+ }
+ } else if (cpu == "ppc") {
+ const StackFramePPC *frame_ppc =
+ reinterpret_cast<const StackFramePPC*>(frame);
+
+ if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0)
+ sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
+ if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
+ sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
+ } else if (cpu == "amd64") {
+ const StackFrameAMD64 *frame_amd64 =
+ reinterpret_cast<const StackFrameAMD64*>(frame);
+
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP)
+ sequence = PrintRegister("rip", frame_amd64->context.rip, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP)
+ sequence = PrintRegister("rsp", frame_amd64->context.rsp, sequence);
+ if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP)
+ sequence = PrintRegister("rbp", frame_amd64->context.rbp, sequence);
+ } else if (cpu == "sparc") {
+ const StackFrameSPARC *frame_sparc =
+ reinterpret_cast<const StackFrameSPARC*>(frame);
+
+ if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP)
+ sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence);
+ if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP)
+ sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence);
+ if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
+ sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
+ }
+ printf("\n");
+ }
+}
+
+// PrintStackMachineReadable prints the call stack in |stack| to stdout,
+// in the following machine readable pipe-delimited text format:
+// thread number|frame number|module|function|source file|line|offset
+//
+// Module, function, source file, and source line may all be empty
+// depending on availability. The code offset follows the same rules as
+// PrintStack above.
+static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
+ int frame_count = stack->frames()->size();
+ for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
+ const StackFrame *frame = stack->frames()->at(frame_index);
+ printf("%d%c%d%c", thread_num, kOutputSeparator, frame_index,
+ kOutputSeparator);
+
+ if (frame->module) {
+ assert(!frame->module->code_file().empty());
+ printf("%s", StripSeparator(PathnameStripper::File(
+ frame->module->code_file())).c_str());
+ if (!frame->function_name.empty()) {
+ printf("%c%s", kOutputSeparator,
+ StripSeparator(frame->function_name).c_str());
+ if (!frame->source_file_name.empty()) {
+ printf("%c%s%c%d%c0x%" PRIx64,
+ kOutputSeparator,
+ StripSeparator(frame->source_file_name).c_str(),
+ kOutputSeparator,
+ frame->source_line,
+ kOutputSeparator,
+ frame->instruction - frame->source_line_base);
+ } else {
+ printf("%c%c%c0x%" PRIx64,
+ kOutputSeparator, // empty source file
+ kOutputSeparator, // empty source line
+ kOutputSeparator,
+ frame->instruction - frame->function_base);
+ }
+ } else {
+ printf("%c%c%c%c0x%" PRIx64,
+ kOutputSeparator, // empty function name
+ kOutputSeparator, // empty source file
+ kOutputSeparator, // empty source line
+ kOutputSeparator,
+ frame->instruction - frame->module->base_address());
+ }
+ } else {
+ // the printf before this prints a trailing separator for module name
+ printf("%c%c%c%c0x%" PRIx64,
+ kOutputSeparator, // empty function name
+ kOutputSeparator, // empty source file
+ kOutputSeparator, // empty source line
+ kOutputSeparator,
+ frame->instruction);
+ }
+ printf("\n");
+ }
+}
+
+static void PrintModules(const CodeModules *modules) {
+ if (!modules)
+ return;
+
+ printf("\n");
+ printf("Loaded modules:\n");
+
+ u_int64_t main_address = 0;
+ const CodeModule *main_module = modules->GetMainModule();
+ if (main_module) {
+ main_address = main_module->base_address();
+ }
+
+ unsigned int module_count = modules->module_count();
+ for (unsigned int module_sequence = 0;
+ module_sequence < module_count;
+ ++module_sequence) {
+ const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
+ u_int64_t base_address = module->base_address();
+ printf("0x%08" PRIx64 " - 0x%08" PRIx64 " %s %s%s\n",
+ base_address, base_address + module->size() - 1,
+ PathnameStripper::File(module->code_file()).c_str(),
+ module->version().empty() ? "???" : module->version().c_str(),
+ main_module != NULL && base_address == main_address ?
+ " (main)" : "");
+ }
+}
+
+// PrintModulesMachineReadable outputs a list of loaded modules,
+// one per line, in the following machine-readable pipe-delimited
+// text format:
+// Module|{Module Filename}|{Version}|{Debug Filename}|{Debug Identifier}|
+// {Base Address}|{Max Address}|{Main}
+static void PrintModulesMachineReadable(const CodeModules *modules) {
+ if (!modules)
+ return;
+
+ u_int64_t main_address = 0;
+ const CodeModule *main_module = modules->GetMainModule();
+ if (main_module) {
+ main_address = main_module->base_address();
+ }
+
+ unsigned int module_count = modules->module_count();
+ for (unsigned int module_sequence = 0;
+ module_sequence < module_count;
+ ++module_sequence) {
+ const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
+ u_int64_t base_address = module->base_address();
+ printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n",
+ kOutputSeparator,
+ StripSeparator(PathnameStripper::File(module->code_file())).c_str(),
+ kOutputSeparator, StripSeparator(module->version()).c_str(),
+ kOutputSeparator,
+ StripSeparator(PathnameStripper::File(module->debug_file())).c_str(),
+ kOutputSeparator,
+ StripSeparator(module->debug_identifier()).c_str(),
+ kOutputSeparator, base_address,
+ kOutputSeparator, base_address + module->size() - 1,
+ kOutputSeparator,
+ main_module != NULL && base_address == main_address ? 1 : 0);
+ }
+}
+
+static void PrintProcessState(const ProcessState& process_state) {
+ // Print OS and CPU information.
+ string cpu = process_state.system_info()->cpu;
+ string cpu_info = process_state.system_info()->cpu_info;
+ printf("Operating system: %s\n", process_state.system_info()->os.c_str());
+ printf(" %s\n",
+ process_state.system_info()->os_version.c_str());
+ printf("CPU: %s\n", cpu.c_str());
+ if (!cpu_info.empty()) {
+ // This field is optional.
+ printf(" %s\n", cpu_info.c_str());
+ }
+ printf(" %d CPU%s\n",
+ process_state.system_info()->cpu_count,
+ process_state.system_info()->cpu_count != 1 ? "s" : "");
+ printf("\n");
+
+ // Print crash information.
+ if (process_state.crashed()) {
+ printf("Crash reason: %s\n", process_state.crash_reason().c_str());
+ printf("Crash address: 0x%" PRIx64 "\n", process_state.crash_address());
+ } else {
+ printf("No crash\n");
+ }
+
+ // If the thread that requested the dump is known, print it first.
+ int requesting_thread = process_state.requesting_thread();
+ if (requesting_thread != -1) {
+ printf("\n");
+ printf("Thread %d (%s)\n",
+ requesting_thread,
+ process_state.crashed() ? "crashed" :
+ "requested dump, did not crash");
+ PrintStack(process_state.threads()->at(requesting_thread), cpu);
+ }
+
+ // Print all of the threads in the dump.
+ int thread_count = process_state.threads()->size();
+ for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
+ if (thread_index != requesting_thread) {
+ // Don't print the crash thread again, it was already printed.
+ printf("\n");
+ printf("Thread %d\n", thread_index);
+ PrintStack(process_state.threads()->at(thread_index), cpu);
+ }
+ }
+
+ PrintModules(process_state.modules());
+}
+
+static void PrintProcessStateMachineReadable(const ProcessState& process_state)
+{
+ // Print OS and CPU information.
+ // OS|{OS Name}|{OS Version}
+ // CPU|{CPU Name}|{CPU Info}|{Number of CPUs}
+ printf("OS%c%s%c%s\n", kOutputSeparator,
+ StripSeparator(process_state.system_info()->os).c_str(),
+ kOutputSeparator,
+ StripSeparator(process_state.system_info()->os_version).c_str());
+ printf("CPU%c%s%c%s%c%d\n", kOutputSeparator,
+ StripSeparator(process_state.system_info()->cpu).c_str(),
+ kOutputSeparator,
+ // this may be empty
+ StripSeparator(process_state.system_info()->cpu_info).c_str(),
+ kOutputSeparator,
+ process_state.system_info()->cpu_count);
+
+ int requesting_thread = process_state.requesting_thread();
+
+ // Print crash information.
+ // Crash|{Crash Reason}|{Crash Address}|{Crashed Thread}
+ printf("Crash%c", kOutputSeparator);
+ if (process_state.crashed()) {
+ printf("%s%c0x%" PRIx64 "%c",
+ StripSeparator(process_state.crash_reason()).c_str(),
+ kOutputSeparator, process_state.crash_address(), kOutputSeparator);
+ } else {
+ printf("No crash%c%c", kOutputSeparator, kOutputSeparator);
+ }
+
+ if (requesting_thread != -1) {
+ printf("%d\n", requesting_thread);
+ } else {
+ printf("\n");
+ }
+
+ PrintModulesMachineReadable(process_state.modules());
+
+ // blank line to indicate start of threads
+ printf("\n");
+
+ // If the thread that requested the dump is known, print it first.
+ if (requesting_thread != -1) {
+ PrintStackMachineReadable(requesting_thread,
+ process_state.threads()->at(requesting_thread));
+ }
+
+ // Print all of the threads in the dump.
+ int thread_count = process_state.threads()->size();
+ for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
+ if (thread_index != requesting_thread) {
+ // Don't print the crash thread again, it was already printed.
+ PrintStackMachineReadable(thread_index,
+ process_state.threads()->at(thread_index));
+ }
+ }
+}
+
+// Processes |minidump_file| using MinidumpProcessor. |symbol_path|, if
+// non-empty, is the base directory of a symbol storage area, laid out in
+// the format required by SimpleSymbolSupplier. If such a storage area
+// is specified, it is made available for use by the MinidumpProcessor.
+//
+// Returns the value of MinidumpProcessor::Process. If processing succeeds,
+// prints identifying OS and CPU information from the minidump, crash
+// information if the minidump was produced as a result of a crash, and
+// call stacks for each thread contained in the minidump. All information
+// is printed to stdout.
+static bool PrintMinidumpProcess(const string &minidump_file,
+ const vector<string> &symbol_paths,
+ bool machine_readable) {
+ scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
+ if (!symbol_paths.empty()) {
+ // TODO(mmentovai): check existence of symbol_path if specified?
+ symbol_supplier.reset(new SimpleSymbolSupplier(symbol_paths));
+ }
+
+ BasicSourceLineResolver resolver;
+ MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver);
+
+ // Process the minidump.
+ ProcessState process_state;
+ if (minidump_processor.Process(minidump_file, &process_state) !=
+ MinidumpProcessor::PROCESS_OK) {
+ BPLOG(ERROR) << "MinidumpProcessor::Process failed";
+ return false;
+ }
+
+ if (machine_readable) {
+ PrintProcessStateMachineReadable(process_state);
+ } else {
+ PrintProcessState(process_state);
+ }
+
+ return true;
+}
+
+} // namespace
+
+extern "C" int pidgin_crash_minidump_print(const char *);
+
+int pidgin_crash_minidump_print(const char *minidump_file) {
+ std::vector<std::string> symbol_paths;
+ return PrintMinidumpProcess(minidump_file,
+ symbol_paths,
+ 0) ? 0 : 1;
+}
============================================================
--- COPYRIGHT 8263dd4945d151ddae2594f6383433f32d24e5d7
+++ COPYRIGHT cf8fb51e7723eecad48857242928dcd98b7e169b
@@ -155,6 +155,7 @@ Michael Golden
Ian Goldberg
Matthew Goldstein
Michael Golden
+Google, Inc.
Charlie Gordon
Ryan C. Gordon
Konrad Gr?fe
============================================================
--- configure.ac ee8e1e7c026df087caad9adfbcb8244e5f8fc213
+++ configure.ac adf72c99cbfa2efbd760108da217faf72080174f
@@ -745,6 +745,54 @@ dnl ####################################
fi
dnl #######################################################################
+dnl # Crash reporter checks (requires C++/libstdc++)
+dnl #######################################################################
+
+AC_ARG_ENABLE(crashreporter,
+ [AC_HELP_STRING([--disable-crashreporter], [compile without crash reporter support])],
+ enable_crashreporter="$enableval", enable_crashreporter="yes")
+if test "x$enable_crashreporter" = "xyes"; then
+ AC_PROG_CXX
+
+ CRASHREPORTER_SUPPORTED_OS="no"
+ case $target_os in
+ linux*)
+ CRASHREPORTER_SUPPORTED_OS="yes"
+ ;;
+ esac
+
+ CRASHREPORTER_SUPPORTED_ARCH="no"
+ case $target_cpu in
+ *86*)
+ CRASHREPORTER_SUPPORTED_ARCH="yes" ;;
+ esac
+
+ if test x$CRASHREPORTER_SUPPORTED_OS = xyes ; then
+ if test x$CRASHREPORTER_SUPPORTED_ARCH = xyes ; then
+ AC_CHECK_LIB([stdc++], [main], [
+ enable_crashreporter="yes"
+ AC_DEFINE(ENABLE_CRASHREPORTER, 1, [Define if we are using the crash reporter])
+ ], [
+ enable_crashreporter="no"
+ if test "x$force_deps" = "xyes" ; then
+ AC_MSG_ERROR([
+libstdc++ not found.
+Use --disable-crashreporter if you do not want crash reporter support.
+])
+ fi])
+
+ else
+ enable_crashreporter="no"
+ fi
+ else
+ enable_crashreporter="no"
+ fi
+
+fi
+
+AM_CONDITIONAL(ENABLE_CRASHREPORTER, test "x$enable_crashreporter" = "xyes")
+
+dnl #######################################################################
dnl # Check for Meanwhile headers (for Sametime)
dnl #######################################################################
AC_ARG_ENABLE(meanwhile,
@@ -2391,6 +2439,7 @@ AC_OUTPUT([Makefile
m4macros/Makefile
pidgin.apspec
pidgin/Makefile
+ pidgin/crash/Makefile
pidgin/pidgin.pc
pidgin/pidgin-uninstalled.pc
pidgin/pixmaps/Makefile
@@ -2492,6 +2541,7 @@ echo
echo Build with Tcl support........ : $enable_tcl
echo Build with Tk support......... : $enable_tk
echo
+echo Build with crash reporter..... : $enable_crashreporter
echo Print debugging messages...... : $enable_debug
echo
eval eval echo Pidgin will be installed in $bindir.
============================================================
--- pidgin/Makefile.am 83bb46eedfe2d4f347e48eaa9bd015d0fcd8fb8b
+++ pidgin/Makefile.am e111ea64b04e7d59bf890e65f2c27e6832f09293
@@ -68,7 +68,7 @@ pkgconfig_DATA = pidgin.pc
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = pidgin.pc
-SUBDIRS = pixmaps plugins
+SUBDIRS = pixmaps plugins
bin_PROGRAMS = pidgin
@@ -128,6 +128,21 @@ pidgin_SOURCES = \
minidialog.c \
pidgintooltip.c
+if ENABLE_CRASHREPORTER
+pidgin_SOURCES += \
+ crash/google-breakpad/common/convert_UTF.c \
+ crash/google-breakpad/common/string_conversion.cc \
+ crash/google-breakpad/common/linux/dump_symbols.cc \
+ crash/google-breakpad/common/linux/file_id.cc \
+ crash/google-breakpad/common/md5.c \
+ crash/google-breakpad/common/linux/guid_creator.cc \
+ crash/google-breakpad/client/minidump_file_writer.cc \
+ crash/google-breakpad/client/linux/handler/exception_handler.cc \
+ crash/google-breakpad/client/linux/handler/minidump_generator.cc \
+ crash/google-breakpad/client/linux/handler/linux_thread.cc \
+ crash/crashhandler.cpp
+endif
+
pidgin_headers = \
eggtrayicon.h \
gtkaccount.h \
@@ -232,4 +247,9 @@ AM_CPPFLAGS = \
$(STARTUP_NOTIFICATION_CFLAGS) \
$(LIBXML_CFLAGS) \
$(INTGG_CFLAGS)
+
+if ENABLE_CRASHREPORTER
+AM_CPPFLAGS += -I$(top_srcdir)/pidgin/crash/google-breakpad
+endif
+
endif # ENABLE_GTK
============================================================
--- pidgin/gtkmain.c d81348657e210136bc46ca216e2f4e1d096884ee
+++ pidgin/gtkmain.c 61f3d4d30b5093843a8fef70111889e2e987d790
@@ -73,6 +73,10 @@
# include <signal.h>
#endif
+#ifdef ENABLE_CRASHREPORTER
+#include "crash/crashhandler.h"
+#endif
+
#include <getopt.h>
#ifdef HAVE_STARTUP_NOTIFICATION
@@ -95,7 +99,10 @@ static const int catch_sig_list[] = {
* Each list terminated with -1
*/
static const int catch_sig_list[] = {
+#ifndef ENABLE_CRASHREPORTER
+ /* If crash reporter is enabled, it will separately handle segfaults */
SIGSEGV,
+#endif
SIGHUP,
SIGINT,
SIGTERM,
@@ -523,6 +530,11 @@ int main(int argc, char *argv[])
setlocale(LC_ALL, "");
#endif
+#ifdef ENABLE_CRASHREPORTER
+ /* Initialize the crash reporter. The crash reporter will do it's own catching of signals */
+ pidgin_crash_init();
+#endif
+
#ifdef HAVE_SIGNAL_H
#ifndef DEBUG
More information about the Commits
mailing list