Merge mozilla-central into moizilla-inbound

This commit is contained in:
Ehsan Akhgari 2012-07-03 11:14:18 -04:00
commit 910d058e01
39 changed files with 1162 additions and 199 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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@

View File

@ -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)

View File

@ -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();
if (!hangID.IsEmpty())
notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(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,17 +200,19 @@ bool
PluginModuleParent::ShouldContinueFromReplyTimeout()
{
#ifdef MOZ_CRASHREPORTER
CrashReporterParent* crashReporter = CrashReporter();
if (crashReporter->GeneratePairedMinidump(this)) {
mBrowserDumpID = crashReporter->ParentDumpID();
mPluginDumpID = crashReporter->ChildDumpID();
PLUGIN_LOG_DEBUG(
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
} else {
NS_WARNING("failed to capture paired minidumps from hang");
if (mPluginDumpID.IsEmpty()) {
CrashReporterParent* crashReporter = CrashReporter();
if (crashReporter->GeneratePairedMinidump(this)) {
mBrowserDumpID = crashReporter->ParentDumpID();
mPluginDumpID = crashReporter->ChildDumpID();
PLUGIN_LOG_DEBUG(
("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
} else {
NS_WARNING("failed to capture paired minidumps from hang");
}
}
#endif
@ -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, &notes)) {
if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
crashReporter->GenerateHangCrashReport(&notes);
}
else if (!mPluginDumpID.IsEmpty()) {
// Nothing to do, we've already written this minidump in
// PluginModuleParent::OnCrash
}
else if (crashReporter->GenerateCrashReport(this, &notes)) {
mPluginDumpID = crashReporter->ChildDumpID();
PLUGIN_LOG_DEBUG(("got child minidump: %s",
NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
}
else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
crashReporter->GenerateHangCrashReport(&notes);
}
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

View File

@ -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

View File

@ -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

View 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

View 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

View 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))));
}

View 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

View File

@ -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 = \

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_;

View File

@ -0,0 +1,6 @@
objs_crash_generation = \
client_info.cc \
crash_generation_client.cc \
crash_generation_server.cc \
minidump_generator.cc \
$(NULL)

View File

@ -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

View File

@ -156,9 +156,29 @@ 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);
}
ExceptionHandler::ExceptionHandler(const wstring &dump_path,
FilterCallback filter,
MinidumpCallback callback,
@ -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.

View File

@ -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

View File

@ -0,0 +1 @@
objs_handler = exception_handler.cc

View File

@ -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

View File

@ -0,0 +1 @@
objs_sender = crash_report_sender.cc

View File

@ -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

View File

@ -0,0 +1,4 @@
objs_common = \
guid_string.cc \
string_utils.cc \
$(NULL)

View 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

View 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;
}

View File

@ -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,8 +1933,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
}
}
@ -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

View File

@ -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);

View File

@ -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 "

View File

@ -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)