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