bug 559228 - Implement multi-process crash reporting on Mac. r=bsmedberg a=blocking

This commit is contained in:
Ted Mielczarek
2010-08-16 15:05:09 -04:00
parent b5f825ab9d
commit 56bd78cc30
5 changed files with 84 additions and 49 deletions

View File

@@ -54,13 +54,13 @@
int int
main(int argc, char* argv[]) main(int argc, char* argv[])
{ {
#if defined(MOZ_CRASHREPORTER) && !defined(XP_MACOSX) #if defined(MOZ_CRASHREPORTER)
if (argc < 2) if (argc < 2)
return 1; return 1;
const char* const crashReporterArg = argv[--argc]; const char* const crashReporterArg = argv[--argc];
# if defined(XP_WIN) # if defined(XP_WIN) || defined(XP_MACOSX)
// on windows, |crashReporterArg| is the named pipe on which the // on windows and mac, |crashReporterArg| is the named pipe on which the
// server is listening for requests, or "-" if crash reporting is // server is listening for requests, or "-" if crash reporting is
// disabled. // disabled.
if (0 != strcmp("-", crashReporterArg) if (0 != strcmp("-", crashReporterArg)

View File

@@ -318,9 +318,7 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
childArgv.push_back("false"); childArgv.push_back("false");
} }
# elif defined(XP_MACOSX) # elif defined(XP_MACOSX)
// Call the stub for initialization side effects. Eventually this childArgv.push_back(CrashReporter::GetChildNotificationPipe());
// code will be unified with that above.
CrashReporter::CreateNotificationPipeForChild();
# endif // OS_LINUX # endif // OS_LINUX
#endif #endif

View File

@@ -52,6 +52,10 @@
#include <DbgHelp.h> #include <DbgHelp.h>
#include <string.h> #include <string.h>
#elif defined(XP_MACOSX) #elif defined(XP_MACOSX)
#if defined(MOZ_IPC)
# include "client/mac/crash_generation/client_info.h"
# include "client/mac/crash_generation/crash_generation_server.h"
#endif
#include "client/mac/handler/exception_handler.h" #include "client/mac/handler/exception_handler.h"
#include <string> #include <string>
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
@@ -104,11 +108,8 @@ CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
#if defined(MOZ_IPC) #if defined(MOZ_IPC)
#include "nsIUUIDGenerator.h" #include "nsIUUIDGenerator.h"
#if !defined(XP_MACOSX)
using google_breakpad::CrashGenerationServer; using google_breakpad::CrashGenerationServer;
using google_breakpad::ClientInfo; using google_breakpad::ClientInfo;
#endif
using mozilla::Mutex; using mozilla::Mutex;
using mozilla::MutexAutoLock; using mozilla::MutexAutoLock;
#endif // MOZ_IPC #endif // MOZ_IPC
@@ -191,12 +192,10 @@ static nsCString* crashReporterAPIData = nsnull;
static nsCString* notesField = nsnull; static nsCString* notesField = nsnull;
#if defined(MOZ_IPC) #if defined(MOZ_IPC)
#if !defined(XP_MACOSX)
// OOP crash reporting // OOP crash reporting
static CrashGenerationServer* crashServer; // chrome process has this static CrashGenerationServer* crashServer; // chrome process has this
#endif
# if defined(XP_WIN) # if defined(XP_WIN) || defined(XP_MACOSX)
// If crash reporting is disabled, we hand out this "null" pipe to the // If crash reporting is disabled, we hand out this "null" pipe to the
// child process and don't attempt to connect to a parent server. // child process and don't attempt to connect to a parent server.
static const char kNullNotifyPipe[] = "-"; static const char kNullNotifyPipe[] = "-";
@@ -206,6 +205,7 @@ static char* childCrashNotifyPipe;
static int serverSocketFd = -1; static int serverSocketFd = -1;
static int clientSocketFd = -1; static int clientSocketFd = -1;
static const int kMagicChildCrashReportFd = 42; static const int kMagicChildCrashReportFd = 42;
# endif # endif
// |dumpMapLock| must protect all access to |pidToMinidump|. // |dumpMapLock| must protect all access to |pidToMinidump|.
@@ -571,11 +571,11 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
google_breakpad::ExceptionHandler::HANDLER_ALL); google_breakpad::ExceptionHandler::HANDLER_ALL);
#else #else
true true
#endif
#if defined(XP_MACOSX) #if defined(XP_MACOSX)
, NULL , NULL
#endif #endif
); );
#endif // XP_WIN32
if (!gExceptionHandler) if (!gExceptionHandler)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
@@ -604,11 +604,7 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
bool GetEnabled() bool GetEnabled()
{ {
#if defined(XP_MACOSX)
return gExceptionHandler != nsnull;
#else
return gExceptionHandler != nsnull && !gExceptionHandler->IsOutOfProcess(); return gExceptionHandler != nsnull && !gExceptionHandler->IsOutOfProcess();
#endif
} }
bool GetMinidumpPath(nsAString& aPath) bool GetMinidumpPath(nsAString& aPath)
@@ -1469,16 +1465,27 @@ MoveToPending(nsIFile* dumpFile, nsIFile* extraFile)
NS_SUCCEEDED(extraFile->MoveTo(pendingDir, EmptyString())); NS_SUCCEEDED(extraFile->MoveTo(pendingDir, EmptyString()));
} }
#if !defined(XP_MACOSX)
static void static void
OnChildProcessDumpRequested(void* aContext, OnChildProcessDumpRequested(void* aContext,
#ifdef XP_MACOSX
const ClientInfo& aClientInfo,
const xpstring& aFilePath
#else
const ClientInfo* aClientInfo, const ClientInfo* aClientInfo,
const xpstring* aFilePath) const xpstring* aFilePath
#endif
)
{ {
nsCOMPtr<nsILocalFile> minidump; nsCOMPtr<nsILocalFile> minidump;
nsCOMPtr<nsILocalFile> extraFile; nsCOMPtr<nsILocalFile> extraFile;
CreateFileFromPath(*aFilePath, getter_AddRefs(minidump)); CreateFileFromPath(
#ifdef XP_MACOSX
aFilePath,
#else
*aFilePath,
#endif
getter_AddRefs(minidump));
if (!WriteExtraForMinidump(minidump, if (!WriteExtraForMinidump(minidump,
Blacklist(kSubprocessBlacklist, Blacklist(kSubprocessBlacklist,
@@ -1490,13 +1497,17 @@ OnChildProcessDumpRequested(void* aContext,
MoveToPending(minidump, extraFile); MoveToPending(minidump, extraFile);
{ {
PRUint32 pid = aClientInfo->pid(); PRUint32 pid =
#ifdef XP_MACOSX
aClientInfo.pid();
#else
aClientInfo->pid();
#endif
MutexAutoLock lock(*dumpMapLock); MutexAutoLock lock(*dumpMapLock);
pidToMinidump->Put(pid, minidump); pidToMinidump->Put(pid, minidump);
} }
} }
#endif // XP_MACOSX
static bool static bool
OOPInitialized() OOPInitialized()
@@ -1539,12 +1550,23 @@ OOPInit()
NULL, NULL, // we don't care about process exit here NULL, NULL, // we don't care about process exit here
true, // automatically generate dumps true, // automatically generate dumps
&dumpPath); &dumpPath);
#elif defined(XP_MACOSX)
childCrashNotifyPipe =
PR_smprintf("gecko-crash-server-pipe.%i",
static_cast<int>(getpid()));
const std::string dumpPath = gExceptionHandler->dump_path();
crashServer = new CrashGenerationServer(
childCrashNotifyPipe,
OnChildProcessDumpRequested, NULL,
NULL, NULL,
true, // automatically generate dumps
dumpPath);
#endif #endif
#if !defined(XP_MACOSX)
if (!crashServer->Start()) if (!crashServer->Start())
NS_RUNTIMEABORT("can't start crash reporter server()"); NS_RUNTIMEABORT("can't start crash reporter server()");
#endif
pidToMinidump = new ChildMinidumpMap(); pidToMinidump = new ChildMinidumpMap();
pidToMinidump->Init(); pidToMinidump->Init();
@@ -1560,10 +1582,8 @@ OOPDeinit()
return; return;
} }
#if !defined(XP_MACOSX)
delete crashServer; delete crashServer;
crashServer = NULL; crashServer = NULL;
#endif
delete dumpMapLock; delete dumpMapLock;
dumpMapLock = NULL; dumpMapLock = NULL;
@@ -1577,7 +1597,7 @@ OOPDeinit()
#endif #endif
} }
#if defined(XP_WIN) #if defined(XP_WIN) || defined(XP_MACOSX)
// Parent-side API for children // Parent-side API for children
const char* const char*
GetChildNotificationPipe() GetChildNotificationPipe()
@@ -1590,7 +1610,9 @@ GetChildNotificationPipe()
return childCrashNotifyPipe; return childCrashNotifyPipe;
} }
#endif
#if defined(XP_WIN)
// Child-side API // Child-side API
bool bool
SetRemoteExceptionHandler(const nsACString& crashPipe) SetRemoteExceptionHandler(const nsACString& crashPipe)
@@ -1657,11 +1679,26 @@ SetRemoteExceptionHandler()
//-------------------------------------------------- //--------------------------------------------------
#elif defined(XP_MACOSX) #elif defined(XP_MACOSX)
void // Child-side API
CreateNotificationPipeForChild() bool
SetRemoteExceptionHandler(const nsACString& crashPipe)
{ {
if (GetEnabled() && !OOPInitialized()) // crash reporting is disabled
OOPInit(); if (crashPipe.Equals(kNullNotifyPipe))
return true;
NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
gExceptionHandler = new google_breakpad::
ExceptionHandler("",
NULL, // no filter callback
NULL, // no minidump callback
NULL, // no callback context
true, // install signal handlers
crashPipe.BeginReading());
// we either do remote or nothing, no fallback to regular crash reporting
return gExceptionHandler->IsOutOfProcess();
} }
#endif // XP_WIN #endif // XP_WIN
@@ -1726,7 +1763,7 @@ CurrentThreadId()
#elif defined(XP_LINUX) #elif defined(XP_LINUX)
return sys_gettid(); return sys_gettid();
#elif defined(XP_MACOSX) #elif defined(XP_MACOSX)
return -1; return mach_thread_self();
#else #else
# error "Unsupported platform" # error "Unsupported platform"
#endif #endif
@@ -1739,12 +1776,11 @@ CreatePairedMinidumps(ProcessHandle childPid,
nsILocalFile** childDump, nsILocalFile** childDump,
nsILocalFile** parentDump) nsILocalFile** parentDump)
{ {
if (!GetEnabled()) #ifdef XP_MACOSX
return false;
#if defined(XP_MACOSX)
return false; return false;
#else #else
if (!GetEnabled())
return false;
// create the UUID for the hang dump as a pair // create the UUID for the hang dump as a pair
nsresult rv; nsresult rv;
@@ -1788,7 +1824,9 @@ CreatePairedMinidumps(ProcessHandle childPid,
{ &parentMinidump, &parentExtra, parentBlacklist }; { &parentMinidump, &parentExtra, parentBlacklist };
if (!google_breakpad::ExceptionHandler::WriteMinidump( if (!google_breakpad::ExceptionHandler::WriteMinidump(
gExceptionHandler->dump_path(), gExceptionHandler->dump_path(),
#ifndef XP_MACOSX
true, // write exception stream true, // write exception stream
#endif
PairedDumpCallback, PairedDumpCallback,
&parentCtx)) &parentCtx))
return false; return false;
@@ -1805,10 +1843,9 @@ CreatePairedMinidumps(ProcessHandle childPid,
parentMinidump.swap(*parentDump); parentMinidump.swap(*parentDump);
return true; return true;
#endif // XP_MACOSX #endif
} }
#if !defined(XP_MACOSX)
bool bool
UnsetRemoteExceptionHandler() UnsetRemoteExceptionHandler()
{ {
@@ -1816,7 +1853,6 @@ UnsetRemoteExceptionHandler()
gExceptionHandler = NULL; gExceptionHandler = NULL;
return true; return true;
} }
#endif // XP_MACOSX
#endif // MOZ_IPC #endif // MOZ_IPC

View File

@@ -52,6 +52,10 @@
#include <windows.h> #include <windows.h>
#endif #endif
#if defined(XP_MACOSX)
#include <mach/mach.h>
#endif
namespace CrashReporter { namespace CrashReporter {
nsresult SetExceptionHandler(nsILocalFile* aXREDirectory, bool force=false); nsresult SetExceptionHandler(nsILocalFile* aXREDirectory, bool force=false);
nsresult UnsetExceptionHandler(); nsresult UnsetExceptionHandler();
@@ -94,9 +98,13 @@ nsresult SetSubmitReports(PRBool aSubmitReport);
bool TakeMinidumpForChild(PRUint32 childPid, bool TakeMinidumpForChild(PRUint32 childPid,
nsILocalFile** dump NS_OUTPARAM); nsILocalFile** dump NS_OUTPARAM);
#ifdef XP_WIN #if defined(XP_WIN)
typedef HANDLE ProcessHandle; typedef HANDLE ProcessHandle;
typedef DWORD ThreadId; typedef DWORD ThreadId;
#elif defined(XP_MACOSX)
//FIXME: mach_port_t
typedef int ProcessHandle;
typedef mach_port_t ThreadId;
#else #else
typedef int ProcessHandle; typedef int ProcessHandle;
typedef int ThreadId; typedef int ThreadId;
@@ -123,7 +131,7 @@ bool CreatePairedMinidumps(ProcessHandle childPid,
nsILocalFile** childDump NS_OUTPARAM, nsILocalFile** childDump NS_OUTPARAM,
nsILocalFile** parentDump NS_OUTPARAM); nsILocalFile** parentDump NS_OUTPARAM);
# if defined(XP_WIN32) # if defined(XP_WIN32) || defined(XP_MACOSX)
// Parent-side API for children // Parent-side API for children
const char* GetChildNotificationPipe(); const char* GetChildNotificationPipe();
@@ -146,11 +154,6 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd);
// Child-side API // Child-side API
bool SetRemoteExceptionHandler(); bool SetRemoteExceptionHandler();
# elif defined(XP_MACOSX)
// When OOP crash reporting is implemented for Mac, it will almost
// certainly use the same interface as the linux code above. Until
// then, we provide stubs.
void CreateNotificationPipeForChild();
#endif // XP_WIN32 #endif // XP_WIN32
bool UnsetRemoteExceptionHandler(); bool UnsetRemoteExceptionHandler();

View File

@@ -258,11 +258,10 @@ XRE_TakeMinidumpForChild(PRUint32 aChildPid, nsILocalFile** aDump)
return CrashReporter::TakeMinidumpForChild(aChildPid, aDump); return CrashReporter::TakeMinidumpForChild(aChildPid, aDump);
} }
#if !defined(XP_MACOSX)
PRBool PRBool
XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/) XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
{ {
#if defined(XP_WIN) #if defined(XP_WIN) || defined(XP_MACOSX)
return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe)); return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
return CrashReporter::SetRemoteExceptionHandler(); return CrashReporter::SetRemoteExceptionHandler();
@@ -270,7 +269,6 @@ XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
# error "OOP crash reporter unsupported on this platform" # error "OOP crash reporter unsupported on this platform"
#endif #endif
} }
#endif // !XP_MACOSX
#endif // if defined(MOZ_CRASHREPORTER) #endif // if defined(MOZ_CRASHREPORTER)
#if defined(XP_WIN) #if defined(XP_WIN)