зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1697895 - Register the WER runtime exception module in child processes r=KrisWright
This patch sets up a few different things that will be used by the WER runtime exception module when it needs to notify the main process of a child process crash. For every child process we allocate a structure in the main process called WindowsErrorReportingData that contains three things: - The address of the function used to notify the main process that there's a pending minidump for a given child process - The PID of said child process - The name of the minidump that has been generated The first field is filled up by the main process and will be read by the WER process when running the runtime exception module, the second and third fields on the other hand start empty and will be written into by the runtime exception module after it has generated a minidump. I know this sounds scary. It is. But bear with me please. When we register the runtime exception module we can pass it a single pointer-sized parameter but we need to pass it at least another pointer that includes data coming from the child process itself (this one is called InProcessWindowsErrorReportingData). This data currently includes only the process type but will also include certain annotations in the future (e.g. bug 1711418). So here's what we do: we store a pointer to the parent data structure in the child process command-line (cringe) and we read it from the runtime exception module by reading the crashed process command-line arguments and parsing them (double-cringe). Armed with this information the WER runtime exception module can populate the info for the generated minidump and then push it into the main process by calling CreateRemoteThread() (which creates a new thread in the main process, triple-cringe at this point). Differential Revision: https://phabricator.services.mozilla.com/D115379
This commit is contained in:
Родитель
c5d3af901d
Коммит
1a86d1dee4
|
@ -227,7 +227,8 @@ class WindowsProcessLauncher : public BaseProcessLauncher {
|
|||
std::vector<std::string>&& aExtraOpts)
|
||||
: BaseProcessLauncher(aHost, std::move(aExtraOpts)),
|
||||
mProfileDir(aHost->mProfileDir),
|
||||
mCachedNtdllThunk(aHost->sCachedNtDllThunk) {}
|
||||
mCachedNtdllThunk(aHost->sCachedNtDllThunk),
|
||||
mWerDataPointer(&(aHost->mWerData)) {}
|
||||
|
||||
protected:
|
||||
bool SetChannel(IPC::Channel*) override { return true; }
|
||||
|
@ -241,6 +242,7 @@ class WindowsProcessLauncher : public BaseProcessLauncher {
|
|||
nsCOMPtr<nsIFile> mProfileDir;
|
||||
|
||||
const StaticAutoPtr<Buffer<IMAGE_THUNK_DATA>>& mCachedNtdllThunk;
|
||||
CrashReporter::WindowsErrorReportingData const* mWerDataPointer;
|
||||
};
|
||||
typedef WindowsProcessLauncher ProcessLauncher;
|
||||
#endif // XP_WIN
|
||||
|
@ -402,6 +404,9 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
|
|||
mProcessState(CREATING_CHANNEL),
|
||||
#ifdef XP_WIN
|
||||
mGroupId(u"-"),
|
||||
mWerData{.mWerNotifyProc = CrashReporter::WerNotifyProc,
|
||||
.mChildPid = 0,
|
||||
.mMinidumpFile = {}},
|
||||
#endif
|
||||
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
|
||||
mEnableSandboxLogging(false),
|
||||
|
@ -1516,6 +1521,10 @@ bool WindowsProcessLauncher::DoSetup() {
|
|||
mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
|
||||
std::string hStr = std::to_string(h);
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide(hStr));
|
||||
|
||||
char werDataAddress[17] = {};
|
||||
SprintfLiteral(werDataAddress, "%p", mWerDataPointer);
|
||||
mCmdLine->AppendLooseValue(UTF8ToWide(werDataAddress));
|
||||
}
|
||||
|
||||
// Process type
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsXULAppAPI.h" // for GeckoProcessType
|
||||
#include "nsString.h"
|
||||
|
||||
|
@ -224,7 +225,7 @@ class GeckoChildProcessHost : public ChildProcessHost,
|
|||
#ifdef XP_WIN
|
||||
void InitWindowsGroupID();
|
||||
nsString mGroupId;
|
||||
|
||||
CrashReporter::WindowsErrorReportingData mWerData;
|
||||
# ifdef MOZ_SANDBOX
|
||||
RefPtr<AbstractSandboxBroker> mSandboxBroker;
|
||||
std::vector<std::wstring> mAllowedFilesRead;
|
||||
|
|
|
@ -209,7 +209,8 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd) {
|
|||
#endif // !defined(XP_WIN) && !defined(XP_MACOSX)
|
||||
|
||||
bool SetRemoteExceptionHandler(const char* aCrashPipe,
|
||||
uintptr_t aCrashTimeAnnotationFile) {
|
||||
FileHandle aCrashTimeAnnotationFile,
|
||||
ProcessId aParentPid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -223,6 +224,12 @@ bool FinalizeOrphanedMinidump(uint32_t aChildPid, GeckoProcessType aType,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
||||
DWORD WINAPI WerNotifyProc(LPVOID aParameter) { return 0; }
|
||||
|
||||
#endif // defined(XP_WIN)
|
||||
|
||||
ThreadId CurrentThreadId() { return -1; }
|
||||
|
||||
bool TakeMinidump(nsIFile** aResult, bool aMoveToPending) { return false; }
|
||||
|
@ -246,9 +253,9 @@ bool CreateAdditionalChildMinidump(ProcessHandle childPid,
|
|||
bool UnsetRemoteExceptionHandler() { return false; }
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
void SetNotificationPipeForChild(int childCrashFd) {}
|
||||
void SetNotificationPipeForChild(FileHandle childCrashFd) {}
|
||||
|
||||
void SetCrashAnnotationPipeForChild(int childCrashAnnotationFd) {}
|
||||
void SetCrashAnnotationPipeForChild(FileHandle childCrashAnnotationFd) {}
|
||||
|
||||
void AddLibraryMapping(const char* library_name, uintptr_t start_address,
|
||||
size_t mapping_length, size_t file_offset) {}
|
||||
|
|
|
@ -1927,6 +1927,12 @@ static void TeardownAnnotationFacilities() {
|
|||
|
||||
#ifdef XP_WIN
|
||||
|
||||
struct InProcessWindowsErrorReportingData {
|
||||
uint32_t mProcessType;
|
||||
};
|
||||
|
||||
static InProcessWindowsErrorReportingData gInProcessWerData = {};
|
||||
|
||||
bool GetRuntimeExceptionModulePath(wchar_t* aPath, const size_t aLength) {
|
||||
const wchar_t* kModuleName = L"mozwer.dll";
|
||||
DWORD res = GetModuleFileName(nullptr, aPath, aLength);
|
||||
|
@ -1945,27 +1951,21 @@ bool GetRuntimeExceptionModulePath(wchar_t* aPath, const size_t aLength) {
|
|||
|
||||
#endif // XP_WIN
|
||||
|
||||
void RegisterRuntimeExceptionModule(void) {
|
||||
static void RegisterRuntimeExceptionModule(
|
||||
GeckoProcessType aProcessType =
|
||||
GeckoProcessType::GeckoProcessType_Default) {
|
||||
#ifdef XP_WIN
|
||||
gInProcessWerData.mProcessType = aProcessType;
|
||||
const size_t kPathLength = MAX_PATH + 1;
|
||||
wchar_t path[kPathLength] = {};
|
||||
if (GetRuntimeExceptionModulePath(path, kPathLength)) {
|
||||
Unused << WerRegisterRuntimeExceptionModule(path, nullptr);
|
||||
}
|
||||
Unused << WerRegisterRuntimeExceptionModule(path, &gInProcessWerData);
|
||||
|
||||
DWORD dwFlags = 0;
|
||||
if (WerGetFlags(GetCurrentProcess(), &dwFlags) == S_OK) {
|
||||
Unused << WerSetFlags(dwFlags | WER_FAULT_REPORTING_DISABLE_SNAPSHOT_HANG);
|
||||
}
|
||||
#endif // XP_WIN
|
||||
}
|
||||
|
||||
void UnregisterRuntimeExceptionModule(void) {
|
||||
#ifdef XP_WIN
|
||||
const size_t kPathLength = MAX_PATH + 1;
|
||||
wchar_t path[kPathLength] = {};
|
||||
if (GetRuntimeExceptionModulePath(path, kPathLength)) {
|
||||
Unused << WerUnregisterRuntimeExceptionModule(path, nullptr);
|
||||
DWORD dwFlags = 0;
|
||||
if (WerGetFlags(GetCurrentProcess(), &dwFlags) == S_OK) {
|
||||
Unused << WerSetFlags(dwFlags |
|
||||
WER_FAULT_REPORTING_DISABLE_SNAPSHOT_HANG);
|
||||
}
|
||||
}
|
||||
#endif // XP_WIN
|
||||
}
|
||||
|
@ -3525,13 +3525,13 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd) {
|
|||
#endif // defined(XP_LINUX)
|
||||
|
||||
bool SetRemoteExceptionHandler(const char* aCrashPipe,
|
||||
uintptr_t aCrashTimeAnnotationFile) {
|
||||
FileHandle aCrashTimeAnnotationFile) {
|
||||
MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
|
||||
|
||||
RegisterRuntimeExceptionModule(XRE_GetProcessType());
|
||||
InitializeAnnotationFacilities();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
gChildCrashAnnotationReportFd = (FileHandle)aCrashTimeAnnotationFile;
|
||||
gChildCrashAnnotationReportFd = aCrashTimeAnnotationFile;
|
||||
gExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
L"", ChildFilter, ChildMinidumpCallback,
|
||||
nullptr, // no callback context
|
||||
|
@ -3629,6 +3629,48 @@ bool FinalizeOrphanedMinidump(uint32_t aChildPid, GeckoProcessType aType,
|
|||
return WriteExtraFile(id, annotations);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
||||
// Function invoked by the WER runtime exception handler running in an
|
||||
// external process. This function isn't used anywhere inside Gecko directly
|
||||
// but rather invoked via CreateRemoteThread() in the main process.
|
||||
DWORD WINAPI WerNotifyProc(LPVOID aParameter) {
|
||||
const WindowsErrorReportingData* werData =
|
||||
static_cast<const WindowsErrorReportingData*>(aParameter);
|
||||
|
||||
// Hold the mutex until the current dump request is complete, to
|
||||
// prevent UnsetExceptionHandler() from pulling the rug out from
|
||||
// under us.
|
||||
MutexAutoLock safetyLock(*dumpSafetyLock);
|
||||
if (!isSafeToDump || !ShouldReport()) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ProcessId pid = werData->mChildPid;
|
||||
nsCOMPtr<nsIFile> minidump;
|
||||
if (!GetPendingDir(getter_AddRefs(minidump))) {
|
||||
return S_OK;
|
||||
}
|
||||
xpstring minidump_native_name(werData->mMinidumpFile,
|
||||
werData->mMinidumpFile + 40);
|
||||
nsString minidump_name(minidump_native_name.c_str());
|
||||
minidump->Append(minidump_name);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(*dumpMapLock);
|
||||
ChildProcessData* pd = pidToMinidump->PutEntry(pid);
|
||||
MOZ_ASSERT(!pd->minidump);
|
||||
pd->minidump = minidump;
|
||||
pd->sequence = ++crashSequence;
|
||||
pd->annotations = MakeUnique<AnnotationTable>();
|
||||
PopulateContentProcessAnnotations(*(pd->annotations));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif // XP_WIN
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CreateMinidumpsAndPair() and helpers
|
||||
//
|
||||
|
|
|
@ -165,6 +165,20 @@ nsresult SetSubmitReports(bool aSubmitReport);
|
|||
|
||||
// Out-of-process crash reporter API.
|
||||
|
||||
#ifdef XP_WIN
|
||||
// This data is stored in the parent process, there is one copy for each child
|
||||
// process. The mChildPid and mMinidumpFile fields are filled by the WER runtime
|
||||
// exception module when the associated child process crashes.
|
||||
struct WindowsErrorReportingData {
|
||||
// Points to the WerNotifyProc function.
|
||||
LPTHREAD_START_ROUTINE mWerNotifyProc;
|
||||
// PID of the child process that crashed.
|
||||
DWORD mChildPid;
|
||||
// Filename of the generated minidump; this is not a 0-terminated string
|
||||
char mMinidumpFile[40];
|
||||
};
|
||||
#endif // XP_WIN
|
||||
|
||||
// Initializes out-of-process crash reporting. This method must be called
|
||||
// before the platform-specific notification pipe APIs are called. If called
|
||||
// from off the main thread, this method will synchronously proxy to the main
|
||||
|
@ -300,7 +314,7 @@ void UnregisterInjectorCallback(DWORD processID);
|
|||
// 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.
|
||||
// the server at |childCrashRemapFd|. Return true if successful.
|
||||
//
|
||||
// If crash reporting is disabled, both outparams will be set to -1
|
||||
// and |true| will be returned.
|
||||
|
@ -308,16 +322,22 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd);
|
|||
|
||||
#endif // XP_WIN
|
||||
|
||||
// Windows Error Reporting helper
|
||||
#if defined(XP_WIN)
|
||||
DWORD WINAPI WerNotifyProc(LPVOID aParameter);
|
||||
#endif
|
||||
|
||||
// Child-side API
|
||||
bool SetRemoteExceptionHandler(const char* aCrashPipe = nullptr,
|
||||
uintptr_t aCrashTimeAnnotationFile = 0);
|
||||
bool SetRemoteExceptionHandler(
|
||||
const char* aCrashPipe = nullptr,
|
||||
FileHandle aCrashTimeAnnotationFile = kInvalidFileHandle);
|
||||
bool UnsetRemoteExceptionHandler();
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
// Android creates child process as services so we must explicitly set
|
||||
// the handle for the pipe since it can't get remapped to a default value.
|
||||
void SetNotificationPipeForChild(int childCrashFd);
|
||||
void SetCrashAnnotationPipeForChild(int childCrashAnnotationFd);
|
||||
void SetNotificationPipeForChild(FileHandle childCrashFd);
|
||||
void SetCrashAnnotationPipeForChild(FileHandle childCrashAnnotationFd);
|
||||
#endif
|
||||
|
||||
// Annotates the crash report with the name of the calling thread.
|
||||
|
|
|
@ -506,28 +506,27 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
|
|||
|
||||
bool exceptionHandlerIsSet = false;
|
||||
if (!CrashReporter::IsDummy()) {
|
||||
CrashReporter::FileHandle crashTimeAnnotationFile =
|
||||
CrashReporter::kInvalidFileHandle;
|
||||
#if defined(XP_WIN)
|
||||
if (aArgc < 1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Pop the first argument, this is used by the WER runtime exception module
|
||||
// which reads it from the command-line so we can just discard it here.
|
||||
--aArgc;
|
||||
|
||||
const char* const crashTimeAnnotationArg = aArgv[--aArgc];
|
||||
uintptr_t crashTimeAnnotationFile =
|
||||
static_cast<uintptr_t>(std::stoul(std::string(crashTimeAnnotationArg)));
|
||||
crashTimeAnnotationFile = reinterpret_cast<CrashReporter::FileHandle>(
|
||||
std::stoul(std::string(crashTimeAnnotationArg)));
|
||||
#endif
|
||||
|
||||
if (aArgc < 1) return NS_ERROR_FAILURE;
|
||||
const char* const crashReporterArg = aArgv[--aArgc];
|
||||
|
||||
if (IsCrashReporterEnabled(crashReporterArg)) {
|
||||
#if defined(XP_MACOSX)
|
||||
exceptionHandlerIsSet =
|
||||
CrashReporter::SetRemoteExceptionHandler(crashReporterArg);
|
||||
#elif defined(XP_WIN)
|
||||
exceptionHandlerIsSet = CrashReporter::SetRemoteExceptionHandler(
|
||||
crashReporterArg, crashTimeAnnotationFile);
|
||||
#else
|
||||
exceptionHandlerIsSet = CrashReporter::SetRemoteExceptionHandler();
|
||||
#endif
|
||||
|
||||
if (!exceptionHandlerIsSet) {
|
||||
// Bug 684322 will add better visibility into this condition
|
||||
|
|
Загрузка…
Ссылка в новой задаче