summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/breakpad-client/windows/common
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/breakpad-client/windows/common')
-rw-r--r--toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h81
-rw-r--r--toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h181
-rw-r--r--toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc319
-rw-r--r--toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h78
-rw-r--r--toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild14
5 files changed, 673 insertions, 0 deletions
diff --git a/toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h b/toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h
new file mode 100644
index 0000000000..3fd4b9b7e6
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/windows/common/auto_critical_section.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
+#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
+
+#include <windows.h>
+
+namespace google_breakpad {
+
+// Automatically enters the critical section in the constructor and leaves
+// the critical section in the destructor.
+class AutoCriticalSection {
+ public:
+ // Creates a new instance with the given critical section object
+ // and enters the critical section immediately.
+ explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs), taken_(false) {
+ assert(cs_);
+ Acquire();
+ }
+
+ // Destructor: leaves the critical section.
+ ~AutoCriticalSection() {
+ if (taken_) {
+ Release();
+ }
+ }
+
+ // Enters the critical section. Recursive Acquire() calls are not allowed.
+ void Acquire() {
+ assert(!taken_);
+ EnterCriticalSection(cs_);
+ taken_ = true;
+ }
+
+ // Leaves the critical section. The caller should not call Release() unless
+ // the critical seciton has been entered already.
+ void Release() {
+ assert(taken_);
+ taken_ = false;
+ LeaveCriticalSection(cs_);
+ }
+
+ private:
+ // Disable copy ctor and operator=.
+ AutoCriticalSection(const AutoCriticalSection&);
+ AutoCriticalSection& operator=(const AutoCriticalSection&);
+
+ CRITICAL_SECTION* cs_;
+ bool taken_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
diff --git a/toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h b/toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h
new file mode 100644
index 0000000000..c74868198c
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/windows/common/ipc_protocol.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
+#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <string>
+#include <utility>
+#include "common/windows/string_utils-inl.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+// Name/value pair for custom client information.
+struct CustomInfoEntry {
+ // Maximum length for name and value for client custom info.
+ static const int kNameMaxLength = 64;
+ static const int kValueMaxLength = 64;
+
+ CustomInfoEntry() {
+ // Putting name and value in initializer list makes VC++ show warning 4351.
+ set_name(NULL);
+ set_value(NULL);
+ }
+
+ CustomInfoEntry(const wchar_t* name_arg, const wchar_t* value_arg) {
+ set_name(name_arg);
+ set_value(value_arg);
+ }
+
+ void set_name(const wchar_t* name_arg) {
+ if (!name_arg) {
+ name[0] = L'\0';
+ return;
+ }
+ WindowsStringUtils::safe_wcscpy(name, kNameMaxLength, name_arg);
+ }
+
+ void set_value(const wchar_t* value_arg) {
+ if (!value_arg) {
+ value[0] = L'\0';
+ return;
+ }
+
+ WindowsStringUtils::safe_wcscpy(value, kValueMaxLength, value_arg);
+ }
+
+ void set(const wchar_t* name_arg, const wchar_t* value_arg) {
+ set_name(name_arg);
+ set_value(value_arg);
+ }
+
+ wchar_t name[kNameMaxLength];
+ wchar_t value[kValueMaxLength];
+};
+
+// Constants for the protocol between client and the server.
+
+// Tags sent with each message indicating the purpose of
+// the message.
+enum MessageTag {
+ MESSAGE_TAG_NONE = 0,
+ MESSAGE_TAG_REGISTRATION_REQUEST = 1,
+ MESSAGE_TAG_REGISTRATION_RESPONSE = 2,
+ MESSAGE_TAG_REGISTRATION_ACK = 3,
+ MESSAGE_TAG_UPLOAD_REQUEST = 4
+};
+
+struct CustomClientInfo {
+ const CustomInfoEntry* entries;
+ size_t count;
+};
+
+// Message structure for IPC between crash client and crash server.
+struct ProtocolMessage {
+ ProtocolMessage()
+ : tag(MESSAGE_TAG_NONE),
+ id(0),
+ dump_type(MiniDumpNormal),
+ thread_id(0),
+ exception_pointers(NULL),
+ assert_info(NULL),
+ custom_client_info(),
+ dump_request_handle(NULL),
+ dump_generated_handle(NULL),
+ server_alive_handle(NULL) {
+ }
+
+ // Creates an instance with the given parameters.
+ ProtocolMessage(MessageTag arg_tag,
+ DWORD arg_id,
+ MINIDUMP_TYPE arg_dump_type,
+ DWORD* arg_thread_id,
+ EXCEPTION_POINTERS** arg_exception_pointers,
+ MDRawAssertionInfo* arg_assert_info,
+ const CustomClientInfo& custom_info,
+ HANDLE arg_dump_request_handle,
+ HANDLE arg_dump_generated_handle,
+ HANDLE arg_server_alive)
+ : tag(arg_tag),
+ id(arg_id),
+ dump_type(arg_dump_type),
+ thread_id(arg_thread_id),
+ exception_pointers(arg_exception_pointers),
+ assert_info(arg_assert_info),
+ custom_client_info(custom_info),
+ dump_request_handle(arg_dump_request_handle),
+ dump_generated_handle(arg_dump_generated_handle),
+ server_alive_handle(arg_server_alive) {
+ }
+
+ // Tag in the message.
+ MessageTag tag;
+
+ // The id for this message. This may be either a process id or a crash id
+ // depending on the type of message.
+ DWORD id;
+
+ // Dump type requested.
+ MINIDUMP_TYPE dump_type;
+
+ // Client thread id pointer.
+ DWORD* thread_id;
+
+ // Exception information.
+ EXCEPTION_POINTERS** exception_pointers;
+
+ // Assert information in case of an invalid parameter or
+ // pure call failure.
+ MDRawAssertionInfo* assert_info;
+
+ // Custom client information.
+ CustomClientInfo custom_client_info;
+
+ // Handle to signal the crash event.
+ HANDLE dump_request_handle;
+
+ // Handle to check if server is done generating crash.
+ HANDLE dump_generated_handle;
+
+ // Handle to a mutex that becomes signaled (WAIT_ABANDONED)
+ // if server process goes down.
+ HANDLE server_alive_handle;
+
+ private:
+ // Disable copy ctor and operator=.
+ ProtocolMessage(const ProtocolMessage& msg);
+ ProtocolMessage& operator=(const ProtocolMessage& msg);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
diff --git a/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc
new file mode 100644
index 0000000000..54d8e25274
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.cc
@@ -0,0 +1,319 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "minidump_callback.h"
+
+#include <winternl.h>
+
+#include <algorithm>
+#include <cassert>
+
+namespace google_breakpad {
+
+static const DWORD sHeapRegionSize= 1024;
+static DWORD sPageSize = 0;
+
+using NtQueryInformationThreadFunc = decltype(::NtQueryInformationThread);
+static NtQueryInformationThreadFunc* sNtQueryInformationThread = nullptr;
+
+
+namespace {
+enum {
+ ThreadBasicInformation,
+};
+
+struct CLIENT_ID {
+ PVOID UniqueProcess;
+ PVOID UniqueThread;
+};
+
+struct THREAD_BASIC_INFORMATION {
+ NTSTATUS ExitStatus;
+ PVOID TebBaseAddress;
+ CLIENT_ID ClientId;
+ KAFFINITY AffMask;
+ DWORD Priority;
+ DWORD BasePriority;
+};
+}
+
+void InitAppMemoryInternal()
+{
+ if (!sPageSize) {
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ sPageSize = systemInfo.dwPageSize;
+ }
+
+ if (!sNtQueryInformationThread) {
+ sNtQueryInformationThread = (NtQueryInformationThreadFunc*)
+ (::GetProcAddress(::GetModuleHandleW(L"ntdll.dll"),
+ "NtQueryInformationThread"));
+ }
+}
+
+bool GetAppMemoryFromRegister(HANDLE aProcess,
+ const NT_TIB* aTib,
+ RegisterValueType aRegister,
+ AppMemory* aResult)
+{
+ static_assert(sizeof(RegisterValueType) == sizeof(void*),
+ "Size mismatch between DWORD/DWORD64 and void*");
+
+ if (!sPageSize) {
+ // GetSystemInfo() should not fail, but bail out just in case it fails.
+ return false;
+ }
+
+ RegisterValueType addr = aRegister;
+ addr &= ~(static_cast<RegisterValueType>(sPageSize) - 1);
+
+ if (aTib) {
+ if (aRegister >= (RegisterValueType)aTib->StackLimit &&
+ aRegister <= (RegisterValueType)aTib->StackBase) {
+ // aRegister points to the stack.
+ return false;
+ }
+ }
+
+ MEMORY_BASIC_INFORMATION memInfo;
+ memset(&memInfo, 0, sizeof(memInfo));
+ SIZE_T rv = ::VirtualQueryEx(aProcess,
+ reinterpret_cast<void*>(addr),
+ &memInfo,
+ sizeof(memInfo));
+ if (!rv) {
+ // VirtualQuery fails: aAddr is not on heap.
+ return false;
+ }
+
+ // Check protection and type of the memory region. Include the region if it's
+ // 1. read-write: heap, or
+ // 2. read-executable and private: likely to be JIT code.
+ if (memInfo.Protect != PAGE_READWRITE &&
+ memInfo.Protect != PAGE_EXECUTE_READ) {
+ return false;
+ }
+
+ // Try to include a region of size sHeapRegionSize around aRegister, bounded
+ // by the [BaseAddress, BaseAddress + RegionSize].
+ RegisterValueType lower =
+ std::max(aRegister - sHeapRegionSize / 2,
+ reinterpret_cast<RegisterValueType>(memInfo.BaseAddress));
+
+ RegisterValueType upper =
+ std::min(lower + sHeapRegionSize,
+ reinterpret_cast<RegisterValueType>(memInfo.BaseAddress) +
+ memInfo.RegionSize);
+
+ aResult->ptr = lower;
+ aResult->length = upper - lower;
+
+ return true;
+}
+
+static AppMemoryList::iterator
+FindNextPreallocated(AppMemoryList& aList, AppMemoryList::iterator aBegin) {
+ auto it = aBegin;
+ for (auto it = aBegin; it != aList.end(); it++) {
+ if (it->preallocated) {
+ return it;
+ }
+ }
+
+ assert(it == aList.end());
+ return it;
+}
+
+static bool
+GetThreadTib(HANDLE aProcess, DWORD aThreadId, NT_TIB* aTib) {
+ HANDLE threadHandle = ::OpenThread(THREAD_QUERY_INFORMATION,
+ FALSE,
+ aThreadId);
+ if (!threadHandle) {
+ return false;
+ }
+
+ if (!sNtQueryInformationThread) {
+ return false;
+ }
+
+ THREAD_BASIC_INFORMATION threadInfo;
+ auto status = (*sNtQueryInformationThread)(threadHandle,
+ (THREADINFOCLASS)ThreadBasicInformation,
+ &threadInfo,
+ sizeof(threadInfo),
+ NULL);
+ if (!NT_SUCCESS(status)) {
+ return false;
+ }
+
+ auto readSuccess = ::ReadProcessMemory(aProcess,
+ threadInfo.TebBaseAddress,
+ aTib,
+ sizeof(*aTib),
+ NULL);
+ if (!readSuccess) {
+ return false;
+ }
+
+ ::CloseHandle(threadHandle);
+ return true;
+}
+
+void IncludeAppMemoryFromExceptionContext(HANDLE aProcess,
+ DWORD aThreadId,
+ AppMemoryList& aList,
+ PCONTEXT aExceptionContext,
+ bool aInstructionPointerOnly) {
+ RegisterValueType heapAddrCandidates[kExceptionAppMemoryRegions];
+ size_t numElements = 0;
+
+ NT_TIB tib;
+ memset(&tib, 0, sizeof(tib));
+ if (!GetThreadTib(aProcess, aThreadId, &tib)) {
+ // Fail to query thread stack range: only safe to include the region around
+ // the instruction pointer.
+ aInstructionPointerOnly = true;
+ }
+
+ // Add registers that might have a heap address to heapAddrCandidates.
+ // Note that older versions of DbgHelp.dll don't correctly put the memory
+ // around the faulting instruction pointer into the minidump. Include Rip/Eip
+ // unconditionally ensures it gets included.
+#if defined(_M_IX86)
+ if (!aInstructionPointerOnly) {
+ heapAddrCandidates[numElements++] = aExceptionContext->Eax;
+ heapAddrCandidates[numElements++] = aExceptionContext->Ebx;
+ heapAddrCandidates[numElements++] = aExceptionContext->Ecx;
+ heapAddrCandidates[numElements++] = aExceptionContext->Edx;
+ heapAddrCandidates[numElements++] = aExceptionContext->Esi;
+ heapAddrCandidates[numElements++] = aExceptionContext->Edi;
+ }
+ heapAddrCandidates[numElements++] = aExceptionContext->Eip;
+#elif defined(_M_AMD64)
+ if (!aInstructionPointerOnly) {
+ heapAddrCandidates[numElements++] = aExceptionContext->Rax;
+ heapAddrCandidates[numElements++] = aExceptionContext->Rbx;
+ heapAddrCandidates[numElements++] = aExceptionContext->Rcx;
+ heapAddrCandidates[numElements++] = aExceptionContext->Rdx;
+ heapAddrCandidates[numElements++] = aExceptionContext->Rsi;
+ heapAddrCandidates[numElements++] = aExceptionContext->Rdi;
+ heapAddrCandidates[numElements++] = aExceptionContext->R8;
+ heapAddrCandidates[numElements++] = aExceptionContext->R9;
+ heapAddrCandidates[numElements++] = aExceptionContext->R10;
+ heapAddrCandidates[numElements++] = aExceptionContext->R11;
+ heapAddrCandidates[numElements++] = aExceptionContext->R12;
+ heapAddrCandidates[numElements++] = aExceptionContext->R13;
+ heapAddrCandidates[numElements++] = aExceptionContext->R14;
+ heapAddrCandidates[numElements++] = aExceptionContext->R15;
+ }
+ heapAddrCandidates[numElements++] = aExceptionContext->Rip;
+#elif defined(_M_ARM64)
+ if (!aInstructionPointerOnly) {
+ for (auto reg : aExceptionContext->X) {
+ heapAddrCandidates[numElements++] = reg;
+ }
+ heapAddrCandidates[numElements++] = aExceptionContext->Sp;
+ }
+ heapAddrCandidates[numElements++] = aExceptionContext->Pc;
+#endif
+
+ // Inplace sort the candidates for excluding or merging memory regions.
+ auto begin = &heapAddrCandidates[0], end = &heapAddrCandidates[numElements];
+ std::make_heap(begin, end);
+ std::sort_heap(begin, end);
+
+ auto appMemory = FindNextPreallocated(aList, aList.begin());
+ for (size_t i = 0; i < numElements; i++) {
+ if (appMemory == aList.end()) {
+ break;
+ }
+
+ AppMemory tmp{};
+ if (!GetAppMemoryFromRegister(aProcess,
+ aInstructionPointerOnly ? nullptr : &tib,
+ heapAddrCandidates[i],
+ &tmp)) {
+ continue;
+ }
+
+ if (!(tmp.ptr && tmp.length)) {
+ // Something unexpected happens. Skip this candidate.
+ continue;
+ }
+
+ if (!appMemory->ptr) {
+ *appMemory = tmp;
+ continue;
+ }
+
+ if (appMemory->ptr + appMemory->length > tmp.ptr) {
+ // The beginning of the next region fall within the range of the previous
+ // region: merge into one. Note that we don't merge adjacent regions like
+ // [0, 99] and [100, 199] in case we cross the border of memory allocation
+ // regions.
+ appMemory->length = tmp.ptr + tmp.length - appMemory->ptr;
+ continue;
+ }
+
+ appMemory = FindNextPreallocated(aList, ++appMemory);
+ if (appMemory == aList.end()) {
+ break;
+ }
+
+ *appMemory = tmp;
+ }
+}
+
+BOOL CALLBACK MinidumpWriteDumpCallback(
+ PVOID context,
+ const PMINIDUMP_CALLBACK_INPUT callback_input,
+ PMINIDUMP_CALLBACK_OUTPUT callback_output) {
+ switch (callback_input->CallbackType) {
+ case MemoryCallback: {
+ MinidumpCallbackContext* callback_context =
+ reinterpret_cast<MinidumpCallbackContext*>(context);
+
+ // Skip unused preallocated AppMemory elements.
+ while (callback_context->iter != callback_context->end &&
+ callback_context->iter->preallocated &&
+ !callback_context->iter->ptr) {
+ callback_context->iter++;
+ }
+
+ if (callback_context->iter == callback_context->end)
+ return FALSE;
+
+ // Include the specified memory region.
+ callback_output->MemoryBase = callback_context->iter->ptr;
+ callback_output->MemorySize = callback_context->iter->length;
+ callback_context->iter++;
+ return TRUE;
+ }
+
+ // Include all modules.
+ case IncludeModuleCallback:
+ case ModuleCallback:
+ return TRUE;
+
+ // Include all threads.
+ case IncludeThreadCallback:
+ case ThreadCallback:
+ return TRUE;
+
+ // Stop receiving cancel callbacks.
+ case CancelCallback:
+ callback_output->CheckCancel = FALSE;
+ callback_output->Cancel = FALSE;
+ return TRUE;
+ }
+ // Ignore other callback types.
+ return FALSE;
+}
+
+} // namespace google_breakpad
+
diff --git a/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h
new file mode 100644
index 0000000000..1306235cfd
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/windows/common/minidump_callback.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 MINIDUMP_CALLBACK_H__
+#define MINIDUMP_CALLBACK_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+
+#include <list>
+
+namespace google_breakpad {
+
+// These entries store a list of memory regions that the client wants included
+// in the minidump.
+struct AppMemory {
+ ULONG64 ptr;
+ ULONG length;
+ bool preallocated;
+
+ bool operator==(const struct AppMemory& other) const {
+ return ptr == other.ptr;
+ }
+
+ bool operator==(const void* other) const {
+ return ptr == reinterpret_cast<ULONG64>(other);
+ }
+
+ AppMemory()
+ : ptr(0)
+ , length(0)
+ , preallocated(false)
+ {}
+
+ AppMemory& operator=(const AppMemory& other) = default;
+};
+typedef std::list<AppMemory> AppMemoryList;
+
+// This is passed as the context to the MinidumpWriteDump callback.
+typedef struct {
+ AppMemoryList::const_iterator iter;
+ AppMemoryList::const_iterator end;
+} MinidumpCallbackContext;
+
+static const size_t kExceptionAppMemoryRegions = 33;
+
+#if defined(_M_IX86)
+using RegisterValueType = DWORD;
+#elif defined(_M_AMD64) || defined(_M_ARM64)
+using RegisterValueType = DWORD64;
+#else
+#error Unsupported platform
+#endif
+
+void IncludeAppMemoryFromExceptionContext(HANDLE aProcess,
+ DWORD aThreadId,
+ AppMemoryList& aList,
+ PCONTEXT aExceptionContext,
+ bool aInsttructionPointerOnly);
+
+// This function is used as a callback when calling MinidumpWriteDump,
+// in order to add additional memory regions to the dump.
+BOOL CALLBACK MinidumpWriteDumpCallback(
+ PVOID context,
+ const PMINIDUMP_CALLBACK_INPUT callback_input,
+ PMINIDUMP_CALLBACK_OUTPUT callback_output);
+
+// Called during startup to initialize system information used by
+// IncludeAppMemoryFromExceptionContext().
+void InitAppMemoryInternal();
+
+} // namespace google_breakpad
+
+#endif
+
diff --git a/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild b/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild
new file mode 100644
index 0000000000..ddc1d58d56
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/windows/common/objs.mozbuild
@@ -0,0 +1,14 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+lobjs_client_common = [
+ 'minidump_callback.cc',
+]
+
+subdir = 'toolkit/crashreporter/breakpad-client/windows/common'
+objs_client_common = [
+ '/%s/%s' % (subdir, s) for s in lobjs_client_common
+]