mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central into moizilla-inbound
This commit is contained in:
commit
910d058e01
@ -9,11 +9,13 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = chrome components locales app
|
||||
DIRS = chrome components locales
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
DIRS += $(DEPTH)/xulrunner/tools/redit
|
||||
endif
|
||||
|
||||
DIRS += app
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/testing/testsuite-targets.mk
|
||||
|
@ -1,23 +0,0 @@
|
||||
#GONK_TOOLCHAIN_VERSION=0
|
||||
#TOOLCHAIN_HOST=linux-x86
|
||||
#export GONK_PRODUCT=generic
|
||||
#gonk="/home/cjones/mozilla/gonk-toolchain-$GONK_TOOLCHAIN_VERSION"
|
||||
|
||||
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j8"
|
||||
|
||||
ac_add_options --enable-application=b2g
|
||||
|
||||
ac_add_options --target=arm-android-eabi
|
||||
ac_add_options --with-gonk="$gonk"
|
||||
ac_add_options --with-gonk-toolchain-prefix="$gonk/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-eabi-4.4.3/bin/arm-eabi-"
|
||||
ac_add_options --with-endian=little
|
||||
ac_add_options --disable-elf-hack
|
||||
ac_add_options --enable-debug-symbols
|
||||
ac_add_options --enable-profiling
|
||||
ac_add_options --with-ccache
|
||||
ac_add_options --enable-marionette
|
||||
|
||||
# Enable dump() from JS.
|
||||
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
@ -1,23 +0,0 @@
|
||||
#GONK_TOOLCHAIN_VERSION=0
|
||||
#TOOLCHAIN_HOST=linux-x86
|
||||
#export GONK_PRODUCT=generic
|
||||
#gonk="/home/cjones/mozilla/gonk-toolchain-$GONK_TOOLCHAIN_VERSION"
|
||||
|
||||
mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-b2g
|
||||
|
||||
mk_add_options MOZ_MAKE_FLAGS="-j8"
|
||||
|
||||
ac_add_options --enable-application=b2g
|
||||
|
||||
ac_add_options --target=arm-android-eabi
|
||||
ac_add_options --with-gonk="$gonk"
|
||||
ac_add_options --with-gonk-toolchain-prefix="$gonk/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-eabi-4.4.3/bin/arm-eabi-"
|
||||
ac_add_options --with-endian=little
|
||||
ac_add_options --disable-elf-hack
|
||||
ac_add_options --enable-debug-symbols
|
||||
ac_add_options --enable-profiling
|
||||
ac_add_options --with-ccache
|
||||
ac_add_options --enable-marionette
|
||||
|
||||
# Enable dump() from JS.
|
||||
export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
|
@ -6,8 +6,6 @@ ac_add_options --enable-signmar
|
||||
# Nightlies only since this has a cost in performance
|
||||
#ac_add_options --enable-js-diagnostics
|
||||
|
||||
. $topsrcdir/build/unix/mozconfig.linux
|
||||
|
||||
# Avoid dependency on libstdc++ 4.5
|
||||
ac_add_options --enable-stdcxx-compat
|
||||
|
@ -661,6 +661,9 @@ bin/libfreebl_32int64_3.so
|
||||
#endif
|
||||
#endif
|
||||
@BINPATH@/crashreporter-override.ini
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
@BINPATH@/breakpadinjector.dll
|
||||
#endif
|
||||
#endif
|
||||
|
||||
; [Extensions]
|
||||
|
@ -155,6 +155,7 @@ LIBJPEG_TURBO_ARM_ASM = @LIBJPEG_TURBO_ARM_ASM@
|
||||
NS_PRINTING = @NS_PRINTING@
|
||||
MOZ_PDF_PRINTING = @MOZ_PDF_PRINTING@
|
||||
MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
|
||||
MOZ_CRASHREPORTER_INJECTOR = @MOZ_CRASHREPORTER_INJECTOR@
|
||||
MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
|
||||
MOC = @MOC@
|
||||
RCC = @RCC@
|
||||
|
@ -5858,6 +5858,11 @@ if test -n "$MOZ_CRASHREPORTER"; then
|
||||
if (test "$OS_ARCH" != "$HOST_OS_ARCH"); then
|
||||
AC_MSG_ERROR([Breakpad tools do not support compiling on $HOST_OS_ARCH while targeting $OS_ARCH. Use --disable-crashreporter.])
|
||||
fi
|
||||
|
||||
if test "$OS_ARCH" == "WINNT" -a -z "$HAVE_64BIT_OS"; then
|
||||
MOZ_CRASHREPORTER_INJECTOR=1
|
||||
AC_DEFINE(MOZ_CRASHREPORTER_INJECTOR)
|
||||
fi
|
||||
fi
|
||||
|
||||
MOZ_ARG_WITH_STRING(crashreporter-enable-percent,
|
||||
@ -8327,6 +8332,7 @@ AC_SUBST(MOZ_SPELLCHECK)
|
||||
AC_SUBST(MOZ_JAVA_COMPOSITOR)
|
||||
AC_SUBST(MOZ_ONLY_TOUCH_EVENTS)
|
||||
AC_SUBST(MOZ_CRASHREPORTER)
|
||||
AC_SUBST(MOZ_CRASHREPORTER_INJECTOR)
|
||||
AC_SUBST(MOZ_MAINTENANCE_SERVICE)
|
||||
AC_SUBST(MOZ_VERIFY_MAR_SIGNATURE)
|
||||
AC_SUBST(MOZ_ENABLE_SIGNMAR)
|
||||
|
@ -102,6 +102,10 @@ PluginModuleParent::PluginModuleParent(const char* aFilePath)
|
||||
, mNPNIface(NULL)
|
||||
, mPlugin(NULL)
|
||||
, mTaskFactory(this)
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
, mFlashProcess1(0)
|
||||
, mFlashProcess2(0)
|
||||
#endif
|
||||
{
|
||||
NS_ASSERTION(mSubprocess, "Out of memory!");
|
||||
|
||||
@ -127,6 +131,13 @@ PluginModuleParent::~PluginModuleParent()
|
||||
mSubprocess = nsnull;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
if (mFlashProcess1)
|
||||
CrashReporter::UnregisterInjectorCallback(mFlashProcess1);
|
||||
if (mFlashProcess2)
|
||||
CrashReporter::UnregisterInjectorCallback(mFlashProcess2);
|
||||
#endif
|
||||
|
||||
Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
|
||||
Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
|
||||
}
|
||||
@ -151,9 +162,12 @@ PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& no
|
||||
notes.Put(CS("PluginName"), CS(""));
|
||||
notes.Put(CS("PluginVersion"), CS(""));
|
||||
|
||||
const nsString& hangID = CrashReporter()->HangID();
|
||||
CrashReporterParent* crashReporter = CrashReporter();
|
||||
if (crashReporter) {
|
||||
const nsString& hangID = crashReporter->HangID();
|
||||
if (!hangID.IsEmpty())
|
||||
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
|
||||
}
|
||||
}
|
||||
#endif // MOZ_CRASHREPORTER
|
||||
|
||||
@ -186,6 +200,7 @@ bool
|
||||
PluginModuleParent::ShouldContinueFromReplyTimeout()
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
if (mPluginDumpID.IsEmpty()) {
|
||||
CrashReporterParent* crashReporter = CrashReporter();
|
||||
if (crashReporter->GeneratePairedMinidump(this)) {
|
||||
mBrowserDumpID = crashReporter->ParentDumpID();
|
||||
@ -198,6 +213,7 @@ PluginModuleParent::ShouldContinueFromReplyTimeout()
|
||||
} else {
|
||||
NS_WARNING("failed to capture paired minidumps from hang");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// this must run before the error notification from the channel,
|
||||
@ -217,7 +233,6 @@ PluginModuleParent::ShouldContinueFromReplyTimeout()
|
||||
CrashReporterParent*
|
||||
PluginModuleParent::CrashReporter()
|
||||
{
|
||||
MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
|
||||
return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
|
||||
}
|
||||
#endif
|
||||
@ -234,14 +249,18 @@ PluginModuleParent::ActorDestroy(ActorDestroyReason why)
|
||||
notes.Init(4);
|
||||
WriteExtraDataForMinidump(notes);
|
||||
|
||||
if (crashReporter->GenerateCrashReport(this, ¬es)) {
|
||||
if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
|
||||
crashReporter->GenerateHangCrashReport(¬es);
|
||||
}
|
||||
else if (!mPluginDumpID.IsEmpty()) {
|
||||
// Nothing to do, we've already written this minidump in
|
||||
// PluginModuleParent::OnCrash
|
||||
}
|
||||
else if (crashReporter->GenerateCrashReport(this, ¬es)) {
|
||||
mPluginDumpID = crashReporter->ChildDumpID();
|
||||
PLUGIN_LOG_DEBUG(("got child minidump: %s",
|
||||
NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
|
||||
}
|
||||
else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
|
||||
crashReporter->GenerateHangCrashReport(¬es);
|
||||
}
|
||||
else {
|
||||
NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
|
||||
}
|
||||
@ -761,6 +780,10 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
|
||||
unused << SendSetAudioSessionData(id, sessionName, iconPath);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
InitializeInjector();
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
@ -1162,3 +1185,102 @@ PluginModuleParent::RecvNPN_ReloadPlugins(const bool& aReloadPages)
|
||||
mozilla::plugins::parent::_reloadplugins(aReloadPages);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
|
||||
// We only add the crash reporter to subprocess which have the filename
|
||||
// FlashPlayerPlugin*
|
||||
#define FLASH_PROCESS_PREFIX "FLASHPLAYERPLUGIN"
|
||||
|
||||
static DWORD
|
||||
GetFlashChildOfPID(DWORD pid, HANDLE snapshot)
|
||||
{
|
||||
PROCESSENTRY32 entry = {
|
||||
sizeof(entry)
|
||||
};
|
||||
for (BOOL ok = Process32First(snapshot, &entry);
|
||||
ok;
|
||||
ok = Process32Next(snapshot, &entry)) {
|
||||
if (entry.th32ParentProcessID == pid) {
|
||||
nsString name(entry.szExeFile);
|
||||
ToUpperCase(name);
|
||||
if (StringBeginsWith(name, NS_LITERAL_STRING(FLASH_PROCESS_PREFIX))) {
|
||||
return entry.th32ProcessID;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We only look for child processes of the Flash plugin, NPSWF*
|
||||
#define FLASH_PLUGIN_PREFIX "NPSWF"
|
||||
|
||||
void
|
||||
PluginModuleParent::InitializeInjector()
|
||||
{
|
||||
if (!Preferences::GetBool("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", false))
|
||||
return;
|
||||
|
||||
nsCString path(Process()->GetPluginFilePath().c_str());
|
||||
ToUpperCase(path);
|
||||
PRInt32 lastSlash = path.RFindCharInSet("\\/");
|
||||
if (kNotFound == lastSlash)
|
||||
return;
|
||||
|
||||
if (!StringBeginsWith(Substring(path, lastSlash + 1),
|
||||
NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
|
||||
return;
|
||||
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (INVALID_HANDLE_VALUE == snapshot)
|
||||
return;
|
||||
|
||||
DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
|
||||
mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, snapshot);
|
||||
if (mFlashProcess1) {
|
||||
InjectCrashReporterIntoProcess(mFlashProcess1, this);
|
||||
|
||||
mFlashProcess2 = GetFlashChildOfPID(mFlashProcess1, snapshot);
|
||||
if (mFlashProcess2) {
|
||||
InjectCrashReporterIntoProcess(mFlashProcess2, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleParent::OnCrash(DWORD processID, const nsAString& aDumpID)
|
||||
{
|
||||
if (!mPluginDumpID.IsEmpty()) {
|
||||
// One process has already crashed: we assume that the first-to-crash
|
||||
// is the interesting one
|
||||
return;
|
||||
}
|
||||
|
||||
mPluginDumpID = aDumpID;
|
||||
|
||||
CrashReporter::AnnotationTable notes;
|
||||
notes.Init(4);
|
||||
WriteExtraDataForMinidump(notes);
|
||||
notes.Put(NS_LITERAL_CSTRING("ProcessType"), NS_LITERAL_CSTRING("plugin"));
|
||||
if (processID == mFlashProcess1) {
|
||||
notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
|
||||
NS_LITERAL_CSTRING("Broker"));
|
||||
}
|
||||
else if (processID == mFlashProcess2) {
|
||||
notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"),
|
||||
NS_LITERAL_CSTRING("Sandbox"));
|
||||
}
|
||||
else {
|
||||
NS_ERROR("Got minidump for Flash process neither broker nor sandbox.");
|
||||
}
|
||||
|
||||
CrashReporter::AppendExtraData(aDumpID, notes);
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
mTaskFactory.NewRunnableMethod(
|
||||
&PluginModuleParent::CleanupFromTimeout));
|
||||
|
||||
KillProcess(OtherProcess(), 1, false);
|
||||
}
|
||||
|
||||
#endif // MOZ_CRASHREPORTER_INJECTOR
|
||||
|
@ -30,6 +30,10 @@
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIFileStreams.h"
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class PCrashReporterParent;
|
||||
@ -52,7 +56,12 @@ class BrowserStreamParent;
|
||||
* child process needs to make these calls back into Gecko proper.
|
||||
* This class is responsible for "actually" making those function calls.
|
||||
*/
|
||||
class PluginModuleParent : public PPluginModuleParent, PluginLibrary
|
||||
class PluginModuleParent
|
||||
: public PPluginModuleParent
|
||||
, public PluginLibrary
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
, public CrashReporter::InjectorCrashCallback
|
||||
#endif
|
||||
{
|
||||
private:
|
||||
typedef mozilla::PluginLibrary PluginLibrary;
|
||||
@ -306,6 +315,15 @@ private:
|
||||
#endif
|
||||
|
||||
friend class mozilla::dom::CrashReporterParent;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
void InitializeInjector();
|
||||
|
||||
NS_OVERRIDE void OnCrash(DWORD processID, const nsAString& aDumpID);
|
||||
|
||||
DWORD mFlashProcess1;
|
||||
DWORD mFlashProcess2;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
@ -1630,6 +1630,8 @@ pref("dom.ipc.plugins.parentTimeoutSecs", 0);
|
||||
// conflicts with our implementation, at least on Windows).
|
||||
pref("dom.ipc.plugins.java.enabled", false);
|
||||
|
||||
pref("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", true);
|
||||
|
||||
#ifndef ANDROID
|
||||
#ifndef XP_MACOSX
|
||||
#ifdef XP_UNIX
|
||||
|
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
|
440
toolkit/crashreporter/LoadLibraryRemote.cpp
Normal file
440
toolkit/crashreporter/LoadLibraryRemote.cpp
Normal file
@ -0,0 +1,440 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef __GNUC__
|
||||
// disable warnings about pointer <-> DWORD conversions
|
||||
#pragma warning( disable : 4311 4312 )
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
#define POINTER_TYPE ULONGLONG
|
||||
#else
|
||||
#define POINTER_TYPE DWORD
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef DEBUG_OUTPUT
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef const unsigned char* FileView;
|
||||
|
||||
template<>
|
||||
class nsAutoRefTraits<FileView>
|
||||
{
|
||||
public:
|
||||
typedef FileView RawRef;
|
||||
static FileView Void()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Release(RawRef aView)
|
||||
{
|
||||
if (NULL != aView)
|
||||
UnmapViewOfFile(aView);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#ifndef IMAGE_SIZEOF_BASE_RELOCATION
|
||||
// Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!?
|
||||
#define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION))
|
||||
#endif
|
||||
|
||||
#include "LoadLibraryRemote.h"
|
||||
|
||||
typedef struct {
|
||||
PIMAGE_NT_HEADERS headers;
|
||||
unsigned char *localCodeBase;
|
||||
unsigned char *remoteCodeBase;
|
||||
HMODULE *modules;
|
||||
int numModules;
|
||||
} MEMORYMODULE, *PMEMORYMODULE;
|
||||
|
||||
typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
|
||||
|
||||
#define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
static void
|
||||
OutputLastError(const char *msg)
|
||||
{
|
||||
char* tmp;
|
||||
char *tmpmsg;
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &tmp, 0, NULL);
|
||||
tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3);
|
||||
sprintf(tmpmsg, "%s: %s", msg, tmp);
|
||||
OutputDebugStringA(tmpmsg);
|
||||
LocalFree(tmpmsg);
|
||||
LocalFree(tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
|
||||
{
|
||||
int i;
|
||||
unsigned char *codeBase = module->localCodeBase;
|
||||
unsigned char *dest;
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
||||
for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
|
||||
dest = codeBase + section->VirtualAddress;
|
||||
memset(dest, 0, section->Misc.VirtualSize);
|
||||
if (section->SizeOfRawData) {
|
||||
memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData);
|
||||
}
|
||||
// section->Misc.PhysicalAddress = (POINTER_TYPE) module->remoteCodeBase + section->VirtualAddress;
|
||||
}
|
||||
}
|
||||
|
||||
// Protection flags for memory pages (Executable, Readable, Writeable)
|
||||
static int ProtectionFlags[2][2][2] = {
|
||||
{
|
||||
// not executable
|
||||
{PAGE_NOACCESS, PAGE_WRITECOPY},
|
||||
{PAGE_READONLY, PAGE_READWRITE},
|
||||
}, {
|
||||
// executable
|
||||
{PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY},
|
||||
{PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE},
|
||||
},
|
||||
};
|
||||
|
||||
static bool
|
||||
FinalizeSections(PMEMORYMODULE module, HANDLE hRemoteProcess)
|
||||
{
|
||||
#ifdef DEBUG_OUTPUT
|
||||
fprintf(stderr, "Finalizing sections: local base %p, remote base %p\n",
|
||||
module->localCodeBase, module->remoteCodeBase);
|
||||
#endif
|
||||
|
||||
int i;
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
|
||||
|
||||
// loop through all sections and change access flags
|
||||
for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
|
||||
DWORD protect, oldProtect, size;
|
||||
int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
|
||||
int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0;
|
||||
int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
|
||||
|
||||
// determine protection flags based on characteristics
|
||||
protect = ProtectionFlags[executable][readable][writeable];
|
||||
if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) {
|
||||
protect |= PAGE_NOCACHE;
|
||||
}
|
||||
|
||||
// determine size of region
|
||||
size = section->Misc.VirtualSize;
|
||||
if (size > 0) {
|
||||
void* remoteAddress = module->remoteCodeBase + section->VirtualAddress;
|
||||
void* localAddress = module->localCodeBase + section->VirtualAddress;
|
||||
|
||||
#ifdef DEBUG_OUTPUT
|
||||
fprintf(stderr, "Copying section %s to %p, size %x, executable %i readable %i writeable %i\n",
|
||||
section->Name, remoteAddress, size, executable, readable, writeable);
|
||||
#endif
|
||||
|
||||
// Copy the data from local->remote and set the memory protection
|
||||
if (!VirtualAllocEx(hRemoteProcess, remoteAddress, size, MEM_COMMIT, PAGE_READWRITE))
|
||||
return false;
|
||||
|
||||
if (!WriteProcessMemory(hRemoteProcess,
|
||||
remoteAddress,
|
||||
localAddress,
|
||||
size,
|
||||
NULL)) {
|
||||
#ifdef DEBUG_OUTPUT
|
||||
OutputLastError("Error writing remote memory.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (VirtualProtectEx(hRemoteProcess, remoteAddress, size, protect, &oldProtect) == 0) {
|
||||
#ifdef DEBUG_OUTPUT
|
||||
OutputLastError("Error protecting memory page");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
|
||||
{
|
||||
DWORD i;
|
||||
unsigned char *codeBase = module->localCodeBase;
|
||||
|
||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
|
||||
if (directory->Size > 0) {
|
||||
PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress);
|
||||
for (; relocation->VirtualAddress > 0; ) {
|
||||
unsigned char *dest = codeBase + relocation->VirtualAddress;
|
||||
unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION);
|
||||
for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) {
|
||||
DWORD *patchAddrHL;
|
||||
#ifdef _WIN64
|
||||
ULONGLONG *patchAddr64;
|
||||
#endif
|
||||
int type, offset;
|
||||
|
||||
// the upper 4 bits define the type of relocation
|
||||
type = *relInfo >> 12;
|
||||
// the lower 12 bits define the offset
|
||||
offset = *relInfo & 0xfff;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case IMAGE_REL_BASED_ABSOLUTE:
|
||||
// skip relocation
|
||||
break;
|
||||
|
||||
case IMAGE_REL_BASED_HIGHLOW:
|
||||
// change complete 32 bit address
|
||||
patchAddrHL = (DWORD *) (dest + offset);
|
||||
*patchAddrHL += delta;
|
||||
break;
|
||||
|
||||
#ifdef _WIN64
|
||||
case IMAGE_REL_BASED_DIR64:
|
||||
patchAddr64 = (ULONGLONG *) (dest + offset);
|
||||
*patchAddr64 += delta;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
//printf("Unknown relocation: %d\n", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// advance to next relocation block
|
||||
relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
BuildImportTable(PMEMORYMODULE module)
|
||||
{
|
||||
int result=1;
|
||||
unsigned char *codeBase = module->localCodeBase;
|
||||
|
||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
if (directory->Size > 0) {
|
||||
PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress);
|
||||
PIMAGE_IMPORT_DESCRIPTOR importEnd = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress + directory->Size);
|
||||
|
||||
for (; importDesc < importEnd && importDesc->Name; importDesc++) {
|
||||
POINTER_TYPE *thunkRef;
|
||||
FARPROC *funcRef;
|
||||
HMODULE handle = GetModuleHandleA((LPCSTR) (codeBase + importDesc->Name));
|
||||
if (handle == NULL) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Can't load library");
|
||||
#endif
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE)));
|
||||
if (module->modules == NULL) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
module->modules[module->numModules++] = handle;
|
||||
if (importDesc->OriginalFirstThunk) {
|
||||
thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk);
|
||||
funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
|
||||
} else {
|
||||
// no hint table
|
||||
thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk);
|
||||
funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
|
||||
}
|
||||
for (; *thunkRef; thunkRef++, funcRef++) {
|
||||
if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {
|
||||
*funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef));
|
||||
} else {
|
||||
PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef));
|
||||
*funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)&thunkData->Name);
|
||||
}
|
||||
if (*funcRef == 0) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name);
|
||||
|
||||
void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess,
|
||||
const WCHAR* library,
|
||||
const char* symbol)
|
||||
{
|
||||
// Map the DLL into memory
|
||||
nsAutoHandle hLibrary(
|
||||
CreateFile(library, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL));
|
||||
if (INVALID_HANDLE_VALUE == hLibrary) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Couldn't CreateFile the library.\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsAutoHandle hMapping(
|
||||
CreateFileMapping(hLibrary, NULL, PAGE_READONLY, 0, 0, NULL));
|
||||
if (!hMapping) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Couldn't CreateFileMapping.\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nsAutoRef<FileView> data(
|
||||
(const unsigned char*) MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (!data) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Couldn't MapViewOfFile.\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SIZE_T locationDelta;
|
||||
|
||||
PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)data.get();
|
||||
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputDebugStringA("Not a valid executable file.\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS old_header = (PIMAGE_NT_HEADERS)(data + dos_header->e_lfanew);
|
||||
if (old_header->Signature != IMAGE_NT_SIGNATURE) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputDebugStringA("No PE header found.\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// reserve memory for image of library in this process and the target process
|
||||
unsigned char* localCode = (unsigned char*) VirtualAlloc(NULL,
|
||||
old_header->OptionalHeader.SizeOfImage,
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
if (!localCode) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Can't reserve local memory.");
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned char* remoteCode = (unsigned char*) VirtualAllocEx(hRemoteProcess, NULL,
|
||||
old_header->OptionalHeader.SizeOfImage,
|
||||
MEM_RESERVE,
|
||||
PAGE_EXECUTE_READ);
|
||||
if (!remoteCode) {
|
||||
#if DEBUG_OUTPUT
|
||||
OutputLastError("Can't reserve remote memory.");
|
||||
#endif
|
||||
}
|
||||
|
||||
MEMORYMODULE result;
|
||||
result.localCodeBase = localCode;
|
||||
result.remoteCodeBase = remoteCode;
|
||||
result.numModules = 0;
|
||||
result.modules = NULL;
|
||||
|
||||
// copy PE header to code
|
||||
memcpy(localCode, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders);
|
||||
result.headers = reinterpret_cast<PIMAGE_NT_HEADERS>(localCode + dos_header->e_lfanew);
|
||||
|
||||
// update position
|
||||
result.headers->OptionalHeader.ImageBase = (POINTER_TYPE)remoteCode;
|
||||
|
||||
// copy sections from DLL file block to new memory location
|
||||
CopySections(data, old_header, &result);
|
||||
|
||||
// adjust base address of imported data
|
||||
locationDelta = (SIZE_T)(remoteCode - old_header->OptionalHeader.ImageBase);
|
||||
if (locationDelta != 0) {
|
||||
PerformBaseRelocation(&result, locationDelta);
|
||||
}
|
||||
|
||||
// load required dlls and adjust function table of imports
|
||||
if (!BuildImportTable(&result)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// mark memory pages depending on section headers and release
|
||||
// sections that are marked as "discardable"
|
||||
if (!FinalizeSections(&result, hRemoteProcess)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return MemoryGetProcAddress(&result, symbol);
|
||||
}
|
||||
|
||||
static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name)
|
||||
{
|
||||
unsigned char *localCodeBase = module->localCodeBase;
|
||||
int idx=-1;
|
||||
DWORD i, *nameRef;
|
||||
WORD *ordinal;
|
||||
PIMAGE_EXPORT_DIRECTORY exports;
|
||||
PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT);
|
||||
if (directory->Size == 0) {
|
||||
// no export table found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
exports = (PIMAGE_EXPORT_DIRECTORY) (localCodeBase + directory->VirtualAddress);
|
||||
if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) {
|
||||
// DLL doesn't export anything
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// search function name in list of exported names
|
||||
nameRef = (DWORD *) (localCodeBase + exports->AddressOfNames);
|
||||
ordinal = (WORD *) (localCodeBase + exports->AddressOfNameOrdinals);
|
||||
for (i=0; i<exports->NumberOfNames; i++, nameRef++, ordinal++) {
|
||||
if (stricmp(name, (const char *) (localCodeBase + (*nameRef))) == 0) {
|
||||
idx = *ordinal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == -1) {
|
||||
// exported symbol not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((DWORD)idx > exports->NumberOfFunctions) {
|
||||
// name <-> ordinal number don't match
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// AddressOfFunctions contains the RVAs to the "real" functions
|
||||
return (FARPROC) (module->remoteCodeBase + (*(DWORD *) (localCodeBase + exports->AddressOfFunctions + (idx*4))));
|
||||
}
|
24
toolkit/crashreporter/LoadLibraryRemote.h
Normal file
24
toolkit/crashreporter/LoadLibraryRemote.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* 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/. */
|
||||
|
||||
#ifndef LoadLibraryRemote_h
|
||||
#define LoadLibraryRemote_h
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/**
|
||||
* Inject a library into a remote process. This injection has the following
|
||||
* restrictions:
|
||||
*
|
||||
* - The DLL being injected must only depend on kernel32 and user32.
|
||||
* - The entry point of the DLL is not run. If the DLL uses the CRT, it is
|
||||
* the responsibility of the caller to make sure that _CRT_INIT is called.
|
||||
* - There is no support for unloading a library once it has been loaded.
|
||||
* - The symbol must be a named symbol and not an ordinal.
|
||||
*/
|
||||
void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess,
|
||||
const WCHAR* library,
|
||||
const char* symbol);
|
||||
|
||||
#endif // LoadLibraryRemote_h
|
@ -14,12 +14,10 @@ LIBXUL_LIBRARY = 1
|
||||
LIBRARY_NAME = exception_handler_s
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
DIRS += \
|
||||
google-breakpad/src/common/windows \
|
||||
google-breakpad/src/client/windows/handler \
|
||||
google-breakpad/src/client/windows/sender \
|
||||
google-breakpad/src/client/windows/crash_generation \
|
||||
$(NULL)
|
||||
DIRS += breakpad-windows-libxul
|
||||
ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
DIRS += breakpad-windows-standalone
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),Darwin)
|
||||
@ -74,6 +72,10 @@ endif
|
||||
|
||||
DIRS += client
|
||||
|
||||
ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
DIRS += injector
|
||||
endif
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/google-breakpad/src
|
||||
DEFINES += -DUNICODE -D_UNICODE
|
||||
|
||||
@ -85,6 +87,13 @@ CPPSRCS = \
|
||||
nsExceptionHandler.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
CPPSRCS += \
|
||||
LoadLibraryRemote.cpp \
|
||||
InjectCrashReporter.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
|
41
toolkit/crashreporter/breakpad-windows-libxul/Makefile.in
Normal file
41
toolkit/crashreporter/breakpad-windows-libxul/Makefile.in
Normal file
@ -0,0 +1,41 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
LIBRARY_NAME = google_breakpad_libxul_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
STL_FLAGS =
|
||||
|
||||
LOCAL_INCLUDES = -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src
|
||||
|
||||
include $(topsrcdir)/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mk
|
||||
include $(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mk
|
||||
include $(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/sender/objs.mk
|
||||
include $(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mk
|
||||
|
||||
VPATH += \
|
||||
$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/common/windows \
|
||||
$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/handler \
|
||||
$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/sender \
|
||||
$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
$(objs_common) \
|
||||
$(objs_handler) \
|
||||
$(objs_sender) \
|
||||
$(objs_crash_generation) \
|
||||
http_upload.cc \ # required for the libxul version but not standalone
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DUNICODE -DUNICODE_ -DBREAKPAD_NO_TERMINATE_THREAD -DNOMINMAX
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -0,0 +1,39 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
LIBRARY_NAME = google_breakpad_standalone_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
USE_STATIC_LIBS = 1
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
|
||||
STL_FLAGS =
|
||||
|
||||
LOCAL_INCLUDES = -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src
|
||||
|
||||
include $(topsrcdir)/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mk
|
||||
include $(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mk
|
||||
include $(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/objs.mk
|
||||
|
||||
VPATH += \
|
||||
$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/common/windows \
|
||||
$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/handler \
|
||||
$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
$(objs_common) \
|
||||
$(objs_handler) \
|
||||
$(objs_crash_generation) \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DUNICODE -DUNICODE_ -DBREAKPAD_NO_TERMINATE_THREAD -DNOMINMAX
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -37,8 +37,7 @@ CPPSRCS = \
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
CPPSRCS += crashreporter_win.cpp
|
||||
LIBS += \
|
||||
$(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/windows/sender/$(LIB_PREFIX)crash_report_sender_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/windows/$(LIB_PREFIX)breakpad_windows_common_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/toolkit/crashreporter/breakpad-windows-libxul/$(LIB_PREFIX)google_breakpad_libxul_s.$(LIB_SUFFIX)
|
||||
$(NULL)
|
||||
LOCAL_INCLUDES += -I$(srcdir)
|
||||
RCINCLUDE = crashreporter.rc
|
||||
|
@ -1,28 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = crash_generation
|
||||
LIBRARY_NAME = crash_generation_s
|
||||
|
||||
LOCAL_INCLUDES = -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src
|
||||
DEFINES += -DUNICODE -D_UNICODE
|
||||
|
||||
CPPSRCS = \
|
||||
client_info.cc \
|
||||
crash_generation_client.cc \
|
||||
crash_generation_server.cc \
|
||||
minidump_generator.cc \
|
||||
$(NULL)
|
||||
|
||||
# need static lib
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -95,6 +95,27 @@ CrashGenerationClient::CrashGenerationClient(
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const CustomClientInfo* custom_info)
|
||||
: pipe_name_(pipe_name),
|
||||
pipe_handle_(NULL),
|
||||
dump_type_(dump_type),
|
||||
thread_id_(0),
|
||||
server_process_id_(0),
|
||||
crash_event_(NULL),
|
||||
crash_generated_(NULL),
|
||||
server_alive_(NULL),
|
||||
exception_pointers_(NULL),
|
||||
custom_info_() {
|
||||
memset(&assert_info_, 0, sizeof(assert_info_));
|
||||
if (custom_info) {
|
||||
custom_info_ = *custom_info;
|
||||
}
|
||||
}
|
||||
|
||||
CrashGenerationClient::CrashGenerationClient(
|
||||
HANDLE pipe_handle,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const CustomClientInfo* custom_info)
|
||||
: pipe_name_(),
|
||||
pipe_handle_(pipe_handle),
|
||||
dump_type_(dump_type),
|
||||
thread_id_(0),
|
||||
server_process_id_(0),
|
||||
@ -231,6 +252,12 @@ bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
|
||||
HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
|
||||
DWORD pipe_access,
|
||||
DWORD flags_attrs) {
|
||||
if (pipe_handle_) {
|
||||
HANDLE t = pipe_handle_;
|
||||
pipe_handle_ = NULL;
|
||||
return t;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
|
||||
HANDLE pipe = CreateFile(pipe_name,
|
||||
pipe_access,
|
||||
@ -325,4 +352,33 @@ bool CrashGenerationClient::SignalCrashEventAndWait() {
|
||||
return result == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
HANDLE CrashGenerationClient::DuplicatePipeToClientProcess(const wchar_t* pipe_name,
|
||||
HANDLE hProcess) {
|
||||
for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
|
||||
HANDLE local_pipe = CreateFile(pipe_name, kPipeDesiredAccess,
|
||||
0, NULL, OPEN_EXISTING,
|
||||
kPipeFlagsAndAttributes, NULL);
|
||||
if (local_pipe != INVALID_HANDLE_VALUE) {
|
||||
HANDLE remotePipe = INVALID_HANDLE_VALUE;
|
||||
if (DuplicateHandle(GetCurrentProcess(), local_pipe,
|
||||
hProcess, &remotePipe, 0, FALSE,
|
||||
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
|
||||
return remotePipe;
|
||||
} else {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot continue retrying if the error wasn't a busy pipe.
|
||||
if (GetLastError() != ERROR_PIPE_BUSY) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@ -66,6 +66,10 @@ class CrashGenerationClient {
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const CustomClientInfo* custom_info);
|
||||
|
||||
CrashGenerationClient(HANDLE pipe_handle,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const CustomClientInfo* custom_info);
|
||||
|
||||
~CrashGenerationClient();
|
||||
|
||||
// Registers the client process with the crash server.
|
||||
@ -92,6 +96,14 @@ class CrashGenerationClient {
|
||||
// false will be returned.
|
||||
bool RequestDump(MDRawAssertionInfo* assert_info);
|
||||
|
||||
// If the crash generation client is running in a sandbox that prevents it
|
||||
// from opening the named pipe directly, the server process may open the
|
||||
// handle and duplicate it into the client process with this helper method.
|
||||
// Returns INVALID_HANDLE_VALUE on failure. The process must have been opened
|
||||
// with the PROCESS_DUP_HANDLE access right.
|
||||
static HANDLE DuplicatePipeToClientProcess(const wchar_t* pipe_name,
|
||||
HANDLE hProcess);
|
||||
|
||||
private:
|
||||
// Connects to the appropriate pipe and sets the pipe handle state.
|
||||
//
|
||||
@ -123,6 +135,10 @@ class CrashGenerationClient {
|
||||
// Pipe name to use to talk to server.
|
||||
std::wstring pipe_name_;
|
||||
|
||||
// Pipe handle duplicated from server process. Only valid before
|
||||
// Register is called.
|
||||
HANDLE pipe_handle_;
|
||||
|
||||
// Custom client information
|
||||
CustomClientInfo custom_info_;
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
objs_crash_generation = \
|
||||
client_info.cc \
|
||||
crash_generation_client.cc \
|
||||
crash_generation_server.cc \
|
||||
minidump_generator.cc \
|
||||
$(NULL)
|
@ -1,26 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = handler
|
||||
LIBRARY_NAME = exception_handler_s
|
||||
XPI_NAME = crashreporter
|
||||
|
||||
LOCAL_INCLUDES = -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src
|
||||
DEFINES += -DUNICODE -D_UNICODE -DBREAKPAD_NO_TERMINATE_THREAD -DNOMINMAX
|
||||
|
||||
CPPSRCS = \
|
||||
exception_handler.cc \
|
||||
$(NULL)
|
||||
|
||||
# need static lib
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -156,6 +156,26 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path,
|
||||
handler_types,
|
||||
dump_type,
|
||||
pipe_name,
|
||||
NULL,
|
||||
custom_info);
|
||||
}
|
||||
|
||||
ExceptionHandler::ExceptionHandler(const wstring& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
HANDLE pipe_handle,
|
||||
const CustomClientInfo* custom_info) {
|
||||
Initialize(dump_path,
|
||||
filter,
|
||||
callback,
|
||||
callback_context,
|
||||
handler_types,
|
||||
dump_type,
|
||||
NULL,
|
||||
pipe_handle,
|
||||
custom_info);
|
||||
}
|
||||
|
||||
@ -171,6 +191,7 @@ ExceptionHandler::ExceptionHandler(const wstring &dump_path,
|
||||
handler_types,
|
||||
MiniDumpNormal,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
@ -181,6 +202,7 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const wchar_t* pipe_name,
|
||||
HANDLE pipe_handle,
|
||||
const CustomClientInfo* custom_info) {
|
||||
LONG instance_count = InterlockedIncrement(&instance_count_);
|
||||
filter_ = filter;
|
||||
@ -210,12 +232,22 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
|
||||
handler_return_value_ = false;
|
||||
handle_debug_exceptions_ = false;
|
||||
|
||||
// Attempt to use out-of-process if user has specified pipe name.
|
||||
if (pipe_name != NULL) {
|
||||
scoped_ptr<CrashGenerationClient> client(
|
||||
// Attempt to use out-of-process if user has specified a pipe.
|
||||
if (pipe_name != NULL || pipe_handle != NULL) {
|
||||
assert(!(pipe_name && pipe_handle));
|
||||
|
||||
scoped_ptr<CrashGenerationClient> client;
|
||||
if (pipe_name) {
|
||||
client.reset(
|
||||
new CrashGenerationClient(pipe_name,
|
||||
dump_type_,
|
||||
custom_info));
|
||||
} else {
|
||||
client.reset(
|
||||
new CrashGenerationClient(pipe_handle,
|
||||
dump_type_,
|
||||
custom_info));
|
||||
}
|
||||
|
||||
// If successful in registering with the monitoring process,
|
||||
// there is no need to setup in-process crash generation.
|
||||
|
@ -164,7 +164,7 @@ class ExceptionHandler {
|
||||
void* callback_context,
|
||||
int handler_types);
|
||||
|
||||
// Creates a new ExcetpionHandler instance that can attempt to perform
|
||||
// Creates a new ExceptionHandler instance that can attempt to perform
|
||||
// out-of-process dump generation if pipe_name is not NULL. If pipe_name is
|
||||
// NULL, or if out-of-process dump generation registration step fails,
|
||||
// in-process dump generation will be used. This also allows specifying
|
||||
@ -178,6 +178,17 @@ class ExceptionHandler {
|
||||
const wchar_t* pipe_name,
|
||||
const CustomClientInfo* custom_info);
|
||||
|
||||
// As above, creates a new ExceptionHandler instance to perform
|
||||
// out-of-process dump generation if the given pipe_handle is not NULL.
|
||||
ExceptionHandler(const wstring& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
HANDLE pipe_handle,
|
||||
const CustomClientInfo* custom_info);
|
||||
|
||||
~ExceptionHandler();
|
||||
|
||||
// Get and set the minidump path.
|
||||
@ -253,6 +264,7 @@ class ExceptionHandler {
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const wchar_t* pipe_name,
|
||||
HANDLE pipe_handle,
|
||||
const CustomClientInfo* custom_info);
|
||||
|
||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||
|
@ -0,0 +1 @@
|
||||
objs_handler = exception_handler.cc
|
@ -1,26 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = sender
|
||||
LIBRARY_NAME = crash_report_sender_s
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/../../..
|
||||
DEFINES += -DUNICODE -D_UNICODE
|
||||
STL_FLAGS =
|
||||
|
||||
CPPSRCS = \
|
||||
crash_report_sender.cc \
|
||||
$(NULL)
|
||||
|
||||
# need static lib
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -0,0 +1 @@
|
||||
objs_sender = crash_report_sender.cc
|
@ -1,28 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = breakpad_windows_common
|
||||
LIBRARY_NAME = breakpad_windows_common_s
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/../..
|
||||
DEFINES += -DUNICODE -D_UNICODE
|
||||
STL_FLAGS =
|
||||
|
||||
CPPSRCS = \
|
||||
guid_string.cc \
|
||||
http_upload.cc \
|
||||
string_utils.cc \
|
||||
$(NULL)
|
||||
|
||||
# need static lib
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -0,0 +1,4 @@
|
||||
objs_common = \
|
||||
guid_string.cc \
|
||||
string_utils.cc \
|
||||
$(NULL)
|
27
toolkit/crashreporter/injector/Makefile.in
Normal file
27
toolkit/crashreporter/injector/Makefile.in
Normal file
@ -0,0 +1,27 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
LIBRARY_NAME = breakpadinjector
|
||||
FORCE_SHARED_LIB = 1
|
||||
USE_STATIC_LIBS = 1
|
||||
STL_FLAGS =
|
||||
MOZ_GLUE_LDFLAGS =
|
||||
|
||||
CPPSRCS = injector.cpp
|
||||
|
||||
SHARED_LIBRARY_LIBS += ../breakpad-windows-standalone/$(LIB_PREFIX)google_breakpad_standalone_s.$(LIB_SUFFIX)
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src
|
||||
LDFLAGS += -ENTRY:DummyEntryPoint
|
40
toolkit/crashreporter/injector/injector.cpp
Normal file
40
toolkit/crashreporter/injector/injector.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/* 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 <windows.h>
|
||||
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
|
||||
using google_breakpad::ExceptionHandler;
|
||||
using std::wstring;
|
||||
|
||||
BOOL WINAPI DummyEntryPoint(HINSTANCE instance,
|
||||
DWORD reason,
|
||||
void* reserved)
|
||||
{
|
||||
__debugbreak();
|
||||
|
||||
return FALSE; // We're being loaded remotely, this shouldn't happen!
|
||||
}
|
||||
|
||||
// support.microsoft.com/kb/94248
|
||||
extern "C" BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
|
||||
|
||||
extern "C"
|
||||
__declspec(dllexport) DWORD Start(void* context)
|
||||
{
|
||||
// Because the remote DLL injector does not call DllMain, we have to
|
||||
// initialize the CRT manually
|
||||
_CRT_INIT(NULL, DLL_PROCESS_ATTACH, NULL);
|
||||
|
||||
HANDLE hCrashPipe = reinterpret_cast<HANDLE>(context);
|
||||
|
||||
ExceptionHandler* e = new (std::nothrow)
|
||||
ExceptionHandler(wstring(), NULL, NULL, NULL,
|
||||
ExceptionHandler::HANDLER_ALL,
|
||||
MiniDumpNormal, hCrashPipe, NULL);
|
||||
if (e)
|
||||
e->set_handle_debug_exceptions(true);
|
||||
return 1;
|
||||
}
|
@ -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>
|
||||
@ -219,6 +224,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[] = {
|
||||
@ -808,7 +830,7 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory,
|
||||
#if defined(XP_WIN32)
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
minidump_type,
|
||||
NULL,
|
||||
(const wchar_t*) NULL,
|
||||
NULL);
|
||||
#else
|
||||
true
|
||||
@ -1911,9 +1933,14 @@ OnChildProcessDumpRequested(void* aContext,
|
||||
aClientInfo->pid();
|
||||
#endif
|
||||
|
||||
{
|
||||
MutexAutoLock lock(*dumpMapLock);
|
||||
pidToMinidump->Put(pid, minidump);
|
||||
}
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
NS_DispatchToMainThread(new ReportInjectedCrash(pid));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2002,6 +2029,16 @@ OOPDeinit()
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
if (sInjectorThread) {
|
||||
sInjectorThread->Shutdown();
|
||||
NS_RELEASE(sInjectorThread);
|
||||
}
|
||||
|
||||
delete pidToInjectorCallback;
|
||||
pidToInjectorCallback = NULL;
|
||||
#endif
|
||||
|
||||
delete crashServer;
|
||||
crashServer = NULL;
|
||||
|
||||
@ -2032,6 +2069,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);
|
||||
|
||||
|
@ -1148,10 +1148,9 @@ if [ "$MOZ_CRASHREPORTER" ]; then
|
||||
"
|
||||
if [ "$OS_ARCH" = "WINNT" ]; then
|
||||
add_makefiles "
|
||||
toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/Makefile
|
||||
toolkit/crashreporter/google-breakpad/src/client/windows/handler/Makefile
|
||||
toolkit/crashreporter/google-breakpad/src/client/windows/sender/Makefile
|
||||
toolkit/crashreporter/google-breakpad/src/common/windows/Makefile
|
||||
toolkit/crashreporter/breakpad-windows-libxul/Makefile
|
||||
toolkit/crashreporter/breakpad-windows-standalone/Makefile
|
||||
toolkit/crashreporter/injector/Makefile
|
||||
"
|
||||
elif [ "$OS_ARCH" = "Darwin" ]; then
|
||||
add_makefiles "
|
||||
|
@ -128,9 +128,7 @@ ifdef MOZ_CRASHREPORTER
|
||||
SHARED_LIBRARY_LIBS += $(DEPTH)/toolkit/crashreporter/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX)
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
$(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/windows/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/$(LIB_PREFIX)crash_generation_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/windows/$(LIB_PREFIX)breakpad_windows_common_s.$(LIB_SUFFIX)
|
||||
$(DEPTH)/toolkit/crashreporter/breakpad-windows-libxul/$(LIB_PREFIX)google_breakpad_libxul_s.$(LIB_SUFFIX)
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),Darwin)
|
||||
|
Loading…
Reference in New Issue
Block a user