mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 769048 part E - Core crashreporter support for injecting a crashreporter DLL into an arbitrary process and callbacks for notifications when that process has crashed, r=ehsan
--HG-- extra : rebase_source : eec98ad1d72106a34dfcd0764d85092a0725565c
This commit is contained in:
parent
4bef88b22e
commit
e7513f945a
84
toolkit/crashreporter/InjectCrashReporter.cpp
Normal file
84
toolkit/crashreporter/InjectCrashReporter.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "InjectCrashReporter.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "client/windows/crash_generation/crash_generation_client.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "LoadLibraryRemote.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
using google_breakpad::CrashGenerationClient;
|
||||
using CrashReporter::GetChildNotificationPipe;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
InjectCrashRunnable::InjectCrashRunnable(DWORD pid)
|
||||
: mPID(pid)
|
||||
{
|
||||
nsCOMPtr<nsIFile> dll;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(dll));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
dll->Append(NS_LITERAL_STRING("breakpadinjector.dll"));
|
||||
dll->GetPath(mInjectorPath);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
InjectCrashRunnable::Run()
|
||||
{
|
||||
if (mInjectorPath.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
nsAutoHandle hProcess(
|
||||
OpenProcess(PROCESS_CREATE_THREAD |
|
||||
PROCESS_QUERY_INFORMATION |
|
||||
PROCESS_DUP_HANDLE |
|
||||
PROCESS_VM_OPERATION |
|
||||
PROCESS_VM_WRITE |
|
||||
PROCESS_VM_READ, FALSE, mPID));
|
||||
if (!hProcess) {
|
||||
NS_WARNING("Unable to open remote process handle for crashreporter injection.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void* proc = LoadRemoteLibraryAndGetAddress(hProcess, mInjectorPath.get(),
|
||||
"Start");
|
||||
if (!proc) {
|
||||
NS_WARNING("Unable to inject crashreporter DLL.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HANDLE hRemotePipe =
|
||||
CrashGenerationClient::DuplicatePipeToClientProcess(
|
||||
NS_ConvertASCIItoUTF16(GetChildNotificationPipe()).get(),
|
||||
hProcess);
|
||||
if (INVALID_HANDLE_VALUE == hRemotePipe) {
|
||||
NS_WARNING("Unable to duplicate crash reporter pipe to process.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoHandle hThread(CreateRemoteThread(hProcess, NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) proc,
|
||||
(void*) hRemotePipe, 0, NULL));
|
||||
if (!hThread) {
|
||||
NS_WARNING("Unable to CreateRemoteThread");
|
||||
|
||||
// We have to close the remote pipe or else our crash generation client
|
||||
// will be stuck unable to accept other remote requests.
|
||||
HANDLE toClose = INVALID_HANDLE_VALUE;
|
||||
if (DuplicateHandle(hProcess, hRemotePipe, ::GetCurrentProcess(),
|
||||
&toClose, 0, FALSE,
|
||||
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
|
||||
CloseHandle(toClose);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
23
toolkit/crashreporter/InjectCrashReporter.h
Normal file
23
toolkit/crashreporter/InjectCrashReporter.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include <windows.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class InjectCrashRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
InjectCrashRunnable(DWORD pid);
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
DWORD mPID;
|
||||
nsString mInjectorPath;
|
||||
};
|
||||
|
||||
} // Namespace mozilla
|
@ -90,6 +90,7 @@ CPPSRCS = \
|
||||
ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
CPPSRCS += \
|
||||
LoadLibraryRemote.cpp \
|
||||
InjectCrashReporter.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
@ -62,6 +62,11 @@
|
||||
#error "Not yet implemented for this platform"
|
||||
#endif // defined(XP_WIN32)
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
#include "InjectCrashReporter.h"
|
||||
using mozilla::InjectCrashRunnable;
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <prenv.h>
|
||||
@ -218,6 +223,23 @@ static Mutex* dumpMapLock;
|
||||
typedef nsInterfaceHashtable<nsUint32HashKey, nsIFile> ChildMinidumpMap;
|
||||
static ChildMinidumpMap* pidToMinidump;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
static nsIThread* sInjectorThread;
|
||||
typedef nsDataHashtable<nsUint32HashKey, InjectorCrashCallback*> InjectorPIDMap;
|
||||
static InjectorPIDMap* pidToInjectorCallback;
|
||||
|
||||
class ReportInjectedCrash : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReportInjectedCrash(PRUint32 pid) : mPID(pid) { }
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
PRUint32 mPID;
|
||||
};
|
||||
#endif // MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
// Crashreporter annotations that we don't send along in subprocess
|
||||
// reports
|
||||
static const char* kSubprocessBlacklist[] = {
|
||||
@ -1902,8 +1924,13 @@ OnChildProcessDumpRequested(void* aContext,
|
||||
aClientInfo->pid();
|
||||
#endif
|
||||
|
||||
MutexAutoLock lock(*dumpMapLock);
|
||||
pidToMinidump->Put(pid, minidump);
|
||||
{
|
||||
MutexAutoLock lock(*dumpMapLock);
|
||||
pidToMinidump->Put(pid, minidump);
|
||||
}
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
NS_DispatchToMainThread(new ReportInjectedCrash(pid));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1986,6 +2013,16 @@ OOPDeinit()
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
if (sInjectorThread) {
|
||||
sInjectorThread->Shutdown();
|
||||
NS_RELEASE(sInjectorThread);
|
||||
}
|
||||
|
||||
delete pidToInjectorCallback;
|
||||
pidToInjectorCallback = NULL;
|
||||
#endif
|
||||
|
||||
delete crashServer;
|
||||
crashServer = NULL;
|
||||
|
||||
@ -2016,6 +2053,67 @@ GetChildNotificationPipe()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
void
|
||||
InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb)
|
||||
{
|
||||
if (!GetEnabled())
|
||||
return;
|
||||
|
||||
if (!OOPInitialized())
|
||||
OOPInit();
|
||||
|
||||
if (!pidToInjectorCallback) {
|
||||
pidToInjectorCallback = new InjectorPIDMap;
|
||||
pidToInjectorCallback->Init();
|
||||
}
|
||||
|
||||
if (!sInjectorThread) {
|
||||
if (NS_FAILED(NS_NewThread(&sInjectorThread)))
|
||||
return;
|
||||
}
|
||||
|
||||
pidToInjectorCallback->Put(processID, cb);
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = new InjectCrashRunnable(processID);
|
||||
sInjectorThread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ReportInjectedCrash::Run()
|
||||
{
|
||||
// Crash reporting may have been disabled after this method was dispatched
|
||||
if (!pidToInjectorCallback)
|
||||
return NS_OK;
|
||||
|
||||
InjectorCrashCallback* cb = pidToInjectorCallback->Get(mPID);
|
||||
if (!cb)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIFile> minidump;
|
||||
if (!TakeMinidumpForChild(mPID, getter_AddRefs(minidump))) {
|
||||
NS_WARNING("No minidump for crash notification.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsString id;
|
||||
GetIDFromMinidump(minidump, id);
|
||||
|
||||
cb->OnCrash(mPID, id);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
UnregisterInjectorCallback(DWORD processID)
|
||||
{
|
||||
if (!OOPInitialized())
|
||||
return;
|
||||
|
||||
pidToInjectorCallback->Remove(processID);
|
||||
}
|
||||
|
||||
#endif // MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Child-side API
|
||||
bool
|
||||
|
@ -111,6 +111,22 @@ bool CreatePairedMinidumps(ProcessHandle childPid,
|
||||
// Parent-side API for children
|
||||
const char* GetChildNotificationPipe();
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
// Inject a crash report client into an arbitrary process, and inform the
|
||||
// callback object when it crashes. Parent process only.
|
||||
|
||||
class InjectorCrashCallback
|
||||
{
|
||||
public:
|
||||
InjectorCrashCallback() { }
|
||||
|
||||
virtual void OnCrash(DWORD processID, const nsAString& aDumpID) = 0;
|
||||
};
|
||||
|
||||
void InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb);
|
||||
void UnregisterInjectorCallback(DWORD processID);
|
||||
#endif
|
||||
|
||||
// Child-side API
|
||||
bool SetRemoteExceptionHandler(const nsACString& crashPipe);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user