Bug 516759: Use OOP crash reporting in Gecko. r=luser

--HG--
extra : rebase_source : 1949d23a5ce0c15c266d9e67e6a6be7d650a51df
This commit is contained in:
Chris Jones 2010-01-12 15:14:38 -06:00
parent 8ecc380a35
commit 6d065b2d57
9 changed files with 281 additions and 4 deletions

View File

@ -54,6 +54,29 @@
int
main(int argc, char* argv[])
{
#if defined(MOZ_CRASHREPORTER)
if (argc < 2)
return 1;
const char* const crashReporterArg = argv[--argc];
# if defined(XP_WIN)
// on windows, |crashReporterArg| is the named pipe on which the
// server is listening for requests, or "-" if crash reporting is
// disabled.
if (0 != strcmp("-", crashReporterArg)
&& !XRE_SetRemoteExceptionHandler(crashReporterArg))
return 1;
# elif defined(OS_LINUX)
// on POSIX, |crashReporterArg| is "true" if crash reporting is
// enabled, false otherwise
if (0 != strcmp("false", crashReporterArg)
&& !XRE_SetRemoteExceptionHandler())
return 1;
# else
# error "OOP crash reporting unsupported on this platform"
# endif
#endif // if defined(MOZ_CRASHREPORTER)
#if defined(XP_WIN) && defined(DEBUG_bent)
MessageBox(NULL, L"Hi", L"Hi", MB_OK);
#endif

View File

@ -46,6 +46,11 @@
#include "prprf.h"
#if defined(OS_LINUX)
# define XP_LINUX 1
#endif
#include "nsExceptionHandler.h"
#include "mozilla/ipc/GeckoThread.h"
using mozilla::MonitorAutoEnter;
@ -179,7 +184,7 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
int srcChannelFd, dstChannelFd;
channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
// no need for kProcessChannelID, the child process inherits the
// other end of the socketpair() from us
@ -192,6 +197,22 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
childArgv.push_back(pidstring);
childArgv.push_back(childProcessType);
#if defined(MOZ_CRASHREPORTER)
int childCrashFd, childCrashRemapFd;
if (!CrashReporter::CreateNotificationPipeForChild(
&childCrashFd, &childCrashRemapFd))
return false;
if (0 <= childCrashFd) {
mFileMap.push_back(std::pair<int,int>(childCrashFd, childCrashRemapFd));
// "true" == crash reporting enabled
childArgv.push_back("true");
}
else {
// "false" == crash reporting disabled
childArgv.push_back("false");
}
#endif
base::LaunchApp(childArgv, mFileMap, false, &process);
//--------------------------------------------------
@ -214,6 +235,10 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
cmdLine.AppendLooseValue(UTF8ToWide(pidstring));
cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
#if defined(MOZ_CRASHREPORTER)
cmdLine.AppendLooseValue(
UTF8ToWide(CrashReporter::GetChildNotificationPipe().BeginReading()));
#endif
base::LaunchApp(cmdLine, false, false, &process);

View File

@ -41,6 +41,8 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/crashreporter
MODULE = ipc
LIBRARY_NAME = mozipc_s
FORCE_STATIC_LIB = 1

View File

@ -48,10 +48,11 @@ LIBRARY_NAME = crash_generation_s
LOCAL_INCLUDES = -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src
DEFINES += -DUNICODE -D_UNICODE
#XXX: We're not currently building the other parts,
# which would only be needed on the server side of the equation.
CPPSRCS = \
client_info.cc \
crash_generation_client.cc \
crash_generation_server.cc \
minidump_generator.cc \
$(NULL)
# need static lib

View File

@ -43,7 +43,9 @@
#undef WIN32_LEAN_AND_MEAN
#endif
#include "client/windows/crash_generation/crash_generation_server.h"
#include "client/windows/handler/exception_handler.h"
#include <DbgHelp.h>
#include <string.h>
#elif defined(XP_MACOSX)
#include "client/mac/handler/exception_handler.h"
@ -54,6 +56,7 @@
#include <unistd.h>
#include "mac_utils.h"
#elif defined(XP_LINUX)
#include "client/linux/crash_generation/crash_generation_server.h"
#include "client/linux/handler/exception_handler.h"
#include <fcntl.h>
#include <sys/types.h>
@ -77,6 +80,9 @@
#include "nsILocalFile.h"
#include "nsDataHashtable.h"
using google_breakpad::CrashGenerationServer;
using google_breakpad::ClientInfo;
namespace CrashReporter {
#ifdef XP_WIN32
@ -141,6 +147,22 @@ static nsDataHashtable<nsCStringHashKey,nsCString>* crashReporterAPIData_Hash;
static nsCString* crashReporterAPIData = nsnull;
static nsCString* notesField = nsnull;
// OOP crash reporting
static CrashGenerationServer* crashServer; // chrome process has this
#if defined(XP_WIN)
// 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.
static const char kNullNotifyPipe[] = "-";
static nsCString* childCrashNotifyPipe;
#elif defined(XP_LINUX)
static int serverSocketFd = -1;
static int clientSocketFd = -1;
static const int kMagicChildCrashReportFd = 42;
#endif
static XP_CHAR*
Concat(XP_CHAR* str, const XP_CHAR* toAppend, int* size)
{
@ -909,4 +931,158 @@ nsresult AppendObjCExceptionInfoToAppNotes(void *inException)
}
#endif
//-----------------------------------------------------------------------------
// Out-of-process crash reporting API wrappers
static void
OnChildProcessDumpRequested(void* aContext,
const ClientInfo* aClientInfo,
#if defined(XP_WIN)
const std::wstring*
#else
const std::string*
#endif
aFilePath)
{
printf("CHILD DUMP REQUEST\n");
}
static bool
OOPInitialized()
{
return crashServer != NULL;
}
static void
OOPInit()
{
NS_ABORT_IF_FALSE(!OOPInitialized(),
"OOP crash reporter initialized more than once!");
NS_ABORT_IF_FALSE(gExceptionHandler != NULL,
"attempt to initialize OOP crash reporter before in-process crashreporter!");
#if defined(XP_WIN)
// this is a CString to make it more convenient to pass on the
// command line
childCrashNotifyPipe =
new nsCString("\\\\.\\pipe\\gecko-crash-server-pipe.");
long pid = static_cast<long>(::GetCurrentProcessId());
childCrashNotifyPipe->AppendInt(pid);
const std::wstring dumpPath = gExceptionHandler->dump_path();
crashServer = new CrashGenerationServer(
NS_ConvertASCIItoUTF16(*childCrashNotifyPipe).BeginReading(),
NULL, // default security attributes
NULL, NULL, // we don't care about process connect here
OnChildProcessDumpRequested, NULL,
NULL, NULL, // we don't care about process exit here
true, // automatically generate dumps
&dumpPath);
#elif defined(XP_LINUX)
if (!CrashGenerationServer::CreateReportChannel(&serverSocketFd,
&clientSocketFd))
NS_RUNTIMEABORT("can't create crash reporter socketpair()");
const std::string dumpPath = gExceptionHandler->dump_path();
crashServer = new CrashGenerationServer(
serverSocketFd,
OnChildProcessDumpRequested, NULL,
NULL, NULL, // we don't care about process exit here
true, // automatically generate dumps
&dumpPath);
#endif
if (!crashServer->Start())
NS_RUNTIMEABORT("can't start crash reporter server()");
}
#if defined(XP_WIN)
// Parent-side API for children
nsCString
GetChildNotificationPipe()
{
if (!GetEnabled())
return nsDependentCString(kNullNotifyPipe);
if (!OOPInitialized())
OOPInit();
return *childCrashNotifyPipe;
}
// Child-side API
bool
SetRemoteExceptionHandler(const nsACString& crashPipe)
{
// crash reporting is disabled
if (crashPipe.Equals(kNullNotifyPipe))
return true;
NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
gExceptionHandler = new google_breakpad::
ExceptionHandler(L"",
NULL, // no filter callback
NULL, // no minidump callback
NULL, // no callback context
google_breakpad::ExceptionHandler::HANDLER_ALL,
MiniDumpNormal,
NS_ConvertASCIItoUTF16(crashPipe).BeginReading(),
NULL);
// we either do remote or nothing, no fallback to regular crash reporting
return gExceptionHandler->IsOutOfProcess();
}
//--------------------------------------------------
#elif defined(XP_UNIX)
// Parent-side API for children
bool
CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd)
{
if (!GetEnabled()) {
*childCrashFd = -1;
*childCrashRemapFd = -1;
return true;
}
if (!OOPInitialized())
OOPInit();
*childCrashFd = clientSocketFd;
*childCrashRemapFd = kMagicChildCrashReportFd;
return true;
}
// Child-side API
bool
SetRemoteExceptionHandler()
{
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
kMagicChildCrashReportFd);
// we either do remote or nothing, no fallback to regular crash reporting
return gExceptionHandler->IsOutOfProcess();
}
#endif
bool
UnsetRemoteExceptionHandler()
{
delete gExceptionHandler;
gExceptionHandler = NULL;
return true;
}
} // namespace CrashReporter

View File

@ -64,10 +64,33 @@ nsresult SetupExtraData(nsILocalFile* aAppDataDirectory,
const nsACString& aBuildID);
#ifdef XP_WIN32
nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo);
// Parent-side API for children
nsCString GetChildNotificationPipe();
// Child-side API
bool SetRemoteExceptionHandler(const nsACString& crashPipe);
#endif
#ifdef XP_MACOSX
nsresult AppendObjCExceptionInfoToAppNotes(void *inException);
#endif
#ifdef XP_LINUX
// Parent-side API for children
// Set the outparams for crash reporter server's fd (|childCrashFd|)
// and the magic fd number it should be remapped to
// (|childCrashRemapFd|) before exec() in the child process.
// |SetRemoteExceptionHandler()| in the child process expects to find
// the server at |childCrashRemapFd|. Return true iff successful.
//
// If crash reporting is disabled, both outparams will be set to -1
// and |true| will be returned.
bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd);
// Child-side API
bool SetRemoteExceptionHandler();
#endif
bool UnsetRemoteExceptionHandler();
}
#endif /* nsExceptionHandler_h__ */

View File

@ -174,7 +174,10 @@ include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES += -I$(topsrcdir)/dom/ipc
LOCAL_INCLUDES += \
-I$(topsrcdir)/dom/ipc \
-I$(topsrcdir)/toolkit/crashreporter \
$(NULL)
ifdef BUILD_STATIC_LIBS
export::

View File

@ -55,10 +55,15 @@
#include "nsIToolkitChromeRegistry.h"
#include "nsIToolkitProfile.h"
#if defined(OS_LINUX)
# define XP_LINUX
#endif
#include "nsAppDirectoryServiceDefs.h"
#include "nsAppRunner.h"
#include "nsAutoRef.h"
#include "nsDirectoryServiceDefs.h"
#include "nsExceptionHandler.h"
#include "nsStaticComponents.h"
#include "nsString.h"
#include "nsThreadUtils.h"
@ -242,6 +247,20 @@ GeckoProcessType sChildProcessType = GeckoProcessType_Default;
static MessageLoop* sIOMessageLoop;
#if defined(MOZ_CRASHREPORTER)
PRBool
XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
{
#if defined(XP_WIN)
return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
#elif defined(OS_LINUX)
return CrashReporter::SetRemoteExceptionHandler();
#else
# error "OOP crash reporter unsupported on this platform"
#endif
}
#endif // if defined(MOZ_CRASHREPORTER)
nsresult
XRE_InitChildProcess(int aArgc,
char* aArgv[],

View File

@ -449,6 +449,11 @@ XRE_API(const char*,
XRE_API(GeckoProcessType,
XRE_StringToChildProcessType, (const char* aProcessTypeString))
#if defined(MOZ_CRASHREPORTER)
XRE_API(PRBool,
XRE_SetRemoteExceptionHandler, (const char* aPipe=0))
#endif
XRE_API(nsresult,
XRE_InitChildProcess, (int aArgc,
char* aArgv[],