cpw.caseyho.crashreporter: 3c453122: Basic info grabbing complete. Crash rep...

caseyho at pidgin.im caseyho at pidgin.im
Fri Feb 13 19:35:41 EST 2009


-----------------------------------------------------------------
Revision: 3c453122d4b365fcabf2f55fe469db2ea8c66650
Ancestor: 9d46bf20ea1299025d3f1240a2c2df0cf724762f
Author: caseyho at pidgin.im
Date: 2009-02-13T21:05:03
Branch: im.pidgin.cpw.caseyho.crashreporter
URL: http://d.pidgin.im/viewmtn/revision/info/3c453122d4b365fcabf2f55fe469db2ea8c66650

Modified files:
        pidgin/crash/Makefile.am pidgin/crash/crashreporter.c
        pidgin/crash/minidump_stackwalk.cc

ChangeLog: 

Basic info grabbing complete.  Crash reporter can now fetch libpurple prefs and plugin information.  Dumps are now scanned for plugin names to be matched against libpurple plugins

-------------- next part --------------
============================================================
--- pidgin/crash/Makefile.am	7be270d7520975baa617b88bfab1a1b2b5114550
+++ pidgin/crash/Makefile.am	940da7d942fe28a6d365317d3f938e11ad180952
@@ -6,9 +6,24 @@ pidgincrashreporter_SOURCES = \
 	crashreporter.c \
 	minidump_stackwalk.cc
 
-pidgincrashreporter_LDADD = $(top_srcdir)/thirdparty/google-breakpad/src/libbreakpad.la
+pidgincrashreporter_LDADD = \
+	$(top_srcdir)/thirdparty/google-breakpad/src/libbreakpad.la \
+	$(GLIB_LIBS) \
+	$(GTK_LIBS) \
+	$(top_builddir)/libpurple/libpurple.la
 
 AM_CPPFLAGS = \
-	-I$(top_srcdir)/thirdparty/google-breakpad/src
+	-DDATADIR=\"$(datadir)\" \
+	-DLIBDIR=\"$(libdir)/pidgin/\" \
+	-DLOCALEDIR=\"$(datadir)/locale\" \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
+	-I$(top_builddir)/libpurple \
+	-I$(top_srcdir)/libpurple/ \
+	-I$(top_srcdir)/thirdparty/google-breakpad/src \
+	-I$(top_builddir) \
+	-I$(top_srcdir) \
+	$(GLIB_CFLAGS) \
+	$(GTK_CFLAGS) 
 
+
 endif
============================================================
--- pidgin/crash/crashreporter.c	0eb9bcb318a89b23d9a65b538d791f1d6c7c2559
+++ pidgin/crash/crashreporter.c	c4ffc4546ecf31851a17dd9d17d134d3ad3e5c35
@@ -1,22 +1,167 @@
 
-int pidgin_crash_minidump_print(const char *);
+#include <glib.h>
+#include <stdio.h>
+#include "crashreporter.h"
 
-#include <stdio.h>
+#include "internal.h"
+#include "pidgin.h"
+#include <gtk/gtk.h>
 
+#include "core.h"
+
+static PurpleCoreUiOps core_ops =
+{
+	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
+};
+
+static PurpleEventLoopUiOps eventloop_ops =
+{
+	g_timeout_add,
+	g_source_remove,
+	NULL,
+	g_source_remove,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static gboolean
+has_file_extension(const char *filename, const char *ext)
+{
+	int len, extlen;
+
+	if (filename == NULL || *filename == '\0' || ext == NULL)
+		return 0;
+
+	extlen = strlen(ext);
+	len = strlen(filename) - extlen;
+
+	if (len < 0)
+		return 0;
+
+	return (strncmp(filename + len, ext, extlen) == 0);
+}
+
+/**
+ * Returns a hashtable mapping strings (library name) to PurplePlugin objects
+ */
+static GHashTable*
+probe_plugins () 
+{
+	gchar *search_path;
+	GDir *dir;
+	const gchar *file;
+	gchar *path;
+	PurplePlugin *plugin;
+	GList *cur;
+	GHashTable *plugins;
+	GList *plugin_search_paths = NULL;
+
+	plugins = g_hash_table_new (g_str_hash, g_str_equal);
+
+	search_path = g_build_filename(purple_user_dir(), "plugins", NULL);
+	plugin_search_paths = g_list_append(plugin_search_paths, search_path);
+	plugin_search_paths = g_list_append(
+		plugin_search_paths, g_strdup(LIBDIR));
+
+	/* Probe plugins */
+	for (cur = plugin_search_paths; cur != NULL; cur = cur->next)
+	{
+		search_path = cur->data;
+
+		dir = g_dir_open(search_path, 0, NULL);
+
+		if (dir != NULL)
+		{
+			while ((file = g_dir_read_name(dir)) != NULL)
+			{
+				path = g_build_filename(search_path, file, NULL);
+
+				if (G_MODULE_SUFFIX == NULL ||
+					has_file_extension(file, G_MODULE_SUFFIX)) {
+					plugin = purple_plugin_probe(path);
+					g_hash_table_insert(plugins, 
+						g_strdup(file), plugin);
+				}
+				g_free(path);
+			}
+			g_dir_close(dir);
+		}
+	}
+
+	return plugins;
+}
+
 int main (int argc, char **argv) {
+	char *search_path;
+	GHashTable *plugins;
 
-	printf("dumping a file!\n");
+	/* Initialize GThread before calling any Glib or GTK+ functions. */
+	g_thread_init(NULL);
 
-	if (argc <= 0) {
-		printf("no crash file");
+	/* 
+	 * Initialize GTK 
+	 * TODO: maybe we need to check return value of gtk_init?
+	 */
+	search_path = g_build_filename(purple_user_dir(), "gtkrc-2.0", NULL);
+	gtk_rc_add_default_file(search_path);
+	g_free(search_path);
+	gtk_init_check(&argc, &argv);
+
+	/* Initialize libpurple.  This is essentially a hail mary attempt to 
+	 * load Pidgin into a "safe mode" of sorts where we can read prefs
+	 * and figure out the user state.  It's possible of course that the
+	 * crash occured in libpurple itself, which negates all this.  On the
+	 * plus side, when we get here the dump will exist, so the next step
+	 * is to go into a traditional triage mode where we ask the user to
+	 * email us the dump or a gdb core, a copy of prefs.xml, etc.
+	 *
+	 * TODO: Add a crash handler to detect if the crash reporter itself
+	 * crashed, and give a simple notification in that case.
+	 */
+
+	/* TODO: if user was using a custom libpurple directory, we don't 
+	 * know anything about it.  Figure it out! */
+
+	/* We're in a rescue mode of sorts.  We need all the info we can get */
+	purple_debug_set_enabled(TRUE);
+
+	purple_core_set_ui_ops(&core_ops);
+	purple_eventloop_set_ui_ops(&eventloop_ops);
+	purple_core_create(PIDGIN_UI);
+
+	/* Load user prefs.  This is important for debugging! */
+	purple_prefs_init();
+
+	/* We want to immediately isolate bugs caused by plugins. */
+	if (!g_module_supported()) return;
+	plugins = probe_plugins();
+
+	/*
+	 * Deal with the minidump from the crash.  Do a simple check and grab
+	 * the names of modules involved in the crash.
+	 */
+	purple_debug_info("crash", "grabbing minidump file\n");
+
+	if (argc <= 0 || argv[1] == NULL) {
+		purple_debug_error("crash", "no crash file provided\n");
 		return 1;
 	}
 
 	const char *minidump_file = argv[1];
+	purple_debug_info("crash", "minidump file name is %s\n", minidump_file);
 
+	GList *module_names = pidgin_crash_module_stack(minidump_file);
 
-	printf("file name is %s\n", minidump_file);
 
-	return pidgin_crash_minidump_print(minidump_file);
+
+	while(module_names != NULL) {
+		g_free(module_names->data);
+		module_names = module_names->next;
+	}
+
+	return 0;
 }
 
============================================================
--- pidgin/crash/minidump_stackwalk.cc	7e4a81d7dce4f654f84b647b9aaa56e9c223f2d6
+++ pidgin/crash/minidump_stackwalk.cc	74e16e2b98123a2c933b1a63980971c4cbf72f5b
@@ -1,36 +1,5 @@
-// 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 <glib.h>
 
 #include <cstdio>
 #include <cstdlib>
@@ -65,408 +34,48 @@ using google_breakpad::StackFrame;
 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 = '|';
+static GList *GetCrashModules(const string &minidump_file) {
+	scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
+	std::vector<std::string> symbol_paths;
+	symbol_supplier.reset(new SimpleSymbolSupplier(symbol_paths));
 
-// 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;
-}
+	BasicSourceLineResolver resolver;
+	MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver);
 
-// 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;
-}
+	// Process the minidump.
+	ProcessState process_state;
+	if (minidump_processor.Process(minidump_file, &process_state) !=
+		MinidumpProcessor::PROCESS_OK) {
+		BPLOG(ERROR) << "MinidumpProcessor::Process failed";
+		return NULL;
+	}
 
-// 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);
+	int requesting_thread = process_state.requesting_thread();
+	if (requesting_thread == -1) {
+		return NULL;
+	}
 
-    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);
-    }
+	CallStack *stack = process_state.threads()->at(requesting_thread);
+	GList *module_names = NULL;
+	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);
+		if (frame->module) {
+			const char *module_name = PathnameStripper::File(
+				frame->module->code_file()).c_str();
+			module_names = g_list_append(
+				module_names, g_strdup(module_name));
+		}
+	}
 
-    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");
-  }
+	return module_names;
 }
 
-// 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 *);
+extern "C" GList *pidgin_crash_module_stack(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;
+GList* pidgin_crash_module_stack(const char *minidump_file) {
+   return GetCrashModules(minidump_file);
 }


More information about the Commits mailing list