forked from LosaDev/ls-2019-source
LosaDev source snapshot 2019
This commit is contained in:
commit
c198676e97
20588 files changed
+8812878
No files matched your search
@@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LS_GoogleDump", "LS_GoogleDump\LS_GoogleDump.vcxproj", "{AD9DACFB-6A8A-42B5-8FDC-DA5E31C7F107}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AD9DACFB-6A8A-42B5-8FDC-DA5E31C7F107}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AD9DACFB-6A8A-42B5-8FDC-DA5E31C7F107}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AD9DACFB-6A8A-42B5-8FDC-DA5E31C7F107}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{AD9DACFB-6A8A-42B5-8FDC-DA5E31C7F107}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,86 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* breakpad_types.h: Precise-width types
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file ensures that types uintN_t are defined for N = 8, 16, 32, and
|
||||
* 64. Types of precise widths are crucial to the task of writing data
|
||||
* structures on one platform and reading them on another.
|
||||
*
|
||||
* Author: Mark Mentovai */
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif /* __STDC_FORMAT_MACROS */
|
||||
#include <inttypes.h>
|
||||
|
||||
#else /* !_WIN32 */
|
||||
|
||||
#if _MSC_VER >= 1600
|
||||
#include <stdint.h>
|
||||
#elif defined(BREAKPAD_CUSTOM_STDINT_H)
|
||||
/* Visual C++ Pre-2010 did not ship a stdint.h, so allow
|
||||
* consumers of this library to provide their own because
|
||||
* there are often subtle type incompatibilities.
|
||||
*/
|
||||
#include BREAKPAD_CUSTOM_STDINT_H
|
||||
#else
|
||||
#include <WTypes.h>
|
||||
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#endif
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
typedef struct {
|
||||
uint64_t high;
|
||||
uint64_t low;
|
||||
} uint128_struct;
|
||||
|
||||
typedef uint64_t breakpad_time_t;
|
||||
|
||||
/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to
|
||||
* llx, which is the format string for "long long" - this is a 64-bit
|
||||
* integral type on many systems. */
|
||||
#ifndef PRIx64
|
||||
#define PRIx64 "llx"
|
||||
#endif /* !PRIx64 */
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */
|
||||
@@ -0,0 +1,192 @@
|
||||
#include "ClientInfo.h"
|
||||
#include "IpcProtocol.h"
|
||||
|
||||
static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
|
||||
static const size_t kMaxCustomInfoEntries = 4096;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
|
||||
DWORD pid,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
DWORD* thread_id,
|
||||
EXCEPTION_POINTERS** ex_info,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
const CustomClientInfo& custom_client_info)
|
||||
: crash_server_(crash_server),
|
||||
pid_(pid),
|
||||
dump_type_(dump_type),
|
||||
ex_info_(ex_info),
|
||||
assert_info_(assert_info),
|
||||
custom_client_info_(custom_client_info),
|
||||
thread_id_(thread_id),
|
||||
process_handle_(NULL),
|
||||
dump_requested_handle_(NULL),
|
||||
dump_generated_handle_(NULL),
|
||||
dump_request_wait_handle_(NULL),
|
||||
process_exit_wait_handle_(NULL),
|
||||
crash_id_(NULL) {
|
||||
GetSystemTimeAsFileTime(&start_time_);
|
||||
}
|
||||
|
||||
bool ClientInfo::Initialize() {
|
||||
process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_);
|
||||
if (!process_handle_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The crash_id will be the low order word of the process creation time.
|
||||
FILETIME creation_time, exit_time, kernel_time, user_time;
|
||||
if (GetProcessTimes(process_handle_, &creation_time, &exit_time,
|
||||
&kernel_time, &user_time))
|
||||
crash_id_ = creation_time.dwLowDateTime;
|
||||
|
||||
dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
|
||||
TRUE, // Manual reset.
|
||||
FALSE, // Initial state.
|
||||
NULL); // Name.
|
||||
if (!dump_requested_handle_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dump_generated_handle_ = CreateEvent(NULL, // Security attributes.
|
||||
TRUE, // Manual reset.
|
||||
FALSE, // Initial state.
|
||||
NULL); // Name.
|
||||
return dump_generated_handle_ != NULL;
|
||||
}
|
||||
|
||||
void ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() {
|
||||
if (dump_request_wait_handle_) {
|
||||
// Wait for callbacks that might already be running to finish.
|
||||
UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
dump_request_wait_handle_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) {
|
||||
if (process_exit_wait_handle_) {
|
||||
if (block_until_no_pending) {
|
||||
// Wait for the callback that might already be running to finish.
|
||||
UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
} else {
|
||||
UnregisterWait(process_exit_wait_handle_);
|
||||
}
|
||||
process_exit_wait_handle_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ClientInfo::~ClientInfo() {
|
||||
// Waiting for the callback to finish here is safe because ClientInfo's are
|
||||
// never destroyed from the dump request handling callback.
|
||||
UnregisterDumpRequestWaitAndBlockUntilNoPending();
|
||||
|
||||
// This is a little tricky because ClientInfo's may be destroyed by the same
|
||||
// callback (OnClientEnd) and waiting for it to finish will cause a deadlock.
|
||||
// Regardless of this complication, wait for any running callbacks to finish
|
||||
// so that the common case is properly handled. In order to avoid deadlocks,
|
||||
// the OnClientEnd callback must call UnregisterProcessExitWait(false)
|
||||
// before deleting the ClientInfo.
|
||||
UnregisterProcessExitWait(true);
|
||||
|
||||
if (process_handle_) {
|
||||
CloseHandle(process_handle_);
|
||||
}
|
||||
|
||||
if (dump_requested_handle_) {
|
||||
CloseHandle(dump_requested_handle_);
|
||||
}
|
||||
|
||||
if (dump_generated_handle_) {
|
||||
CloseHandle(dump_generated_handle_);
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {
|
||||
SIZE_T bytes_count = 0;
|
||||
if (!ReadProcessMemory(process_handle_,
|
||||
ex_info_,
|
||||
ex_info,
|
||||
sizeof(*ex_info),
|
||||
&bytes_count)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bytes_count == sizeof(*ex_info);
|
||||
}
|
||||
|
||||
bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
|
||||
SIZE_T bytes_count = 0;
|
||||
if (!ReadProcessMemory(process_handle_,
|
||||
thread_id_,
|
||||
thread_id,
|
||||
sizeof(*thread_id),
|
||||
&bytes_count)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bytes_count == sizeof(*thread_id);
|
||||
}
|
||||
|
||||
void ClientInfo::SetProcessUptime() {
|
||||
FILETIME now = {0};
|
||||
GetSystemTimeAsFileTime(&now);
|
||||
|
||||
ULARGE_INTEGER time_start;
|
||||
time_start.HighPart = start_time_.dwHighDateTime;
|
||||
time_start.LowPart = start_time_.dwLowDateTime;
|
||||
|
||||
ULARGE_INTEGER time_now;
|
||||
time_now.HighPart = now.dwHighDateTime;
|
||||
time_now.LowPart = now.dwLowDateTime;
|
||||
|
||||
// Calculate the delay and convert it from 100-nanoseconds to milliseconds.
|
||||
__int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000;
|
||||
|
||||
// Convert it to a string.
|
||||
wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value;
|
||||
_i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10);
|
||||
}
|
||||
|
||||
bool ClientInfo::PopulateCustomInfo() {
|
||||
if (custom_client_info_.count > kMaxCustomInfoEntries)
|
||||
return false;
|
||||
|
||||
SIZE_T bytes_count = 0;
|
||||
SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count;
|
||||
|
||||
// If the scoped array for custom info already has an array, it will be
|
||||
// the same size as what we need. This is because the number of custom info
|
||||
// entries is always the same. So allocate memory only if scoped array has
|
||||
// a NULL pointer.
|
||||
if (!custom_info_entries_.get()) {
|
||||
// Allocate an extra entry for reporting uptime for the client process.
|
||||
custom_info_entries_.reset(
|
||||
new CustomInfoEntry[custom_client_info_.count + 1]);
|
||||
// Use the last element in the array for uptime.
|
||||
custom_info_entries_.get()[custom_client_info_.count].set_name(
|
||||
kCustomInfoProcessUptimeName);
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(process_handle_,
|
||||
custom_client_info_.entries,
|
||||
custom_info_entries_.get(),
|
||||
read_count,
|
||||
&bytes_count)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProcessUptime();
|
||||
return (bytes_count == read_count);
|
||||
}
|
||||
|
||||
CustomClientInfo ClientInfo::GetCustomInfo() const {
|
||||
CustomClientInfo custom_info;
|
||||
custom_info.entries = custom_info_entries_.get();
|
||||
// Add 1 to the count from the client process to account for extra entry for
|
||||
// process uptime.
|
||||
custom_info.count = custom_client_info_.count + 1;
|
||||
return custom_info;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
@@ -0,0 +1,148 @@
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
|
||||
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include "IpcProtocol.h"
|
||||
#include "ScopedPtr.h"
|
||||
#include "MinidumpFormat.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class CrashGenerationServer;
|
||||
|
||||
// Abstraction for a crash client process.
|
||||
class ClientInfo {
|
||||
public:
|
||||
// Creates an instance with the given values. Gets the process
|
||||
// handle for the given process id and creates necessary event
|
||||
// objects.
|
||||
ClientInfo(CrashGenerationServer* crash_server,
|
||||
DWORD pid,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
DWORD* thread_id,
|
||||
EXCEPTION_POINTERS** ex_info,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
const CustomClientInfo& custom_client_info);
|
||||
|
||||
~ClientInfo();
|
||||
|
||||
CrashGenerationServer* crash_server() const { return crash_server_; }
|
||||
DWORD pid() const { return pid_; }
|
||||
MINIDUMP_TYPE dump_type() const { return dump_type_; }
|
||||
EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
|
||||
MDRawAssertionInfo* assert_info() const { return assert_info_; }
|
||||
DWORD* thread_id() const { return thread_id_; }
|
||||
HANDLE process_handle() const { return process_handle_; }
|
||||
HANDLE dump_requested_handle() const { return dump_requested_handle_; }
|
||||
HANDLE dump_generated_handle() const { return dump_generated_handle_; }
|
||||
DWORD crash_id() const { return crash_id_; }
|
||||
const CustomClientInfo& custom_client_info() const {
|
||||
return custom_client_info_;
|
||||
}
|
||||
|
||||
void set_dump_request_wait_handle(HANDLE value) {
|
||||
dump_request_wait_handle_ = value;
|
||||
}
|
||||
|
||||
void set_process_exit_wait_handle(HANDLE value) {
|
||||
process_exit_wait_handle_ = value;
|
||||
}
|
||||
|
||||
// Unregister the dump request wait operation and wait for all callbacks
|
||||
// that might already be running to complete before returning.
|
||||
void UnregisterDumpRequestWaitAndBlockUntilNoPending();
|
||||
|
||||
// Unregister the process exit wait operation. If block_until_no_pending is
|
||||
// true, wait for all callbacks that might already be running to complete
|
||||
// before returning.
|
||||
void UnregisterProcessExitWait(bool block_until_no_pending);
|
||||
|
||||
bool Initialize();
|
||||
bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
|
||||
bool GetClientThreadId(DWORD* thread_id) const;
|
||||
|
||||
// Reads the custom information from the client process address space.
|
||||
bool PopulateCustomInfo();
|
||||
|
||||
// Returns the client custom information.
|
||||
CustomClientInfo GetCustomInfo() const;
|
||||
|
||||
private:
|
||||
// Calcualtes the uptime for the client process, converts it to a string and
|
||||
// stores it in the last entry of client custom info.
|
||||
void SetProcessUptime();
|
||||
|
||||
// Crash generation server.
|
||||
CrashGenerationServer* crash_server_;
|
||||
|
||||
// Client process ID.
|
||||
DWORD pid_;
|
||||
|
||||
// Dump type requested by the client.
|
||||
MINIDUMP_TYPE dump_type_;
|
||||
|
||||
// Address of an EXCEPTION_POINTERS* variable in the client
|
||||
// process address space that will point to an instance of
|
||||
// EXCEPTION_POINTERS containing information about crash.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
EXCEPTION_POINTERS** ex_info_;
|
||||
|
||||
// Address of an instance of MDRawAssertionInfo in the client
|
||||
// process address space that will contain information about
|
||||
// non-exception related crashes like invalid parameter assertion
|
||||
// failures and pure calls.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
MDRawAssertionInfo* assert_info_;
|
||||
|
||||
// Custom information about the client.
|
||||
CustomClientInfo custom_client_info_;
|
||||
|
||||
// Contains the custom client info entries read from the client process
|
||||
// memory. This will be populated only if the method GetClientCustomInfo
|
||||
// is called.
|
||||
scoped_array<CustomInfoEntry> custom_info_entries_;
|
||||
|
||||
// Address of a variable in the client process address space that
|
||||
// will contain the thread id of the crashing client thread.
|
||||
//
|
||||
// WARNING: Do not dereference these pointers as they are pointers
|
||||
// in the address space of another process.
|
||||
DWORD* thread_id_;
|
||||
|
||||
// Client process handle.
|
||||
HANDLE process_handle_;
|
||||
|
||||
// Dump request event handle.
|
||||
HANDLE dump_requested_handle_;
|
||||
|
||||
// Dump generated event handle.
|
||||
HANDLE dump_generated_handle_;
|
||||
|
||||
// Wait handle for dump request event.
|
||||
HANDLE dump_request_wait_handle_;
|
||||
|
||||
// Wait handle for process exit event.
|
||||
HANDLE process_exit_wait_handle_;
|
||||
|
||||
// Time when the client process started. It is used to determine the uptime
|
||||
// for the client process when it signals a crash.
|
||||
FILETIME start_time_;
|
||||
|
||||
// The crash id which can be used to request an upload. This will be the
|
||||
// value of the low order dword of the process creation time for the process
|
||||
// being dumped.
|
||||
DWORD crash_id_;
|
||||
|
||||
// Disallow copy ctor and operator=.
|
||||
ClientInfo(const ClientInfo& client_info);
|
||||
ClientInfo& operator=(const ClientInfo& client_info);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
|
||||
@@ -0,0 +1,235 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on amd64. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
|
||||
|
||||
|
||||
/*
|
||||
* AMD64 support, see WINNT.H
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint16_t control_word;
|
||||
uint16_t status_word;
|
||||
uint8_t tag_word;
|
||||
uint8_t reserved1;
|
||||
uint16_t error_opcode;
|
||||
uint32_t error_offset;
|
||||
uint16_t error_selector;
|
||||
uint16_t reserved2;
|
||||
uint32_t data_offset;
|
||||
uint16_t data_selector;
|
||||
uint16_t reserved3;
|
||||
uint32_t mx_csr;
|
||||
uint32_t mx_csr_mask;
|
||||
uint128_struct float_registers[8];
|
||||
uint128_struct xmm_registers[16];
|
||||
uint8_t reserved4[96];
|
||||
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */
|
||||
|
||||
#define MD_CONTEXT_AMD64_VR_COUNT 26
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* Register parameter home addresses.
|
||||
*/
|
||||
uint64_t p1_home;
|
||||
uint64_t p2_home;
|
||||
uint64_t p3_home;
|
||||
uint64_t p4_home;
|
||||
uint64_t p5_home;
|
||||
uint64_t p6_home;
|
||||
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */
|
||||
uint32_t context_flags;
|
||||
uint32_t mx_csr;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
uint16_t cs;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */
|
||||
uint16_t ds;
|
||||
uint16_t es;
|
||||
uint16_t fs;
|
||||
uint16_t gs;
|
||||
|
||||
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
|
||||
uint16_t ss;
|
||||
uint32_t eflags;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
uint64_t dr0;
|
||||
uint64_t dr1;
|
||||
uint64_t dr2;
|
||||
uint64_t dr3;
|
||||
uint64_t dr6;
|
||||
uint64_t dr7;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||
uint64_t rax;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rbx;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
uint64_t rsp;
|
||||
|
||||
/* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */
|
||||
uint64_t rbp;
|
||||
uint64_t rsi;
|
||||
uint64_t rdi;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
|
||||
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
|
||||
uint64_t rip;
|
||||
|
||||
/* The next set of registers are included with
|
||||
* MD_CONTEXT_AMD64_FLOATING_POINT
|
||||
*/
|
||||
union {
|
||||
MDXmmSaveArea32AMD64 flt_save;
|
||||
struct {
|
||||
uint128_struct header[2];
|
||||
uint128_struct legacy[8];
|
||||
uint128_struct xmm0;
|
||||
uint128_struct xmm1;
|
||||
uint128_struct xmm2;
|
||||
uint128_struct xmm3;
|
||||
uint128_struct xmm4;
|
||||
uint128_struct xmm5;
|
||||
uint128_struct xmm6;
|
||||
uint128_struct xmm7;
|
||||
uint128_struct xmm8;
|
||||
uint128_struct xmm9;
|
||||
uint128_struct xmm10;
|
||||
uint128_struct xmm11;
|
||||
uint128_struct xmm12;
|
||||
uint128_struct xmm13;
|
||||
uint128_struct xmm14;
|
||||
uint128_struct xmm15;
|
||||
} sse_registers;
|
||||
};
|
||||
|
||||
uint128_struct vector_register[MD_CONTEXT_AMD64_VR_COUNT];
|
||||
uint64_t vector_control;
|
||||
|
||||
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
uint64_t debug_control;
|
||||
uint64_t last_branch_to_rip;
|
||||
uint64_t last_branch_from_rip;
|
||||
uint64_t last_exception_to_rip;
|
||||
uint64_t last_exception_from_rip;
|
||||
|
||||
} MDRawContextAMD64; /* CONTEXT */
|
||||
|
||||
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 24 bits identify the CPU, the
|
||||
* low 8 bits identify the type of context saved. */
|
||||
#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */
|
||||
#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001)
|
||||
/* CONTEXT_CONTROL */
|
||||
#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002)
|
||||
/* CONTEXT_INTEGER */
|
||||
#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004)
|
||||
/* CONTEXT_SEGMENTS */
|
||||
#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008)
|
||||
/* CONTEXT_FLOATING_POINT */
|
||||
#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)
|
||||
/* CONTEXT_DEBUG_REGISTERS */
|
||||
#define MD_CONTEXT_AMD64_XSTATE (MD_CONTEXT_AMD64 | 0x00000040)
|
||||
/* CONTEXT_XSTATE */
|
||||
|
||||
/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
|
||||
* I think it really means CONTEXT_FLOATING_POINT.
|
||||
*/
|
||||
|
||||
#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \
|
||||
MD_CONTEXT_AMD64_INTEGER | \
|
||||
MD_CONTEXT_AMD64_FLOATING_POINT)
|
||||
/* CONTEXT_FULL */
|
||||
|
||||
#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \
|
||||
MD_CONTEXT_AMD64_SEGMENTS | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS)
|
||||
/* CONTEXT_ALL */
|
||||
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */
|
||||
@@ -0,0 +1,151 @@
|
||||
/* Copyright (c) 2009, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on ARM. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by
|
||||
* ensuring that all members are aligned on their natural boundaries.
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file.
|
||||
*
|
||||
* Author: Julian Seward
|
||||
*/
|
||||
|
||||
/*
|
||||
* ARM support
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_ARM_FPR_COUNT 32
|
||||
#define MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT 8
|
||||
|
||||
/*
|
||||
* Note that these structures *do not* map directly to the CONTEXT
|
||||
* structure defined in WinNT.h in the Windows Mobile SDK. That structure
|
||||
* does not accomodate VFPv3, and I'm unsure if it was ever used in the
|
||||
* wild anyway, as Windows CE only seems to produce "cedumps" which
|
||||
* are not exactly minidumps.
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t fpscr; /* FPU status register */
|
||||
|
||||
/* 32 64-bit floating point registers, d0 .. d31. */
|
||||
uint64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT];
|
||||
|
||||
/* Miscellaneous control words */
|
||||
uint32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT];
|
||||
} MDFloatingSaveAreaARM;
|
||||
|
||||
#define MD_CONTEXT_ARM_GPR_COUNT 16
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated
|
||||
*/
|
||||
uint32_t context_flags;
|
||||
|
||||
/* 16 32-bit integer registers, r0 .. r15
|
||||
* Note the following fixed uses:
|
||||
* r13 is the stack pointer
|
||||
* r14 is the link register
|
||||
* r15 is the program counter
|
||||
*/
|
||||
uint32_t iregs[MD_CONTEXT_ARM_GPR_COUNT];
|
||||
|
||||
/* CPSR (flags, basically): 32 bits:
|
||||
bit 31 - N (negative)
|
||||
bit 30 - Z (zero)
|
||||
bit 29 - C (carry)
|
||||
bit 28 - V (overflow)
|
||||
bit 27 - Q (saturation flag, sticky)
|
||||
All other fields -- ignore */
|
||||
uint32_t cpsr;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_ARM_FLOATING_POINT */
|
||||
MDFloatingSaveAreaARM float_save;
|
||||
|
||||
} MDRawContextARM;
|
||||
|
||||
/* Indices into iregs for registers with a dedicated or conventional
|
||||
* purpose.
|
||||
*/
|
||||
enum MDARMRegisterNumbers {
|
||||
MD_CONTEXT_ARM_REG_IOS_FP = 7,
|
||||
MD_CONTEXT_ARM_REG_FP = 11,
|
||||
MD_CONTEXT_ARM_REG_SP = 13,
|
||||
MD_CONTEXT_ARM_REG_LR = 14,
|
||||
MD_CONTEXT_ARM_REG_PC = 15
|
||||
};
|
||||
|
||||
/* For (MDRawContextARM).context_flags. These values indicate the type of
|
||||
* context stored in the structure. */
|
||||
/* CONTEXT_ARM from the Windows CE 5.0 SDK. This value isn't correct
|
||||
* because this bit can be used for flags. Presumably this value was
|
||||
* never actually used in minidumps, but only in "CEDumps" which
|
||||
* are a whole parallel minidump file format for Windows CE.
|
||||
* Therefore, Breakpad defines its own value for ARM CPUs.
|
||||
*/
|
||||
#define MD_CONTEXT_ARM_OLD 0x00000040
|
||||
/* This value was chosen to avoid likely conflicts with MD_CONTEXT_*
|
||||
* for other CPUs. */
|
||||
#define MD_CONTEXT_ARM 0x40000000
|
||||
#define MD_CONTEXT_ARM_INTEGER (MD_CONTEXT_ARM | 0x00000002)
|
||||
#define MD_CONTEXT_ARM_FLOATING_POINT (MD_CONTEXT_ARM | 0x00000004)
|
||||
|
||||
#define MD_CONTEXT_ARM_FULL (MD_CONTEXT_ARM_INTEGER | \
|
||||
MD_CONTEXT_ARM_FLOATING_POINT)
|
||||
|
||||
#define MD_CONTEXT_ARM_ALL (MD_CONTEXT_ARM_INTEGER | \
|
||||
MD_CONTEXT_ARM_FLOATING_POINT)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ */
|
||||
@@ -0,0 +1,178 @@
|
||||
/* Copyright (c) 2013, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on MIPS. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by
|
||||
* ensuring that all members are aligned on their natural boundaries.
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file.
|
||||
*
|
||||
* Author: Chris Dearman
|
||||
*/
|
||||
|
||||
/*
|
||||
* MIPS support
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
|
||||
|
||||
#if defined(__mips__) && !defined(__ANDROID__)
|
||||
typedef struct {
|
||||
uint64_t regs[32];
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
uint64_t epc;
|
||||
uint64_t badvaddr;
|
||||
uint64_t status;
|
||||
uint64_t cause;
|
||||
} user_regs_struct;
|
||||
|
||||
typedef struct {
|
||||
uint64_t regs[32];
|
||||
uint32_t fpcsr;
|
||||
uint32_t fir;
|
||||
} user_fpregs_struct;
|
||||
#endif
|
||||
|
||||
#define MD_CONTEXT_MIPS_GPR_COUNT 32
|
||||
#define MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT 32
|
||||
#define MD_CONTEXT_MIPS_DSP_COUNT 3
|
||||
|
||||
/*
|
||||
* Note that these structures *do not* map directly to the CONTEXT
|
||||
* structure defined in WinNT.h in the Windows Mobile SDK. That structure
|
||||
* does not accomodate VFPv3, and I'm unsure if it was ever used in the
|
||||
* wild anyway, as Windows CE only seems to produce "cedumps" which
|
||||
* are not exactly minidumps.
|
||||
*/
|
||||
typedef struct {
|
||||
/* 32 64-bit floating point registers, f0..f31 */
|
||||
uint64_t regs[MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT];
|
||||
|
||||
uint32_t fpcsr; /* FPU status register. */
|
||||
uint32_t fir; /* FPU implementation register. */
|
||||
} MDFloatingSaveAreaMIPS;
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated.
|
||||
*/
|
||||
uint32_t context_flags;
|
||||
uint32_t _pad0;
|
||||
|
||||
/* 32 64-bit integer registers, r0..r31.
|
||||
* Note the following fixed uses:
|
||||
* r30 is the stack pointer.
|
||||
* r31 is the return address (link register).
|
||||
*/
|
||||
uint64_t iregs[MD_CONTEXT_MIPS_GPR_COUNT];
|
||||
|
||||
/* multiply/divide result. */
|
||||
uint64_t mdhi, mdlo;
|
||||
|
||||
/* DSP accumulators. */
|
||||
uint32_t hi[MD_CONTEXT_MIPS_DSP_COUNT];
|
||||
uint32_t lo[MD_CONTEXT_MIPS_DSP_COUNT];
|
||||
uint32_t dsp_control;
|
||||
uint32_t _pad1;
|
||||
|
||||
uint64_t epc;
|
||||
uint64_t badvaddr;
|
||||
uint32_t status;
|
||||
uint32_t cause;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_MIPS_FLOATING_POINT. */
|
||||
MDFloatingSaveAreaMIPS float_save;
|
||||
|
||||
} MDRawContextMIPS;
|
||||
|
||||
/* Indices into iregs for registers with a dedicated or conventional
|
||||
* purpose.
|
||||
*/
|
||||
enum MDMIPSRegisterNumbers {
|
||||
MD_CONTEXT_MIPS_REG_S0 = 16,
|
||||
MD_CONTEXT_MIPS_REG_S1 = 17,
|
||||
MD_CONTEXT_MIPS_REG_S2 = 18,
|
||||
MD_CONTEXT_MIPS_REG_S3 = 19,
|
||||
MD_CONTEXT_MIPS_REG_S4 = 20,
|
||||
MD_CONTEXT_MIPS_REG_S5 = 21,
|
||||
MD_CONTEXT_MIPS_REG_S6 = 22,
|
||||
MD_CONTEXT_MIPS_REG_S7 = 23,
|
||||
MD_CONTEXT_MIPS_REG_GP = 28,
|
||||
MD_CONTEXT_MIPS_REG_SP = 29,
|
||||
MD_CONTEXT_MIPS_REG_FP = 30,
|
||||
MD_CONTEXT_MIPS_REG_RA = 31,
|
||||
};
|
||||
|
||||
/* For (MDRawContextMIPS).context_flags. These values indicate the type of
|
||||
* context stored in the structure. */
|
||||
/* CONTEXT_MIPS from the Windows CE 5.0 SDK. This value isn't correct
|
||||
* because this bit can be used for flags. Presumably this value was
|
||||
* never actually used in minidumps, but only in "CEDumps" which
|
||||
* are a whole parallel minidump file format for Windows CE.
|
||||
* Therefore, Breakpad defines its own value for MIPS CPUs.
|
||||
*/
|
||||
#define MD_CONTEXT_MIPS 0x00040000
|
||||
#define MD_CONTEXT_MIPS_INTEGER (MD_CONTEXT_MIPS | 0x00000002)
|
||||
#define MD_CONTEXT_MIPS_FLOATING_POINT (MD_CONTEXT_MIPS | 0x00000004)
|
||||
#define MD_CONTEXT_MIPS_DSP (MD_CONTEXT_MIPS | 0x00000008)
|
||||
|
||||
#define MD_CONTEXT_MIPS_FULL (MD_CONTEXT_MIPS_INTEGER | \
|
||||
MD_CONTEXT_MIPS_FLOATING_POINT | \
|
||||
MD_CONTEXT_MIPS_DSP)
|
||||
|
||||
#define MD_CONTEXT_MIPS_ALL (MD_CONTEXT_MIPS_INTEGER | \
|
||||
MD_CONTEXT_MIPS_FLOATING_POINT \
|
||||
MD_CONTEXT_MIPS_DSP)
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
|
||||
@@ -0,0 +1,163 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on ppc. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */
|
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X'
|
||||
* mach/ppc/_types.h
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* fpregs is a double[32] in mach/ppc/_types.h, but a uint64_t is used
|
||||
* here for precise sizing. */
|
||||
uint64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];
|
||||
uint32_t fpscr_pad;
|
||||
uint32_t fpscr; /* Status/control */
|
||||
} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */
|
||||
|
||||
|
||||
#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
|
||||
* exposes them as four 32-bit quantities. */
|
||||
uint128_struct save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
|
||||
uint128_struct save_vscr; /* Status/control */
|
||||
uint32_t save_pad5[4];
|
||||
uint32_t save_vrvalid; /* Indicates which vector registers are saved */
|
||||
uint32_t save_pad6[7];
|
||||
} MDVectorSaveAreaPPC; /* ppc_vector_state */
|
||||
|
||||
|
||||
#define MD_CONTEXT_PPC_GPR_COUNT 32
|
||||
|
||||
/* Use the same 32-bit alignment when accessing this structure from 64-bit code
|
||||
* as is used natively in 32-bit code. #pragma pack is a MSVC extension
|
||||
* supported by gcc. */
|
||||
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
#pragma pack(4)
|
||||
#else
|
||||
#pragma pack(push, 4)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types,
|
||||
* and it guarantees alignment when we get to float_save. */
|
||||
uint32_t context_flags;
|
||||
|
||||
uint32_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */
|
||||
uint32_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */
|
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */
|
||||
uint32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
|
||||
uint32_t cr; /* Condition */
|
||||
uint32_t xer; /* Integer (fiXed-point) exception */
|
||||
uint32_t lr; /* Link */
|
||||
uint32_t ctr; /* Count */
|
||||
uint32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
|
||||
uint32_t vrsave; /* Vector save */
|
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's
|
||||
* context. */
|
||||
MDFloatingSaveAreaPPC float_save;
|
||||
MDVectorSaveAreaPPC vector_save;
|
||||
} MDRawContextPPC; /* Based on ppc_thread_state */
|
||||
|
||||
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
/* For (MDRawContextPPC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_PPC 0x20000000
|
||||
#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001)
|
||||
#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
|
||||
#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020)
|
||||
|
||||
#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE
|
||||
#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \
|
||||
MD_CONTEXT_PPC_FLOATING_POINT | \
|
||||
MD_CONTEXT_PPC_VECTOR)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */
|
||||
@@ -0,0 +1,129 @@
|
||||
/* 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on ppc64. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Neal Sidhwaney */
|
||||
|
||||
|
||||
/*
|
||||
* Breakpad minidump extension for PPC64 support. Based on Darwin/Mac OS X'
|
||||
* mach/ppc/_types.h
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
|
||||
|
||||
#include "CpuPpc.h"
|
||||
|
||||
// these types are the same in ppc64 & ppc
|
||||
typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64;
|
||||
typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64;
|
||||
|
||||
#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT
|
||||
|
||||
typedef struct {
|
||||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types,
|
||||
* and it guarantees alignment when we get to float_save. */
|
||||
uint64_t context_flags;
|
||||
|
||||
uint64_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */
|
||||
uint64_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */
|
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */
|
||||
uint64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT];
|
||||
uint64_t cr; /* Condition */
|
||||
uint64_t xer; /* Integer (fiXed-point) exception */
|
||||
uint64_t lr; /* Link */
|
||||
uint64_t ctr; /* Count */
|
||||
uint64_t vrsave; /* Vector save */
|
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's
|
||||
* context. */
|
||||
MDFloatingSaveAreaPPC float_save;
|
||||
MDVectorSaveAreaPPC vector_save;
|
||||
} MDRawContextPPC64; /* Based on ppc_thread_state */
|
||||
|
||||
/* For (MDRawContextPPC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_PPC64 0x01000000
|
||||
#define MD_CONTEXT_PPC64_BASE (MD_CONTEXT_PPC64 | 0x00000001)
|
||||
#define MD_CONTEXT_PPC64_FLOATING_POINT (MD_CONTEXT_PPC64 | 0x00000008)
|
||||
#define MD_CONTEXT_PPC64_VECTOR (MD_CONTEXT_PPC64 | 0x00000020)
|
||||
|
||||
#define MD_CONTEXT_PPC64_FULL MD_CONTEXT_PPC64_BASE
|
||||
#define MD_CONTEXT_PPC64_ALL (MD_CONTEXT_PPC64_FULL | \
|
||||
MD_CONTEXT_PPC64_FLOATING_POINT | \
|
||||
MD_CONTEXT_PPC64_VECTOR)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */
|
||||
@@ -0,0 +1,158 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on sparc. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */
|
||||
|
||||
/*
|
||||
* SPARC support, see (solaris)sys/procfs_isa.h also
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* FPU floating point regs */
|
||||
uint64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
|
||||
|
||||
uint64_t filler;
|
||||
uint64_t fsr; /* FPU status register */
|
||||
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */
|
||||
|
||||
#define MD_CONTEXT_SPARC_GPR_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated
|
||||
*/
|
||||
uint32_t context_flags;
|
||||
uint32_t flag_pad;
|
||||
/*
|
||||
* General register access (SPARC).
|
||||
* Don't confuse definitions here with definitions in <sys/regset.h>.
|
||||
* Registers are 32 bits for ILP32, 64 bits for LP64.
|
||||
* SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit
|
||||
*/
|
||||
|
||||
/* 32 Integer working registers */
|
||||
|
||||
/* g_r[0-7] global registers(g0-g7)
|
||||
* g_r[8-15] out registers(o0-o7)
|
||||
* g_r[16-23] local registers(l0-l7)
|
||||
* g_r[24-31] in registers(i0-i7)
|
||||
*/
|
||||
uint64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT];
|
||||
|
||||
/* several control registers */
|
||||
|
||||
/* Processor State register(PSR) for SPARC V7/V8
|
||||
* Condition Code register (CCR) for SPARC V9
|
||||
*/
|
||||
uint64_t ccr;
|
||||
|
||||
uint64_t pc; /* Program Counter register (PC) */
|
||||
uint64_t npc; /* Next Program Counter register (nPC) */
|
||||
uint64_t y; /* Y register (Y) */
|
||||
|
||||
/* Address Space Identifier register (ASI) for SPARC V9
|
||||
* WIM for SPARC V7/V8
|
||||
*/
|
||||
uint64_t asi;
|
||||
|
||||
/* Floating-Point Registers State register (FPRS) for SPARC V9
|
||||
* TBR for for SPARC V7/V8
|
||||
*/
|
||||
uint64_t fprs;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */
|
||||
MDFloatingSaveAreaSPARC float_save;
|
||||
|
||||
} MDRawContextSPARC; /* CONTEXT_SPARC */
|
||||
|
||||
/* For (MDRawContextSPARC).context_flags. These values indicate the type of
|
||||
* context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its
|
||||
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
|
||||
* CPUs. */
|
||||
#define MD_CONTEXT_SPARC 0x10000000
|
||||
#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001)
|
||||
#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002)
|
||||
#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004)
|
||||
#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008)
|
||||
|
||||
#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \
|
||||
MD_CONTEXT_SPARC_INTEGER)
|
||||
|
||||
#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \
|
||||
MD_CONTEXT_SAPARC_FLOATING_POINT | \
|
||||
MD_CONTEXT_SAPARC_EXTRA)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */
|
||||
@@ -0,0 +1,174 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* This file contains the necessary definitions to read minidump files
|
||||
* produced on x86. These files may be read on any platform provided
|
||||
* that the alignments of these structures on the processing system are
|
||||
* identical to the alignments of these structures on the producing system.
|
||||
* For this reason, precise-sized types are used. The structures defined
|
||||
* by this file have been laid out to minimize alignment problems by ensuring
|
||||
* ensuring that all members are aligned on their natural boundaries. In
|
||||
* In some cases, tail-padding may be significant when different ABIs specify
|
||||
* different tail-padding behaviors. To avoid problems when reading or
|
||||
* writing affected structures, MD_*_SIZE macros are provided where needed,
|
||||
* containing the useful size of the structures without padding.
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai */
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
|
||||
|
||||
#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80
|
||||
/* SIZE_OF_80387_REGISTERS */
|
||||
|
||||
typedef struct {
|
||||
uint32_t control_word;
|
||||
uint32_t status_word;
|
||||
uint32_t tag_word;
|
||||
uint32_t error_offset;
|
||||
uint32_t error_selector;
|
||||
uint32_t data_offset;
|
||||
uint32_t data_selector;
|
||||
|
||||
/* register_area contains eight 80-bit (x87 "long double") quantities for
|
||||
* floating-point registers %st0 (%mm0) through %st7 (%mm7). */
|
||||
uint8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];
|
||||
uint32_t cr0_npx_state;
|
||||
} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */
|
||||
|
||||
|
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512
|
||||
/* MAXIMUM_SUPPORTED_EXTENSION */
|
||||
|
||||
typedef struct {
|
||||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated */
|
||||
uint32_t context_flags;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */
|
||||
uint32_t dr0;
|
||||
uint32_t dr1;
|
||||
uint32_t dr2;
|
||||
uint32_t dr3;
|
||||
uint32_t dr6;
|
||||
uint32_t dr7;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */
|
||||
MDFloatingSaveAreaX86 float_save;
|
||||
|
||||
/* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */
|
||||
uint32_t gs;
|
||||
uint32_t fs;
|
||||
uint32_t es;
|
||||
uint32_t ds;
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebx;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t eax;
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */
|
||||
uint32_t ebp;
|
||||
uint32_t eip;
|
||||
uint32_t cs; /* WinNT.h says "must be sanitized" */
|
||||
uint32_t eflags; /* WinNT.h says "must be sanitized" */
|
||||
uint32_t esp;
|
||||
uint32_t ss;
|
||||
|
||||
/* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.
|
||||
* It contains vector (MMX/SSE) registers. It it laid out in the
|
||||
* format used by the fxsave and fsrstor instructions, so it includes
|
||||
* a copy of the x87 floating-point registers as well. See FXSAVE in
|
||||
* "Intel Architecture Software Developer's Manual, Volume 2." */
|
||||
uint8_t extended_registers[
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE];
|
||||
} MDRawContextX86; /* CONTEXT */
|
||||
|
||||
/* For (MDRawContextX86).context_flags. These values indicate the type of
|
||||
* context stored in the structure. The high 24 bits identify the CPU, the
|
||||
* low 8 bits identify the type of context saved. */
|
||||
#define MD_CONTEXT_X86 0x00010000
|
||||
/* CONTEXT_i386, CONTEXT_i486: identifies CPU */
|
||||
#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001)
|
||||
/* CONTEXT_CONTROL */
|
||||
#define MD_CONTEXT_X86_INTEGER (MD_CONTEXT_X86 | 0x00000002)
|
||||
/* CONTEXT_INTEGER */
|
||||
#define MD_CONTEXT_X86_SEGMENTS (MD_CONTEXT_X86 | 0x00000004)
|
||||
/* CONTEXT_SEGMENTS */
|
||||
#define MD_CONTEXT_X86_FLOATING_POINT (MD_CONTEXT_X86 | 0x00000008)
|
||||
/* CONTEXT_FLOATING_POINT */
|
||||
#define MD_CONTEXT_X86_DEBUG_REGISTERS (MD_CONTEXT_X86 | 0x00000010)
|
||||
/* CONTEXT_DEBUG_REGISTERS */
|
||||
#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020)
|
||||
/* CONTEXT_EXTENDED_REGISTERS */
|
||||
#define MD_CONTEXT_X86_XSTATE (MD_CONTEXT_X86 | 0x00000040)
|
||||
/* CONTEXT_XSTATE */
|
||||
|
||||
#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \
|
||||
MD_CONTEXT_X86_INTEGER | \
|
||||
MD_CONTEXT_X86_SEGMENTS)
|
||||
/* CONTEXT_FULL */
|
||||
|
||||
#define MD_CONTEXT_X86_ALL (MD_CONTEXT_X86_FULL | \
|
||||
MD_CONTEXT_X86_FLOATING_POINT | \
|
||||
MD_CONTEXT_X86_DEBUG_REGISTERS | \
|
||||
MD_CONTEXT_X86_EXTENDED_REGISTERS)
|
||||
/* CONTEXT_ALL */
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */
|
||||
@@ -0,0 +1,376 @@
|
||||
#include "CrashClient.h"
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
//#include "IpcProtocol.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
const int kPipeBusyWaitTimeoutMs = 2000;
|
||||
|
||||
#ifdef _DEBUG
|
||||
const DWORD kWaitForServerTimeoutMs = INFINITE;
|
||||
#else
|
||||
const DWORD kWaitForServerTimeoutMs = 15000;
|
||||
#endif
|
||||
|
||||
const int kPipeConnectMaxAttempts = 2;
|
||||
|
||||
const DWORD kPipeDesiredAccess = FILE_READ_DATA |
|
||||
FILE_WRITE_DATA |
|
||||
FILE_WRITE_ATTRIBUTES;
|
||||
|
||||
const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
|
||||
SECURITY_SQOS_PRESENT;
|
||||
|
||||
const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
|
||||
|
||||
const size_t kWaitEventCount = 2;
|
||||
|
||||
// This function is orphan for production code. It can be used
|
||||
// for debugging to help repro some scenarios like the client
|
||||
// is slow in writing to the pipe after connecting, the client
|
||||
// is slow in reading from the pipe after writing, etc. The parameter
|
||||
// overlapped below is not used and it is present to match the signature
|
||||
// of this function to TransactNamedPipe Win32 API. Uncomment if needed
|
||||
// for debugging.
|
||||
/**
|
||||
static bool TransactNamedPipeDebugHelper(HANDLE pipe,
|
||||
const void* in_buffer,
|
||||
DWORD in_size,
|
||||
void* out_buffer,
|
||||
DWORD out_size,
|
||||
DWORD* bytes_count,
|
||||
LPOVERLAPPED) {
|
||||
// Uncomment the next sleep to create a gap before writing
|
||||
// to pipe.
|
||||
// Sleep(5000);
|
||||
|
||||
if (!WriteFile(pipe,
|
||||
in_buffer,
|
||||
in_size,
|
||||
bytes_count,
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Uncomment the next sleep to create a gap between write
|
||||
// and read.
|
||||
// Sleep(5000);
|
||||
|
||||
return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
|
||||
}
|
||||
**/
|
||||
|
||||
CrashGenerationClient::CrashGenerationClient(
|
||||
const TCHAR* pipe_name,
|
||||
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),
|
||||
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() {
|
||||
if (crash_event_) {
|
||||
CloseHandle(crash_event_);
|
||||
}
|
||||
|
||||
if (crash_generated_) {
|
||||
CloseHandle(crash_generated_);
|
||||
}
|
||||
|
||||
if (server_alive_) {
|
||||
CloseHandle(server_alive_);
|
||||
}
|
||||
}
|
||||
|
||||
// Performs the registration step with the server process.
|
||||
// The registration step involves communicating with the server
|
||||
// via a named pipe. The client sends the following pieces of
|
||||
// data to the server:
|
||||
//
|
||||
// * Message tag indicating the client is requesting registration.
|
||||
// * Process id of the client process.
|
||||
// * Address of a DWORD variable in the client address space
|
||||
// that will contain the thread id of the client thread that
|
||||
// caused the crash.
|
||||
// * Address of a EXCEPTION_POINTERS* variable in the client
|
||||
// address space that will point to an instance of EXCEPTION_POINTERS
|
||||
// when the crash happens.
|
||||
// * Address of an instance of MDRawAssertionInfo that will contain
|
||||
// relevant information in case of non-exception crashes like assertion
|
||||
// failures and pure calls.
|
||||
//
|
||||
// In return the client expects the following information from the server:
|
||||
//
|
||||
// * Message tag indicating successful registration.
|
||||
// * Server process id.
|
||||
// * Handle to an object that client can signal to request dump
|
||||
// generation from the server.
|
||||
// * Handle to an object that client can wait on after requesting
|
||||
// dump generation for the server to finish dump generation.
|
||||
// * Handle to a mutex object that client can wait on to make sure
|
||||
// server is still alive.
|
||||
//
|
||||
// If any step of the expected behavior mentioned above fails, the
|
||||
// registration step is not considered successful and hence out-of-process
|
||||
// dump generation service is not available.
|
||||
//
|
||||
// Returns true if the registration is successful; false otherwise.
|
||||
bool CrashGenerationClient::Register() {
|
||||
if (IsRegistered()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE pipe = ConnectToServer();
|
||||
if (!pipe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = RegisterClient(pipe);
|
||||
CloseHandle(pipe);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestUpload(DWORD crash_id) {
|
||||
HANDLE pipe = ConnectToServer();
|
||||
if (!pipe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomClientInfo custom_info = {NULL, 0};
|
||||
ProtocolMessage msg(MESSAGE_TAG_UPLOAD_REQUEST, crash_id,
|
||||
static_cast<MINIDUMP_TYPE>(NULL), NULL, NULL, NULL,
|
||||
custom_info, NULL, NULL, NULL);
|
||||
DWORD bytes_count = 0;
|
||||
bool success = WriteFile(pipe, &msg, sizeof(msg), &bytes_count, NULL) != 0;
|
||||
|
||||
CloseHandle(pipe);
|
||||
return success;
|
||||
}
|
||||
|
||||
HANDLE CrashGenerationClient::ConnectToServer() {
|
||||
HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
|
||||
kPipeDesiredAccess,
|
||||
kPipeFlagsAndAttributes);
|
||||
if (!pipe) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWORD mode = kPipeMode;
|
||||
if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
|
||||
CloseHandle(pipe);
|
||||
pipe = NULL;
|
||||
}
|
||||
|
||||
return pipe;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
|
||||
ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
|
||||
GetCurrentProcessId(),
|
||||
dump_type_,
|
||||
&thread_id_,
|
||||
&exception_pointers_,
|
||||
&assert_info_,
|
||||
custom_info_,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
ProtocolMessage reply;
|
||||
DWORD bytes_count = 0;
|
||||
// The call to TransactNamedPipe below can be changed to a call
|
||||
// to TransactNamedPipeDebugHelper to help repro some scenarios.
|
||||
// For details see comments for TransactNamedPipeDebugHelper.
|
||||
if (!TransactNamedPipe(pipe,
|
||||
&msg,
|
||||
sizeof(msg),
|
||||
&reply,
|
||||
sizeof(ProtocolMessage),
|
||||
&bytes_count,
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateResponse(reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProtocolMessage ack_msg;
|
||||
ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
|
||||
|
||||
if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
|
||||
return false;
|
||||
}
|
||||
crash_event_ = reply.dump_request_handle;
|
||||
crash_generated_ = reply.dump_generated_handle;
|
||||
server_alive_ = reply.server_alive_handle;
|
||||
server_process_id_ = reply.id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE CrashGenerationClient::ConnectToPipe(const TCHAR* 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,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
flags_attrs,
|
||||
NULL);
|
||||
if (pipe != INVALID_HANDLE_VALUE) {
|
||||
return pipe;
|
||||
}
|
||||
|
||||
// Cannot continue retrying if error is something other than
|
||||
// ERROR_PIPE_BUSY.
|
||||
if (GetLastError() != ERROR_PIPE_BUSY) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Cannot continue retrying if wait on pipe fails.
|
||||
if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::ValidateResponse(
|
||||
const ProtocolMessage& msg) const {
|
||||
return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
|
||||
(msg.id != 0) &&
|
||||
(msg.dump_request_handle != NULL) &&
|
||||
(msg.dump_generated_handle != NULL) &&
|
||||
(msg.server_alive_handle != NULL);
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::IsRegistered() const {
|
||||
return crash_event_ != NULL;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info,
|
||||
MDRawAssertionInfo* assert_info) {
|
||||
if (!IsRegistered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
exception_pointers_ = ex_info;
|
||||
thread_id_ = GetCurrentThreadId();
|
||||
|
||||
if (assert_info) {
|
||||
memcpy(&assert_info_, assert_info, sizeof(assert_info_));
|
||||
} else {
|
||||
memset(&assert_info_, 0, sizeof(assert_info_));
|
||||
}
|
||||
|
||||
return SignalCrashEventAndWait();
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
|
||||
return RequestDump(ex_info, NULL);
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
|
||||
return RequestDump(NULL, assert_info);
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::SignalCrashEventAndWait() {
|
||||
assert(crash_event_);
|
||||
assert(crash_generated_);
|
||||
assert(server_alive_);
|
||||
|
||||
// Reset the dump generated event before signaling the crash
|
||||
// event so that the server can set the dump generated event
|
||||
// once it is done generating the event.
|
||||
if (!ResetEvent(crash_generated_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetEvent(crash_event_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
|
||||
|
||||
DWORD result = WaitForMultipleObjects(kWaitEventCount,
|
||||
wait_handles,
|
||||
FALSE,
|
||||
kWaitForServerTimeoutMs);
|
||||
|
||||
// Crash dump was successfully generated only if the server
|
||||
// signaled the crash generated event.
|
||||
return result == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
HANDLE CrashGenerationClient::DuplicatePipeToClientProcess(const TCHAR* 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
|
||||
@@ -0,0 +1,153 @@
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include "IpcProtocol.h"
|
||||
#include "ScopedPtr.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
struct CustomClientInfo;
|
||||
|
||||
// Abstraction of client-side implementation of out of process
|
||||
// crash generation.
|
||||
//
|
||||
// The process that desires to have out-of-process crash dump
|
||||
// generation service can use this class in the following way:
|
||||
//
|
||||
// * Create an instance.
|
||||
// * Call Register method so that the client tries to register
|
||||
// with the server process and check the return value. If
|
||||
// registration is not successful, out-of-process crash dump
|
||||
// generation will not be available
|
||||
// * Request dump generation by calling either of the two
|
||||
// overloaded RequestDump methods - one in case of exceptions
|
||||
// and the other in case of assertion failures
|
||||
//
|
||||
// Note that it is the responsibility of the client code of
|
||||
// this class to set the unhandled exception filter with the
|
||||
// system by calling the SetUnhandledExceptionFilter function
|
||||
// and the client code should explicitly request dump generation.
|
||||
class CrashGenerationClient {
|
||||
public:
|
||||
CrashGenerationClient(const TCHAR* pipe_name,
|
||||
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.
|
||||
//
|
||||
// Returns true if the registration is successful; false otherwise.
|
||||
bool Register();
|
||||
|
||||
// Requests the crash server to upload a previous dump with the
|
||||
// given crash id.
|
||||
bool RequestUpload(DWORD crash_id);
|
||||
|
||||
bool RequestDump(EXCEPTION_POINTERS* ex_info,
|
||||
MDRawAssertionInfo* assert_info);
|
||||
|
||||
// Requests the crash server to generate a dump with the given
|
||||
// exception information.
|
||||
//
|
||||
// Returns true if the dump was successful; false otherwise. Note that
|
||||
// if the registration step was not performed or it was not successful,
|
||||
// false will be returned.
|
||||
bool RequestDump(EXCEPTION_POINTERS* ex_info);
|
||||
|
||||
// Requests the crash server to generate a dump with the given
|
||||
// assertion information.
|
||||
//
|
||||
// Returns true if the dump was successful; false otherwise. Note that
|
||||
// if the registration step was not performed or it was not successful,
|
||||
// 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 TCHAR* pipe_name,
|
||||
HANDLE hProcess);
|
||||
|
||||
private:
|
||||
// Connects to the appropriate pipe and sets the pipe handle state.
|
||||
//
|
||||
// Returns the pipe handle if everything goes well; otherwise Returns NULL.
|
||||
HANDLE ConnectToServer();
|
||||
|
||||
// Performs a handshake with the server over the given pipe which should be
|
||||
// already connected to the server.
|
||||
//
|
||||
// Returns true if handshake with the server was successful; false otherwise.
|
||||
bool RegisterClient(HANDLE pipe);
|
||||
|
||||
// Validates the given server response.
|
||||
bool ValidateResponse(const ProtocolMessage& msg) const;
|
||||
|
||||
// Returns true if the registration step succeeded; false otherwise.
|
||||
bool IsRegistered() const;
|
||||
|
||||
// Connects to the given named pipe with given parameters.
|
||||
//
|
||||
// Returns true if the connection is successful; false otherwise.
|
||||
HANDLE ConnectToPipe(const TCHAR* pipe_name,
|
||||
DWORD pipe_access,
|
||||
DWORD flags_attrs);
|
||||
|
||||
// Signals the crash event and wait for the server to generate crash.
|
||||
bool SignalCrashEventAndWait();
|
||||
|
||||
// Pipe name to use to talk to server.
|
||||
std::string pipe_name_;
|
||||
|
||||
// Pipe handle duplicated from server process. Only valid before
|
||||
// Register is called.
|
||||
HANDLE pipe_handle_;
|
||||
|
||||
// Custom client information
|
||||
CustomClientInfo custom_info_;
|
||||
|
||||
// Type of dump to generate.
|
||||
MINIDUMP_TYPE dump_type_;
|
||||
|
||||
// Event to signal in case of a crash.
|
||||
HANDLE crash_event_;
|
||||
|
||||
// Handle to wait on after signaling a crash for the server
|
||||
// to finish generating crash dump.
|
||||
HANDLE crash_generated_;
|
||||
|
||||
// Handle to a mutex that will become signaled with WAIT_ABANDONED
|
||||
// if the server process goes down.
|
||||
HANDLE server_alive_;
|
||||
|
||||
// Server process id.
|
||||
DWORD server_process_id_;
|
||||
|
||||
// Id of the thread that caused the crash.
|
||||
DWORD thread_id_;
|
||||
|
||||
// Exception pointers for an exception crash.
|
||||
EXCEPTION_POINTERS* exception_pointers_;
|
||||
|
||||
// Assertion info for an invalid parameter or pure call crash.
|
||||
MDRawAssertionInfo assert_info_;
|
||||
|
||||
// Disable copy ctor and operator=.
|
||||
CrashGenerationClient(const CrashGenerationClient& crash_client);
|
||||
CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
@@ -0,0 +1,909 @@
|
||||
#include "CrashServer.h"
|
||||
#include <windows.h>
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include "AutoCriticalSection.h"
|
||||
#include "ScopedPtr.h"
|
||||
|
||||
#include "ClientInfo.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Output buffer size.
|
||||
static const size_t kOutBufferSize = 64;
|
||||
|
||||
// Input buffer size.
|
||||
static const size_t kInBufferSize = 64;
|
||||
|
||||
// Access flags for the client on the dump request event.
|
||||
static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
|
||||
|
||||
// Access flags for the client on the dump generated event.
|
||||
static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
|
||||
SYNCHRONIZE;
|
||||
|
||||
// Access flags for the client on the mutex.
|
||||
static const DWORD kMutexAccess = SYNCHRONIZE;
|
||||
|
||||
// Attribute flags for the pipe.
|
||||
static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
|
||||
PIPE_ACCESS_DUPLEX |
|
||||
FILE_FLAG_OVERLAPPED;
|
||||
|
||||
// Mode for the pipe.
|
||||
static const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
|
||||
PIPE_READMODE_MESSAGE |
|
||||
PIPE_WAIT;
|
||||
|
||||
// For pipe I/O, execute the callback in the wait thread itself,
|
||||
// since the callback does very little work. The callback executes
|
||||
// the code for one of the states of the server state machine and
|
||||
// the code for all of the states perform async I/O and hence
|
||||
// finish very quickly.
|
||||
static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
|
||||
|
||||
// Dump request threads will, most likely, generate dumps. That may
|
||||
// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
|
||||
static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
|
||||
WT_EXECUTELONGFUNCTION;
|
||||
|
||||
static bool IsClientRequestValid(const ProtocolMessage& msg) {
|
||||
return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST ||
|
||||
(msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
|
||||
msg.id != 0 &&
|
||||
msg.thread_id != NULL &&
|
||||
msg.exception_pointers != NULL &&
|
||||
msg.assert_info != NULL);
|
||||
}
|
||||
|
||||
CrashGenerationServer::CrashGenerationServer(
|
||||
const std::wstring& pipe_name,
|
||||
SECURITY_ATTRIBUTES* pipe_sec_attrs,
|
||||
OnClientConnectedCallback connect_callback,
|
||||
void* connect_context,
|
||||
OnClientDumpRequestCallback dump_callback,
|
||||
void* dump_context,
|
||||
OnClientExitedCallback exit_callback,
|
||||
void* exit_context,
|
||||
OnClientUploadRequestCallback upload_request_callback,
|
||||
void* upload_context,
|
||||
bool generate_dumps,
|
||||
const std::wstring* dump_path)
|
||||
: pipe_name_(pipe_name),
|
||||
pipe_sec_attrs_(pipe_sec_attrs),
|
||||
pipe_(NULL),
|
||||
pipe_wait_handle_(NULL),
|
||||
server_alive_handle_(NULL),
|
||||
connect_callback_(connect_callback),
|
||||
connect_context_(connect_context),
|
||||
dump_callback_(dump_callback),
|
||||
dump_context_(dump_context),
|
||||
exit_callback_(exit_callback),
|
||||
exit_context_(exit_context),
|
||||
upload_request_callback_(upload_request_callback),
|
||||
upload_context_(upload_context),
|
||||
generate_dumps_(generate_dumps),
|
||||
dump_generator_(NULL),
|
||||
server_state_(IPC_SERVER_STATE_UNINITIALIZED),
|
||||
shutting_down_(false),
|
||||
overlapped_(),
|
||||
client_info_(NULL),
|
||||
pre_fetch_custom_info_(true) {
|
||||
InitializeCriticalSection(&sync_);
|
||||
|
||||
if (dump_path) {
|
||||
dump_generator_.reset(new MinidumpGenerator(*dump_path));
|
||||
}
|
||||
}
|
||||
|
||||
// This should never be called from the OnPipeConnected callback.
|
||||
// Otherwise the UnregisterWaitEx call below will cause a deadlock.
|
||||
CrashGenerationServer::~CrashGenerationServer() {
|
||||
// New scope to release the lock automatically.
|
||||
{
|
||||
// Make sure no clients are added or removed beyond this point.
|
||||
// Before adding or removing any clients, the critical section
|
||||
// must be entered and the shutting_down_ flag checked. The
|
||||
// critical section is then exited only after the clients_ list
|
||||
// modifications are done and the list is in a consistent state.
|
||||
AutoCriticalSection lock(&sync_);
|
||||
|
||||
// Indicate to existing threads that server is shutting down.
|
||||
shutting_down_ = true;
|
||||
}
|
||||
// No one will modify the clients_ list beyond this point -
|
||||
// not even from another thread.
|
||||
|
||||
// Even if there are no current worker threads running, it is possible that
|
||||
// an I/O request is pending on the pipe right now but not yet done.
|
||||
// In fact, it's very likely this is the case unless we are in an ERROR
|
||||
// state. If we don't wait for the pending I/O to be done, then when the I/O
|
||||
// completes, it may write to invalid memory. AppVerifier will flag this
|
||||
// problem too. So we disconnect from the pipe and then wait for the server
|
||||
// to get into error state so that the pending I/O will fail and get
|
||||
// cleared.
|
||||
DisconnectNamedPipe(pipe_);
|
||||
int num_tries = 100;
|
||||
while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {
|
||||
Sleep(10);
|
||||
}
|
||||
|
||||
// Unregister wait on the pipe.
|
||||
if (pipe_wait_handle_) {
|
||||
// Wait for already executing callbacks to finish.
|
||||
UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
// Close the pipe to avoid further client connections.
|
||||
if (pipe_) {
|
||||
CloseHandle(pipe_);
|
||||
}
|
||||
|
||||
// Request all ClientInfo objects to unregister all waits.
|
||||
// No need to enter the critical section because no one is allowed to modify
|
||||
// the clients_ list once the shutting_down_ flag is set.
|
||||
std::list<ClientInfo*>::iterator iter;
|
||||
for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
|
||||
ClientInfo* client_info = *iter;
|
||||
// Unregister waits. Wait for already executing callbacks to finish.
|
||||
// Unregister the client process exit wait first and only then unregister
|
||||
// the dump request wait. The reason is that the OnClientExit callback
|
||||
// also unregisters the dump request wait and such a race (doing the same
|
||||
// unregistration from two threads) is undesirable.
|
||||
client_info->UnregisterProcessExitWait(true);
|
||||
client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending();
|
||||
|
||||
// Destroying the ClientInfo here is safe because all wait operations for
|
||||
// this ClientInfo were unregistered and no pending or running callbacks
|
||||
// for this ClientInfo can possible exist (block_until_no_pending option
|
||||
// was used).
|
||||
delete client_info;
|
||||
}
|
||||
|
||||
if (server_alive_handle_) {
|
||||
// Release the mutex before closing the handle so that clients requesting
|
||||
// dumps wait for a long time for the server to generate a dump.
|
||||
ReleaseMutex(server_alive_handle_);
|
||||
CloseHandle(server_alive_handle_);
|
||||
}
|
||||
|
||||
if (overlapped_.hEvent) {
|
||||
CloseHandle(overlapped_.hEvent);
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&sync_);
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::Start() {
|
||||
if (server_state_ != IPC_SERVER_STATE_UNINITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
server_state_ = IPC_SERVER_STATE_INITIAL;
|
||||
|
||||
server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
|
||||
if (!server_alive_handle_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Event to signal the client connection and pipe reads and writes.
|
||||
overlapped_.hEvent = CreateEvent(NULL, // Security descriptor.
|
||||
TRUE, // Manual reset.
|
||||
FALSE, // Initially nonsignaled.
|
||||
NULL); // Name.
|
||||
if (!overlapped_.hEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register a callback with the thread pool for the client connection.
|
||||
if (!RegisterWaitForSingleObject(&pipe_wait_handle_,
|
||||
overlapped_.hEvent,
|
||||
OnPipeConnected,
|
||||
this,
|
||||
INFINITE,
|
||||
kPipeIOThreadFlags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pipe_ = CreateNamedPipe(pipe_name_.c_str(),
|
||||
kPipeAttr,
|
||||
kPipeMode,
|
||||
1,
|
||||
kOutBufferSize,
|
||||
kInBufferSize,
|
||||
0,
|
||||
pipe_sec_attrs_);
|
||||
if (pipe_ == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Kick-start the state machine. This will initiate an asynchronous wait
|
||||
// for client connections.
|
||||
if (!SetEvent(overlapped_.hEvent)) {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we are in error state, it's because we failed to start listening.
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the server thread serving clients ever gets into the
|
||||
// ERROR state, reset the event, close the pipe and remain
|
||||
// in the error state forever. Error state means something
|
||||
// that we didn't account for has happened, and it's dangerous
|
||||
// to do anything unknowingly.
|
||||
void CrashGenerationServer::HandleErrorState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_ERROR);
|
||||
|
||||
// If the server is shutting down anyway, don't clean up
|
||||
// here since shut down process will clean up.
|
||||
if (shutting_down_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe_wait_handle_) {
|
||||
UnregisterWait(pipe_wait_handle_);
|
||||
pipe_wait_handle_ = NULL;
|
||||
}
|
||||
|
||||
if (pipe_) {
|
||||
CloseHandle(pipe_);
|
||||
pipe_ = NULL;
|
||||
}
|
||||
|
||||
if (overlapped_.hEvent) {
|
||||
CloseHandle(overlapped_.hEvent);
|
||||
overlapped_.hEvent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving clients is in the INITIAL state,
|
||||
// try to connect to the pipe asynchronously. If the connection
|
||||
// finishes synchronously, directly go into the CONNECTED state;
|
||||
// otherwise go into the CONNECTING state. For any problems, go
|
||||
// into the ERROR state.
|
||||
void CrashGenerationServer::HandleInitialState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_INITIAL);
|
||||
|
||||
if (!ResetEvent(overlapped_.hEvent)) {
|
||||
EnterErrorState();
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
// From MSDN, it is not clear that when ConnectNamedPipe is used
|
||||
// in an overlapped mode, will it ever return non-zero value, and
|
||||
// if so, in what cases.
|
||||
assert(!success);
|
||||
|
||||
switch (error_code) {
|
||||
case ERROR_IO_PENDING:
|
||||
EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING);
|
||||
break;
|
||||
|
||||
case ERROR_PIPE_CONNECTED:
|
||||
EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
|
||||
break;
|
||||
|
||||
default:
|
||||
EnterErrorState();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the CONNECTING state,
|
||||
// try to get the result of the asynchronous connection request using
|
||||
// the OVERLAPPED object. If the result indicates the connection is done,
|
||||
// go into the CONNECTED state. If the result indicates I/O is still
|
||||
// INCOMPLETE, remain in the CONNECTING state. For any problems,
|
||||
// go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleConnectingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
if (success) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
|
||||
} else if (error_code != ERROR_IO_INCOMPLETE) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
} else {
|
||||
// remain in CONNECTING state
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the CONNECTED state,
|
||||
// try to issue an asynchronous read from the pipe. If read completes
|
||||
// synchronously or if I/O is pending then go into the READING state.
|
||||
// For any problems, go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleConnectedState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
memset(&msg_, 0, sizeof(msg_));
|
||||
bool success = ReadFile(pipe_,
|
||||
&msg_,
|
||||
sizeof(msg_),
|
||||
&bytes_count,
|
||||
&overlapped_) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
// Note that the asynchronous read issued above can finish before the
|
||||
// code below executes. But, it is okay to change state after issuing
|
||||
// the asynchronous read. This is because even if the asynchronous read
|
||||
// is done, the callback for it would not be executed until the current
|
||||
// thread finishes its execution.
|
||||
if (success || error_code == ERROR_IO_PENDING) {
|
||||
EnterStateWhenSignaled(IPC_SERVER_STATE_READING);
|
||||
} else {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the READING state,
|
||||
// try to get the result of the async read. If async read is done,
|
||||
// go into the READ_DONE state. For any problems, go into the
|
||||
// DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleReadingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_READING);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
if (success && bytes_count == sizeof(ProtocolMessage)) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_READ_DONE);
|
||||
} else {
|
||||
// We should never get an I/O incomplete since we should not execute this
|
||||
// unless the Read has finished and the overlapped event is signaled. If
|
||||
// we do get INCOMPLETE, we have a bug in our code.
|
||||
assert(error_code != ERROR_IO_INCOMPLETE);
|
||||
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the client is in the READ_DONE state,
|
||||
// validate the client's request message, register the client by
|
||||
// creating appropriate objects and prepare the response. Then try to
|
||||
// write the response to the pipe asynchronously. If that succeeds,
|
||||
// go into the WRITING state. For any problems, go into the DISCONNECTING
|
||||
// state.
|
||||
void CrashGenerationServer::HandleReadDoneState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
|
||||
|
||||
if (!IsClientRequestValid(msg_)) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_.tag == MESSAGE_TAG_UPLOAD_REQUEST) {
|
||||
if (upload_request_callback_)
|
||||
upload_request_callback_(upload_context_, msg_.id);
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_ptr<ClientInfo> client_info(
|
||||
new ClientInfo(this,
|
||||
msg_.id,
|
||||
msg_.dump_type,
|
||||
msg_.thread_id,
|
||||
msg_.exception_pointers,
|
||||
msg_.assert_info,
|
||||
msg_.custom_client_info));
|
||||
|
||||
if (!client_info->Initialize()) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
return;
|
||||
}
|
||||
|
||||
// Issues an asynchronous WriteFile call if successful.
|
||||
// Iff successful, assigns ownership of the client_info pointer to the server
|
||||
// instance, in which case we must be sure not to free it in this function.
|
||||
if (!RespondToClient(client_info.get())) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is only valid as long as it can be found in the clients_ list
|
||||
client_info_ = client_info.release();
|
||||
|
||||
// Note that the asynchronous write issued by RespondToClient function
|
||||
// can finish before the code below executes. But it is okay to change
|
||||
// state after issuing the asynchronous write. This is because even if
|
||||
// the asynchronous write is done, the callback for it would not be
|
||||
// executed until the current thread finishes its execution.
|
||||
EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING);
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the WRITING state,
|
||||
// try to get the result of the async write. If the async write is done,
|
||||
// go into the WRITE_DONE state. For any problems, go into the
|
||||
// DISONNECTING state.
|
||||
void CrashGenerationServer::HandleWritingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_WRITING);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
if (success) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE);
|
||||
return;
|
||||
}
|
||||
|
||||
// We should never get an I/O incomplete since we should not execute this
|
||||
// unless the Write has finished and the overlapped event is signaled. If
|
||||
// we do get INCOMPLETE, we have a bug in our code.
|
||||
assert(error_code != ERROR_IO_INCOMPLETE);
|
||||
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the WRITE_DONE state,
|
||||
// try to issue an async read on the pipe. If the read completes synchronously
|
||||
// or if I/O is still pending then go into the READING_ACK state. For any
|
||||
// issues, go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleWriteDoneState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = ReadFile(pipe_,
|
||||
&msg_,
|
||||
sizeof(msg_),
|
||||
&bytes_count,
|
||||
&overlapped_) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
if (success) {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_READING_ACK);
|
||||
} else if (error_code == ERROR_IO_PENDING) {
|
||||
EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK);
|
||||
} else {
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
}
|
||||
}
|
||||
|
||||
// When the server thread serving the clients is in the READING_ACK state,
|
||||
// try to get result of async read. Go into the DISCONNECTING state.
|
||||
void CrashGenerationServer::HandleReadingAckState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = GetOverlappedResult(pipe_,
|
||||
&overlapped_,
|
||||
&bytes_count,
|
||||
FALSE) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
if (success) {
|
||||
// The connection handshake with the client is now complete; perform
|
||||
// the callback.
|
||||
if (connect_callback_) {
|
||||
// Note that there is only a single copy of the ClientInfo of the
|
||||
// currently connected client. However it is being referenced from
|
||||
// two different places:
|
||||
// - the client_info_ member
|
||||
// - the clients_ list
|
||||
// The lifetime of this ClientInfo depends on the lifetime of the
|
||||
// client process - basically it can go away at any time.
|
||||
// However, as long as it is referenced by the clients_ list it
|
||||
// is guaranteed to be valid. Enter the critical section and check
|
||||
// to see whether the client_info_ can be found in the list.
|
||||
// If found, execute the callback and only then leave the critical
|
||||
// section.
|
||||
AutoCriticalSection lock(&sync_);
|
||||
|
||||
bool client_is_still_alive = false;
|
||||
std::list<ClientInfo*>::iterator iter;
|
||||
for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
|
||||
if (client_info_ == *iter) {
|
||||
client_is_still_alive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (client_is_still_alive) {
|
||||
connect_callback_(connect_context_, client_info_);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We should never get an I/O incomplete since we should not execute this
|
||||
// unless the Read has finished and the overlapped event is signaled. If
|
||||
// we do get INCOMPLETE, we have a bug in our code.
|
||||
assert(error_code != ERROR_IO_INCOMPLETE);
|
||||
}
|
||||
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
}
|
||||
|
||||
// When the server thread serving the client is in the DISCONNECTING state,
|
||||
// disconnect from the pipe and reset the event. If anything fails, go into
|
||||
// the ERROR state. If it goes well, go into the INITIAL state and set the
|
||||
// event to start all over again.
|
||||
void CrashGenerationServer::HandleDisconnectingState() {
|
||||
assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
|
||||
|
||||
// Done serving the client.
|
||||
client_info_ = NULL;
|
||||
|
||||
overlapped_.Internal = NULL;
|
||||
overlapped_.InternalHigh = NULL;
|
||||
overlapped_.Offset = 0;
|
||||
overlapped_.OffsetHigh = 0;
|
||||
overlapped_.Pointer = NULL;
|
||||
|
||||
if (!ResetEvent(overlapped_.hEvent)) {
|
||||
EnterErrorState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DisconnectNamedPipe(pipe_)) {
|
||||
EnterErrorState();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the server is shutting down do not connect to the
|
||||
// next client.
|
||||
if (shutting_down_) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnterStateImmediately(IPC_SERVER_STATE_INITIAL);
|
||||
}
|
||||
|
||||
void CrashGenerationServer::EnterErrorState() {
|
||||
SetEvent(overlapped_.hEvent);
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
}
|
||||
|
||||
void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) {
|
||||
server_state_ = state;
|
||||
}
|
||||
|
||||
void CrashGenerationServer::EnterStateImmediately(IPCServerState state) {
|
||||
server_state_ = state;
|
||||
|
||||
if (!SetEvent(overlapped_.hEvent)) {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const {
|
||||
reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
|
||||
reply->id = GetCurrentProcessId();
|
||||
|
||||
if (CreateClientHandles(client_info, reply)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Closing of remote handles (belonging to a different process) can
|
||||
// only be done through DuplicateHandle.
|
||||
if (reply->dump_request_handle) {
|
||||
DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle
|
||||
reply->dump_request_handle, // hSourceHandle
|
||||
NULL, // hTargetProcessHandle
|
||||
0, // lpTargetHandle
|
||||
0, // dwDesiredAccess
|
||||
FALSE, // bInheritHandle
|
||||
DUPLICATE_CLOSE_SOURCE); // dwOptions
|
||||
reply->dump_request_handle = NULL;
|
||||
}
|
||||
|
||||
if (reply->dump_generated_handle) {
|
||||
DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle
|
||||
reply->dump_generated_handle, // hSourceHandle
|
||||
NULL, // hTargetProcessHandle
|
||||
0, // lpTargetHandle
|
||||
0, // dwDesiredAccess
|
||||
FALSE, // bInheritHandle
|
||||
DUPLICATE_CLOSE_SOURCE); // dwOptions
|
||||
reply->dump_generated_handle = NULL;
|
||||
}
|
||||
|
||||
if (reply->server_alive_handle) {
|
||||
DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle
|
||||
reply->server_alive_handle, // hSourceHandle
|
||||
NULL, // hTargetProcessHandle
|
||||
0, // lpTargetHandle
|
||||
0, // dwDesiredAccess
|
||||
FALSE, // bInheritHandle
|
||||
DUPLICATE_CLOSE_SOURCE); // dwOptions
|
||||
reply->server_alive_handle = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const {
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
if (!DuplicateHandle(current_process,
|
||||
client_info.dump_requested_handle(),
|
||||
client_info.process_handle(),
|
||||
&reply->dump_request_handle,
|
||||
kDumpRequestEventAccess,
|
||||
FALSE,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DuplicateHandle(current_process,
|
||||
client_info.dump_generated_handle(),
|
||||
client_info.process_handle(),
|
||||
&reply->dump_generated_handle,
|
||||
kDumpGeneratedEventAccess,
|
||||
FALSE,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DuplicateHandle(current_process,
|
||||
server_alive_handle_,
|
||||
client_info.process_handle(),
|
||||
&reply->server_alive_handle,
|
||||
kMutexAccess,
|
||||
FALSE,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
|
||||
ProtocolMessage reply;
|
||||
if (!PrepareReply(*client_info, &reply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD bytes_count = 0;
|
||||
bool success = WriteFile(pipe_,
|
||||
&reply,
|
||||
sizeof(reply),
|
||||
&bytes_count,
|
||||
&overlapped_) != FALSE;
|
||||
DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
|
||||
|
||||
if (!success && error_code != ERROR_IO_PENDING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Takes over ownership of client_info. We MUST return true if AddClient
|
||||
// succeeds.
|
||||
return AddClient(client_info);
|
||||
}
|
||||
|
||||
// The server thread servicing the clients runs this method. The method
|
||||
// implements the state machine described in ReadMe.txt along with the
|
||||
// helper methods HandleXXXState.
|
||||
void CrashGenerationServer::HandleConnectionRequest() {
|
||||
// If the server is shutting down, get into ERROR state, reset the event so
|
||||
// more workers don't run and return immediately.
|
||||
if (shutting_down_) {
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
ResetEvent(overlapped_.hEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (server_state_) {
|
||||
case IPC_SERVER_STATE_ERROR:
|
||||
HandleErrorState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_INITIAL:
|
||||
HandleInitialState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_CONNECTING:
|
||||
HandleConnectingState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_CONNECTED:
|
||||
HandleConnectedState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_READING:
|
||||
HandleReadingState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_READ_DONE:
|
||||
HandleReadDoneState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_WRITING:
|
||||
HandleWritingState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_WRITE_DONE:
|
||||
HandleWriteDoneState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_READING_ACK:
|
||||
HandleReadingAckState();
|
||||
break;
|
||||
|
||||
case IPC_SERVER_STATE_DISCONNECTING:
|
||||
HandleDisconnectingState();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
// This indicates that we added one more state without
|
||||
// adding handling code.
|
||||
server_state_ = IPC_SERVER_STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
|
||||
HANDLE request_wait_handle = NULL;
|
||||
if (!RegisterWaitForSingleObject(&request_wait_handle,
|
||||
client_info->dump_requested_handle(),
|
||||
OnDumpRequest,
|
||||
client_info,
|
||||
INFINITE,
|
||||
kDumpRequestThreadFlags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
client_info->set_dump_request_wait_handle(request_wait_handle);
|
||||
|
||||
// OnClientEnd will be called when the client process terminates.
|
||||
HANDLE process_wait_handle = NULL;
|
||||
if (!RegisterWaitForSingleObject(&process_wait_handle,
|
||||
client_info->process_handle(),
|
||||
OnClientEnd,
|
||||
client_info,
|
||||
INFINITE,
|
||||
WT_EXECUTEONLYONCE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
client_info->set_process_exit_wait_handle(process_wait_handle);
|
||||
|
||||
// New scope to hold the lock for the shortest time.
|
||||
{
|
||||
AutoCriticalSection lock(&sync_);
|
||||
if (shutting_down_) {
|
||||
// If server is shutting down, don't add new clients
|
||||
return false;
|
||||
}
|
||||
clients_.push_back(client_info);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
|
||||
assert(context);
|
||||
|
||||
CrashGenerationServer* obj =
|
||||
reinterpret_cast<CrashGenerationServer*>(context);
|
||||
obj->HandleConnectionRequest();
|
||||
}
|
||||
|
||||
// static
|
||||
void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
|
||||
assert(context);
|
||||
ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
|
||||
|
||||
CrashGenerationServer* crash_server = client_info->crash_server();
|
||||
assert(crash_server);
|
||||
if (crash_server->pre_fetch_custom_info_) {
|
||||
client_info->PopulateCustomInfo();
|
||||
}
|
||||
crash_server->HandleDumpRequest(*client_info);
|
||||
|
||||
ResetEvent(client_info->dump_requested_handle());
|
||||
}
|
||||
|
||||
// static
|
||||
void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
|
||||
assert(context);
|
||||
ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
|
||||
|
||||
CrashGenerationServer* crash_server = client_info->crash_server();
|
||||
assert(crash_server);
|
||||
|
||||
crash_server->HandleClientProcessExit(client_info);
|
||||
}
|
||||
|
||||
void CrashGenerationServer::HandleClientProcessExit(ClientInfo* client_info) {
|
||||
assert(client_info);
|
||||
|
||||
// Must unregister the dump request wait operation and wait for any
|
||||
// dump requests that might be pending to finish before proceeding
|
||||
// with the client_info cleanup.
|
||||
client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending();
|
||||
|
||||
if (exit_callback_) {
|
||||
exit_callback_(exit_context_, client_info);
|
||||
}
|
||||
|
||||
// Start a new scope to release lock automatically.
|
||||
{
|
||||
AutoCriticalSection lock(&sync_);
|
||||
if (shutting_down_) {
|
||||
// The crash generation server is shutting down and as part of the
|
||||
// shutdown process it will delete all clients from the clients_ list.
|
||||
return;
|
||||
}
|
||||
clients_.remove(client_info);
|
||||
}
|
||||
|
||||
// Explicitly unregister the process exit wait using the non-blocking method.
|
||||
// Otherwise, the destructor will attempt to unregister it using the blocking
|
||||
// method which will lead to a deadlock because it is being called from the
|
||||
// callback of the same wait operation
|
||||
client_info->UnregisterProcessExitWait(false);
|
||||
|
||||
delete client_info;
|
||||
}
|
||||
|
||||
void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
|
||||
bool execute_callback = true;
|
||||
// Generate the dump only if it's explicitly requested by the
|
||||
// server application; otherwise the server might want to generate
|
||||
// dump in the callback.
|
||||
std::wstring dump_path;
|
||||
if (generate_dumps_) {
|
||||
if (!GenerateDump(client_info, &dump_path)) {
|
||||
// client proccess terminated or some other error
|
||||
execute_callback = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_callback_ && execute_callback) {
|
||||
std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path;
|
||||
dump_callback_(dump_context_, &client_info, ptr_dump_path);
|
||||
}
|
||||
|
||||
SetEvent(client_info.dump_generated_handle());
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
|
||||
std::wstring* dump_path) {
|
||||
assert(client.pid() != 0);
|
||||
assert(client.process_handle());
|
||||
|
||||
// We have to get the address of EXCEPTION_INFORMATION from
|
||||
// the client process address space.
|
||||
EXCEPTION_POINTERS* client_ex_info = NULL;
|
||||
if (!client.GetClientExceptionInfo(&client_ex_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD client_thread_id = 0;
|
||||
if (!client.GetClientThreadId(&client_thread_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dump_generator_->WriteMinidump(client.process_handle(),
|
||||
client.pid(),
|
||||
client_thread_id,
|
||||
GetCurrentThreadId(),
|
||||
client_ex_info,
|
||||
client.assert_info(),
|
||||
client.dump_type(),
|
||||
true,
|
||||
dump_path);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
@@ -0,0 +1,270 @@
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "IpcProtocol.h"
|
||||
#include "MinidumpGenerator.h"
|
||||
#include "ScopedPtr.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
class ClientInfo;
|
||||
|
||||
// Abstraction for server side implementation of out-of-process crash
|
||||
// generation protocol for Windows platform only. It generates Windows
|
||||
// minidump files for client processes that request dump generation. When
|
||||
// the server is requested to start listening for clients (by calling the
|
||||
// Start method), it creates a named pipe and waits for the clients to
|
||||
// register. In response, it hands them event handles that the client can
|
||||
// signal to request dump generation. When the clients request dump
|
||||
// generation in this way, the server generates Windows minidump files.
|
||||
class CrashGenerationServer {
|
||||
public:
|
||||
typedef void (*OnClientConnectedCallback)(void* context,
|
||||
const ClientInfo* client_info);
|
||||
|
||||
typedef void (*OnClientDumpRequestCallback)(void* context,
|
||||
const ClientInfo* client_info,
|
||||
const std::wstring* file_path);
|
||||
|
||||
typedef void (*OnClientExitedCallback)(void* context,
|
||||
const ClientInfo* client_info);
|
||||
|
||||
typedef void (*OnClientUploadRequestCallback)(void* context,
|
||||
const DWORD crash_id);
|
||||
|
||||
// Creates an instance with the given parameters.
|
||||
//
|
||||
// Parameter pipe_name: Name of the Windows named pipe
|
||||
// Parameter pipe_sec_attrs Security attributes to set on the pipe. Pass
|
||||
// NULL to use default security on the pipe. By default, the pipe created
|
||||
// allows Local System, Administrators and the Creator full control and
|
||||
// the Everyone group read access on the pipe.
|
||||
// Parameter connect_callback: Callback for a new client connection.
|
||||
// Parameter connect_context: Context for client connection callback.
|
||||
// Parameter crash_callback: Callback for a client crash dump request.
|
||||
// Parameter crash_context: Context for client crash dump request callback.
|
||||
// Parameter exit_callback: Callback for client process exit.
|
||||
// Parameter exit_context: Context for client exit callback.
|
||||
// Parameter generate_dumps: Whether to automatically generate dumps.
|
||||
// Client code of this class might want to generate dumps explicitly in the
|
||||
// crash dump request callback. In that case, false can be passed for this
|
||||
// parameter.
|
||||
// Parameter dump_path: Path for generating dumps; required only if true is
|
||||
// passed for generateDumps parameter; NULL can be passed otherwise.
|
||||
CrashGenerationServer(const std::wstring& pipe_name,
|
||||
SECURITY_ATTRIBUTES* pipe_sec_attrs,
|
||||
OnClientConnectedCallback connect_callback,
|
||||
void* connect_context,
|
||||
OnClientDumpRequestCallback dump_callback,
|
||||
void* dump_context,
|
||||
OnClientExitedCallback exit_callback,
|
||||
void* exit_context,
|
||||
OnClientUploadRequestCallback upload_request_callback,
|
||||
void* upload_context,
|
||||
bool generate_dumps,
|
||||
const std::wstring* dump_path);
|
||||
|
||||
~CrashGenerationServer();
|
||||
|
||||
// Performs initialization steps needed to start listening to clients. Upon
|
||||
// successful return clients may connect to this server's pipe.
|
||||
//
|
||||
// Returns true if initialization is successful; false otherwise.
|
||||
bool Start();
|
||||
|
||||
void pre_fetch_custom_info(bool do_pre_fetch) {
|
||||
pre_fetch_custom_info_ = do_pre_fetch;
|
||||
}
|
||||
|
||||
private:
|
||||
// Various states the client can be in during the handshake with
|
||||
// the server.
|
||||
enum IPCServerState {
|
||||
// Server starts in this state.
|
||||
IPC_SERVER_STATE_UNINITIALIZED,
|
||||
|
||||
// Server is in error state and it cannot serve any clients.
|
||||
IPC_SERVER_STATE_ERROR,
|
||||
|
||||
// Server starts in this state.
|
||||
IPC_SERVER_STATE_INITIAL,
|
||||
|
||||
// Server has issued an async connect to the pipe and it is waiting
|
||||
// for the connection to be established.
|
||||
IPC_SERVER_STATE_CONNECTING,
|
||||
|
||||
// Server is connected successfully.
|
||||
IPC_SERVER_STATE_CONNECTED,
|
||||
|
||||
// Server has issued an async read from the pipe and it is waiting for
|
||||
// the read to finish.
|
||||
IPC_SERVER_STATE_READING,
|
||||
|
||||
// Server is done reading from the pipe.
|
||||
IPC_SERVER_STATE_READ_DONE,
|
||||
|
||||
// Server has issued an async write to the pipe and it is waiting for
|
||||
// the write to finish.
|
||||
IPC_SERVER_STATE_WRITING,
|
||||
|
||||
// Server is done writing to the pipe.
|
||||
IPC_SERVER_STATE_WRITE_DONE,
|
||||
|
||||
// Server has issued an async read from the pipe for an ack and it
|
||||
// is waiting for the read to finish.
|
||||
IPC_SERVER_STATE_READING_ACK,
|
||||
|
||||
// Server is done writing to the pipe and it is now ready to disconnect
|
||||
// and reconnect.
|
||||
IPC_SERVER_STATE_DISCONNECTING
|
||||
};
|
||||
|
||||
//
|
||||
// Helper methods to handle various server IPC states.
|
||||
//
|
||||
void HandleErrorState();
|
||||
void HandleInitialState();
|
||||
void HandleConnectingState();
|
||||
void HandleConnectedState();
|
||||
void HandleReadingState();
|
||||
void HandleReadDoneState();
|
||||
void HandleWritingState();
|
||||
void HandleWriteDoneState();
|
||||
void HandleReadingAckState();
|
||||
void HandleDisconnectingState();
|
||||
|
||||
// Prepares reply for a client from the given parameters.
|
||||
bool PrepareReply(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const;
|
||||
|
||||
// Duplicates various handles in the ClientInfo object for the client
|
||||
// process and stores them in the given ProtocolMessage instance. If
|
||||
// creating any handle fails, ProtocolMessage will contain the handles
|
||||
// already created successfully, which should be closed by the caller.
|
||||
bool CreateClientHandles(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const;
|
||||
|
||||
// Response to the given client. Return true if all steps of
|
||||
// responding to the client succeed, false otherwise.
|
||||
bool RespondToClient(ClientInfo* client_info);
|
||||
|
||||
// Handles a connection request from the client.
|
||||
void HandleConnectionRequest();
|
||||
|
||||
// Handles a dump request from the client.
|
||||
void HandleDumpRequest(const ClientInfo& client_info);
|
||||
|
||||
// Callback for pipe connected event.
|
||||
static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
|
||||
|
||||
// Callback for a dump request.
|
||||
static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
|
||||
|
||||
// Callback for client process exit event.
|
||||
static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
|
||||
|
||||
// Handles client process exit.
|
||||
void HandleClientProcessExit(ClientInfo* client_info);
|
||||
|
||||
// Adds the given client to the list of registered clients.
|
||||
bool AddClient(ClientInfo* client_info);
|
||||
|
||||
// Generates dump for the given client.
|
||||
bool GenerateDump(const ClientInfo& client, std::wstring* dump_path);
|
||||
|
||||
// Puts the server in a permanent error state and sets a signal such that
|
||||
// the state will be immediately entered after the current state transition
|
||||
// is complete.
|
||||
void EnterErrorState();
|
||||
|
||||
// Puts the server in the specified state and sets a signal such that the
|
||||
// state is immediately entered after the current state transition is
|
||||
// complete.
|
||||
void EnterStateImmediately(IPCServerState state);
|
||||
|
||||
// Puts the server in the specified state. No signal will be set, so the state
|
||||
// transition will only occur when signaled manually or by completion of an
|
||||
// asynchronous IO operation.
|
||||
void EnterStateWhenSignaled(IPCServerState state);
|
||||
|
||||
// Sync object for thread-safe access to the shared list of clients.
|
||||
CRITICAL_SECTION sync_;
|
||||
|
||||
// List of clients.
|
||||
std::list<ClientInfo*> clients_;
|
||||
|
||||
// Pipe name.
|
||||
std::wstring pipe_name_;
|
||||
|
||||
// Pipe security attributes
|
||||
SECURITY_ATTRIBUTES* pipe_sec_attrs_;
|
||||
|
||||
// Handle to the pipe used for handshake with clients.
|
||||
HANDLE pipe_;
|
||||
|
||||
// Pipe wait handle.
|
||||
HANDLE pipe_wait_handle_;
|
||||
|
||||
// Handle to server-alive mutex.
|
||||
HANDLE server_alive_handle_;
|
||||
|
||||
// Callback for a successful client connection.
|
||||
OnClientConnectedCallback connect_callback_;
|
||||
|
||||
// Context for client connected callback.
|
||||
void* connect_context_;
|
||||
|
||||
// Callback for a client dump request.
|
||||
OnClientDumpRequestCallback dump_callback_;
|
||||
|
||||
// Context for client dump request callback.
|
||||
void* dump_context_;
|
||||
|
||||
// Callback for client process exit.
|
||||
OnClientExitedCallback exit_callback_;
|
||||
|
||||
// Context for client process exit callback.
|
||||
void* exit_context_;
|
||||
|
||||
// Callback for upload request.
|
||||
OnClientUploadRequestCallback upload_request_callback_;
|
||||
|
||||
// Context for upload request callback.
|
||||
void* upload_context_;
|
||||
|
||||
// Whether to generate dumps.
|
||||
bool generate_dumps_;
|
||||
|
||||
// Wether to populate custom information up-front.
|
||||
bool pre_fetch_custom_info_;
|
||||
|
||||
// Instance of a mini dump generator.
|
||||
scoped_ptr<MinidumpGenerator> dump_generator_;
|
||||
|
||||
// State of the server in performing the IPC with the client.
|
||||
// Note that since we restrict the pipe to one instance, we
|
||||
// only need to keep one state of the server. Otherwise, server
|
||||
// would have one state per client it is talking to.
|
||||
IPCServerState server_state_;
|
||||
|
||||
// Whether the server is shutting down.
|
||||
bool shutting_down_;
|
||||
|
||||
// Overlapped instance for async I/O on the pipe.
|
||||
OVERLAPPED overlapped_;
|
||||
|
||||
// Message object used in IPC with the client.
|
||||
ProtocolMessage msg_;
|
||||
|
||||
// Client Info for the client that's connecting to the server.
|
||||
ClientInfo* client_info_;
|
||||
|
||||
// Disable copy ctor and operator=.
|
||||
CrashGenerationServer(const CrashGenerationServer& crash_server);
|
||||
CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,466 @@
|
||||
// ExceptionHandler *e = new ExceptionHandler(...);
|
||||
// ExceptionHandler *f = new ExceptionHandler(...);
|
||||
// delete e;
|
||||
// This will put the exception filter stack into an inconsistent state.
|
||||
|
||||
#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
|
||||
#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <rpc.h>
|
||||
|
||||
#pragma warning(push)
|
||||
// Disable exception handler warnings.
|
||||
#pragma warning(disable:4530)
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "IpcProtocol.h"
|
||||
#include "CrashClient.h"
|
||||
#include "ScopedPtr.h"
|
||||
#include "MinidumpFormat.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
// These entries store a list of memory regions that the client wants included
|
||||
// in the minidump.
|
||||
struct AppMemory {
|
||||
ULONG64 ptr;
|
||||
ULONG length;
|
||||
|
||||
bool operator==(const struct AppMemory& other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
|
||||
bool operator==(const void* other) const {
|
||||
return ptr == reinterpret_cast<ULONG64>(other);
|
||||
}
|
||||
};
|
||||
typedef std::list<AppMemory> AppMemoryList;
|
||||
|
||||
class ExceptionHandler {
|
||||
public:
|
||||
// A callback function to run before Breakpad performs any substantial
|
||||
// processing of an exception. A FilterCallback is called before writing
|
||||
// a minidump. context is the parameter supplied by the user as
|
||||
// callback_context when the handler was created. exinfo points to the
|
||||
// exception record, if any; assertion points to assertion information,
|
||||
// if any.
|
||||
//
|
||||
// If a FilterCallback returns true, Breakpad will continue processing,
|
||||
// attempting to write a minidump. If a FilterCallback returns false,
|
||||
// Breakpad will immediately report the exception as unhandled without
|
||||
// writing a minidump, allowing another handler the opportunity to handle it.
|
||||
typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion);
|
||||
|
||||
// A callback function to run after the minidump has been written.
|
||||
// minidump_id is a unique id for the dump, so the minidump
|
||||
// file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied
|
||||
// by the user as callback_context when the handler was created. exinfo
|
||||
// points to the exception record, or NULL if no exception occurred.
|
||||
// succeeded indicates whether a minidump file was successfully written.
|
||||
// assertion points to information about an assertion if the handler was
|
||||
// invoked by an assertion.
|
||||
//
|
||||
// If an exception occurred and the callback returns true, Breakpad will treat
|
||||
// the exception as fully-handled, suppressing any other handlers from being
|
||||
// notified of the exception. If the callback returns false, Breakpad will
|
||||
// treat the exception as unhandled, and allow another handler to handle it.
|
||||
// If there are no other handlers, Breakpad will report the exception to the
|
||||
// system as unhandled, allowing a debugger or native crash dialog the
|
||||
// opportunity to handle the exception. Most callback implementations
|
||||
// should normally return the value of |succeeded|, or when they wish to
|
||||
// not report an exception of handled, false. Callbacks will rarely want to
|
||||
// return true directly (unless |succeeded| is true).
|
||||
//
|
||||
// For out-of-process dump generation, dump path and minidump ID will always
|
||||
// be NULL. In case of out-of-process dump generation, the dump path and
|
||||
// minidump id are controlled by the server process and are not communicated
|
||||
// back to the crashing process.
|
||||
typedef bool (*MinidumpCallback)(const TCHAR* dump_path,
|
||||
const TCHAR* minidump_id,
|
||||
void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion,
|
||||
bool succeeded);
|
||||
|
||||
// HandlerType specifies which types of handlers should be installed, if
|
||||
// any. Use HANDLER_NONE for an ExceptionHandler that remains idle,
|
||||
// without catching any failures on its own. This type of handler may
|
||||
// still be triggered by calling WriteMinidump. Otherwise, use a
|
||||
// combination of the other HANDLER_ values, or HANDLER_ALL to install
|
||||
// all handlers.
|
||||
enum HandlerType {
|
||||
HANDLER_NONE = 0,
|
||||
HANDLER_EXCEPTION = 1 << 0, // SetUnhandledExceptionFilter
|
||||
HANDLER_INVALID_PARAMETER = 1 << 1, // _set_invalid_parameter_handler
|
||||
HANDLER_PURECALL = 1 << 2, // _set_purecall_handler
|
||||
HANDLER_ALL = HANDLER_EXCEPTION |
|
||||
HANDLER_INVALID_PARAMETER |
|
||||
HANDLER_PURECALL
|
||||
};
|
||||
|
||||
// Creates a new ExceptionHandler instance to handle writing minidumps.
|
||||
// Before writing a minidump, the optional filter callback will be called.
|
||||
// Its return value determines whether or not Breakpad should write a
|
||||
// minidump. Minidump files will be written to dump_path, and the optional
|
||||
// callback is called after writing the dump file, as described above.
|
||||
// handler_types specifies the types of handlers that should be installed.
|
||||
ExceptionHandler(const string& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types);
|
||||
|
||||
ExceptionHandler(const string& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type);
|
||||
|
||||
// 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
|
||||
// the dump type to generate.
|
||||
ExceptionHandler(const string& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const TCHAR* 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 string& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
HANDLE pipe_handle,
|
||||
const CustomClientInfo* custom_info);
|
||||
|
||||
// ExceptionHandler that ENSURES out-of-process dump generation. Expects a
|
||||
// crash generation client that is already registered with a crash generation
|
||||
// server. Takes ownership of the passed-in crash_generation_client.
|
||||
//
|
||||
// Usage example:
|
||||
// crash_generation_client = new CrashGenerationClient(..);
|
||||
// if (crash_generation_client->Register()) {
|
||||
// // Registration with the crash generation server succeeded.
|
||||
// // Out-of-process dump generation is guaranteed.
|
||||
// g_handler = new ExceptionHandler(.., crash_generation_client, ..);
|
||||
// return true;
|
||||
// }
|
||||
ExceptionHandler(const string& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types,
|
||||
CrashGenerationClient* crash_generation_client);
|
||||
|
||||
~ExceptionHandler();
|
||||
|
||||
// Get and set the minidump path.
|
||||
string dump_path() const { return dump_path_; }
|
||||
void set_dump_path(const string &dump_path) {
|
||||
dump_path_ = dump_path;
|
||||
dump_path_c_ = dump_path_.c_str();
|
||||
UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_.
|
||||
}
|
||||
|
||||
// Requests that a previously reported crash be uploaded.
|
||||
bool RequestUpload(DWORD crash_id);
|
||||
|
||||
// Writes a minidump immediately. This can be used to capture the
|
||||
// execution state independently of a crash. Returns true on success.
|
||||
bool WriteMinidump();
|
||||
|
||||
// Writes a minidump immediately, with the user-supplied exception
|
||||
// information.
|
||||
bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo);
|
||||
|
||||
// Convenience form of WriteMinidump which does not require an
|
||||
// ExceptionHandler instance.
|
||||
static bool WriteMinidump(const string &dump_path,
|
||||
MinidumpCallback callback, void* callback_context);
|
||||
|
||||
// Write a minidump of |child| immediately. This can be used to
|
||||
// capture the execution state of |child| independently of a crash.
|
||||
// Pass a meaningful |child_blamed_thread| to make that thread in
|
||||
// the child process the one from which a crash signature is
|
||||
// extracted.
|
||||
static bool WriteMinidumpForChild(HANDLE child,
|
||||
DWORD child_blamed_thread,
|
||||
const string& dump_path,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
// Get the thread ID of the thread requesting the dump (either the exception
|
||||
// thread or any other thread that called WriteMinidump directly). This
|
||||
// may be useful if you want to include additional thread state in your
|
||||
// dumps.
|
||||
DWORD get_requesting_thread_id() const { return requesting_thread_id_; }
|
||||
|
||||
// Controls behavior of EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP.
|
||||
bool get_handle_debug_exceptions() const { return handle_debug_exceptions_; }
|
||||
void set_handle_debug_exceptions(bool handle_debug_exceptions) {
|
||||
handle_debug_exceptions_ = handle_debug_exceptions;
|
||||
}
|
||||
|
||||
// Returns whether out-of-process dump generation is used or not.
|
||||
bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }
|
||||
|
||||
// Calling RegisterAppMemory(p, len) causes len bytes starting
|
||||
// at address p to be copied to the minidump when a crash happens.
|
||||
void RegisterAppMemory(void* ptr, size_t length);
|
||||
void UnregisterAppMemory(void* ptr);
|
||||
|
||||
private:
|
||||
friend class AutoExceptionHandler;
|
||||
|
||||
// Initializes the instance with given values.
|
||||
void Initialize(const string& dump_path,
|
||||
FilterCallback filter,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context,
|
||||
int handler_types,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
const TCHAR* pipe_name,
|
||||
HANDLE pipe_handle,
|
||||
CrashGenerationClient* crash_generation_client,
|
||||
const CustomClientInfo* custom_info);
|
||||
|
||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||
// dynamically.
|
||||
typedef BOOL (WINAPI *MiniDumpWriteDump_type)(
|
||||
HANDLE hProcess,
|
||||
DWORD dwPid,
|
||||
HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
|
||||
// Function pointer type for UuidCreate, which is looked up dynamically.
|
||||
typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid);
|
||||
|
||||
// Runs the main loop for the exception handler thread.
|
||||
static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter);
|
||||
|
||||
// Called on the exception thread when an unhandled exception occurs.
|
||||
// Signals the exception handler thread to handle the exception.
|
||||
static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo);
|
||||
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
// This function will be called by some CRT functions when they detect
|
||||
// that they were passed an invalid parameter. Note that in _DEBUG builds,
|
||||
// the CRT may display an assertion dialog before calling this function,
|
||||
// and the function will not be called unless the assertion dialog is
|
||||
// dismissed by clicking "Ignore."
|
||||
static void HandleInvalidParameter(const wchar_t* expression,
|
||||
const wchar_t* function,
|
||||
const wchar_t* file,
|
||||
unsigned int line,
|
||||
uintptr_t reserved);
|
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
// This function will be called by the CRT when a pure virtual
|
||||
// function is called.
|
||||
static void HandlePureVirtualCall();
|
||||
|
||||
// This is called on the exception thread or on another thread that
|
||||
// the user wishes to produce a dump from. It calls
|
||||
// WriteMinidumpWithException on the handler thread, avoiding stack
|
||||
// overflows and inconsistent dumps due to writing the dump from
|
||||
// the exception thread. If the dump is requested as a result of an
|
||||
// exception, exinfo contains exception information, otherwise, it
|
||||
// is NULL. If the dump is requested as a result of an assertion
|
||||
// (such as an invalid parameter being passed to a CRT function),
|
||||
// assertion contains data about the assertion, otherwise, it is NULL.
|
||||
bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion);
|
||||
|
||||
// This function is called on the handler thread. It calls into
|
||||
// WriteMinidumpWithExceptionForProcess() with a handle to the
|
||||
// current process. requesting_thread_id is the ID of the thread
|
||||
// that requested the dump. If the dump is requested as a result of
|
||||
// an exception, exinfo contains exception information, otherwise,
|
||||
// it is NULL.
|
||||
bool WriteMinidumpWithException(DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion);
|
||||
|
||||
// This function is used as a callback when calling MinidumpWriteDump,
|
||||
// in order to add additional memory regions to the dump.
|
||||
static BOOL CALLBACK MinidumpWriteDumpCallback(
|
||||
PVOID context,
|
||||
const PMINIDUMP_CALLBACK_INPUT callback_input,
|
||||
PMINIDUMP_CALLBACK_OUTPUT callback_output);
|
||||
|
||||
// This function does the actual writing of a minidump. It is
|
||||
// called on the handler thread. requesting_thread_id is the ID of
|
||||
// the thread that requested the dump, if that information is
|
||||
// meaningful. If the dump is requested as a result of an
|
||||
// exception, exinfo contains exception information, otherwise, it
|
||||
// is NULL. process is the one that will be dumped. If
|
||||
// requesting_thread_id is meaningful and should be added to the
|
||||
// minidump, write_requester_stream is |true|.
|
||||
bool WriteMinidumpWithExceptionForProcess(DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion,
|
||||
HANDLE process,
|
||||
bool write_requester_stream);
|
||||
|
||||
// Generates a new ID and stores it in next_minidump_id_, and stores the
|
||||
// path of the next minidump to be written in next_minidump_path_.
|
||||
void UpdateNextID();
|
||||
|
||||
FilterCallback filter_;
|
||||
MinidumpCallback callback_;
|
||||
void* callback_context_;
|
||||
|
||||
scoped_ptr<CrashGenerationClient> crash_generation_client_;
|
||||
|
||||
// The directory in which a minidump will be written, set by the dump_path
|
||||
// argument to the constructor, or set_dump_path.
|
||||
string dump_path_;
|
||||
|
||||
// The basename of the next minidump to be written, without the extension.
|
||||
string next_minidump_id_;
|
||||
|
||||
// The full pathname of the next minidump to be written, including the file
|
||||
// extension.
|
||||
string next_minidump_path_;
|
||||
|
||||
// Pointers to C-string representations of the above. These are set when
|
||||
// the above string versions are set in order to avoid calling c_str during
|
||||
// an exception, as c_str may attempt to allocate heap memory. These
|
||||
// pointers are not owned by the ExceptionHandler object, but their lifetimes
|
||||
// should be equivalent to the lifetimes of the associated string, provided
|
||||
// that the wstrings are not altered.
|
||||
const TCHAR* dump_path_c_;
|
||||
const TCHAR* next_minidump_id_c_;
|
||||
const TCHAR* next_minidump_path_c_;
|
||||
|
||||
HMODULE dbghelp_module_;
|
||||
MiniDumpWriteDump_type minidump_write_dump_;
|
||||
MINIDUMP_TYPE dump_type_;
|
||||
|
||||
HMODULE rpcrt4_module_;
|
||||
UuidCreate_type uuid_create_;
|
||||
|
||||
// Tracks the handler types that were installed according to the
|
||||
// handler_types constructor argument.
|
||||
int handler_types_;
|
||||
|
||||
// When installed_handler_ is true, previous_filter_ is the unhandled
|
||||
// exception filter that was set prior to installing ExceptionHandler as
|
||||
// the unhandled exception filter and pointing it to |this|. NULL indicates
|
||||
// that there is no previous unhandled exception filter.
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_;
|
||||
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
// Beginning in VC 8, the CRT provides an invalid parameter handler that will
|
||||
// be called when some CRT functions are passed invalid parameters. In
|
||||
// earlier CRTs, the same conditions would cause unexpected behavior or
|
||||
// crashes.
|
||||
_invalid_parameter_handler previous_iph_;
|
||||
#endif // _MSC_VER >= 1400
|
||||
|
||||
// The CRT allows you to override the default handler for pure
|
||||
// virtual function calls.
|
||||
_purecall_handler previous_pch_;
|
||||
|
||||
// The exception handler thread.
|
||||
HANDLE handler_thread_;
|
||||
|
||||
// True if the exception handler is being destroyed.
|
||||
// Starting with MSVC 2005, Visual C has stronger guarantees on volatile vars.
|
||||
// It has release semantics on write and acquire semantics on reads.
|
||||
// See the msdn documentation.
|
||||
volatile bool is_shutdown_;
|
||||
|
||||
// The critical section enforcing the requirement that only one exception be
|
||||
// handled by a handler at a time.
|
||||
CRITICAL_SECTION handler_critical_section_;
|
||||
|
||||
// Semaphores used to move exception handling between the exception thread
|
||||
// and the handler thread. handler_start_semaphore_ is signalled by the
|
||||
// exception thread to wake up the handler thread when an exception occurs.
|
||||
// handler_finish_semaphore_ is signalled by the handler thread to wake up
|
||||
// the exception thread when handling is complete.
|
||||
HANDLE handler_start_semaphore_;
|
||||
HANDLE handler_finish_semaphore_;
|
||||
|
||||
// The next 2 fields contain data passed from the requesting thread to
|
||||
// the handler thread.
|
||||
|
||||
// The thread ID of the thread requesting the dump (either the exception
|
||||
// thread or any other thread that called WriteMinidump directly).
|
||||
DWORD requesting_thread_id_;
|
||||
|
||||
// The exception info passed to the exception handler on the exception
|
||||
// thread, if an exception occurred. NULL for user-requested dumps.
|
||||
EXCEPTION_POINTERS* exception_info_;
|
||||
|
||||
// If the handler is invoked due to an assertion, this will contain a
|
||||
// pointer to the assertion information. It is NULL at other times.
|
||||
MDRawAssertionInfo* assertion_;
|
||||
|
||||
// The return value of the handler, passed from the handler thread back to
|
||||
// the requesting thread.
|
||||
bool handler_return_value_;
|
||||
|
||||
// If true, the handler will intercept EXCEPTION_BREAKPOINT and
|
||||
// EXCEPTION_SINGLE_STEP exceptions. Leave this false (the default)
|
||||
// to not interfere with debuggers.
|
||||
bool handle_debug_exceptions_;
|
||||
|
||||
// Callers can request additional memory regions to be included in
|
||||
// the dump.
|
||||
AppMemoryList app_memory_info_;
|
||||
|
||||
// A stack of ExceptionHandler objects that have installed unhandled
|
||||
// exception filters. This vector is used by HandleException to determine
|
||||
// which ExceptionHandler object to route an exception to. When an
|
||||
// ExceptionHandler is created with install_handler true, it will append
|
||||
// itself to this list.
|
||||
static vector<ExceptionHandler*>* handler_stack_;
|
||||
|
||||
// The index of the ExceptionHandler in handler_stack_ that will handle the
|
||||
// next exception. Note that 0 means the last entry in handler_stack_, 1
|
||||
// means the next-to-last entry, and so on. This is used by HandleException
|
||||
// to support multiple stacked Breakpad handlers.
|
||||
static LONG handler_stack_index_;
|
||||
|
||||
// handler_stack_critical_section_ guards operations on handler_stack_ and
|
||||
// handler_stack_index_. The critical section is initialized by the
|
||||
// first instance of the class and destroyed by the last instance of it.
|
||||
static CRITICAL_SECTION handler_stack_critical_section_;
|
||||
|
||||
// The number of instances of this class.
|
||||
static volatile LONG instance_count_;
|
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit ExceptionHandler(const ExceptionHandler &);
|
||||
void operator=(const ExceptionHandler &);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <tchar.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "ExceptionHandler.h"
|
||||
#include "GoogleDump.h"
|
||||
|
||||
google_breakpad::ExceptionHandler *g_handler;
|
||||
TCHAR GoogleDump::m_foldername[MAXPATH];
|
||||
TCHAR GoogleDump::m_filename[MAXPATH];
|
||||
|
||||
GoogleDump::GoogleDump()
|
||||
{
|
||||
g_handler = NULL;
|
||||
}
|
||||
|
||||
GoogleDump::~GoogleDump()
|
||||
{
|
||||
End();
|
||||
}
|
||||
|
||||
void GoogleDump::Begin(const TCHAR* fileName)
|
||||
{
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
|
||||
TCHAR temp[256];
|
||||
GetCurrentDirectory(_countof(temp), temp);
|
||||
_sntprintf_s(m_foldername,_countof(m_foldername), _T("%s\\dump\\"), temp);
|
||||
_tcscpy_s(m_filename,_countof(m_filename), fileName);
|
||||
CreateDirectory(m_foldername, NULL);
|
||||
|
||||
g_handler = new google_breakpad::ExceptionHandler(
|
||||
std::string(m_foldername,m_foldername+_tcslen(m_foldername)),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
MiniDumpNormal);
|
||||
}
|
||||
|
||||
void GoogleDump::End()
|
||||
{
|
||||
if(g_handler != NULL)
|
||||
{
|
||||
delete g_handler;
|
||||
g_handler = NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#define MAXPATH 512
|
||||
|
||||
class GoogleDump
|
||||
{
|
||||
public:
|
||||
static TCHAR m_foldername[MAXPATH];
|
||||
static TCHAR m_filename[MAXPATH];
|
||||
|
||||
GoogleDump();
|
||||
~GoogleDump();
|
||||
|
||||
static void Begin(const TCHAR* foldername);
|
||||
static void End();
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
// guid_string.cc: Convert GUIDs to strings.
|
||||
//
|
||||
// See guid_string.h for documentation.
|
||||
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "StringUtils-inl.h"
|
||||
|
||||
#include "GuidString.h"
|
||||
#include "ExceptionHandler.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// static
|
||||
string GUIDString::GUIDToWString(GUID *guid) {
|
||||
CHAR guid_string[37];
|
||||
sprintf_s(
|
||||
guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
guid->Data1, guid->Data2, guid->Data3,
|
||||
guid->Data4[0], guid->Data4[1], guid->Data4[2],
|
||||
guid->Data4[3], guid->Data4[4], guid->Data4[5],
|
||||
guid->Data4[6], guid->Data4[7]);
|
||||
|
||||
|
||||
// remove when VC++7.1 is no longer supported
|
||||
guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
|
||||
|
||||
return string(guid_string);
|
||||
}
|
||||
|
||||
// static
|
||||
string GUIDString::GUIDToSymbolServerWString(GUID *guid) {
|
||||
CHAR guid_string[33];
|
||||
sprintf_s(
|
||||
guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
|
||||
"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
guid->Data1, guid->Data2, guid->Data3,
|
||||
guid->Data4[0], guid->Data4[1], guid->Data4[2],
|
||||
guid->Data4[3], guid->Data4[4], guid->Data4[5],
|
||||
guid->Data4[6], guid->Data4[7]);
|
||||
|
||||
// remove when VC++7.1 is no longer supported
|
||||
guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
|
||||
|
||||
return string(guid_string);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2006, 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.
|
||||
|
||||
// guid_string.cc: Convert GUIDs to strings.
|
||||
|
||||
#ifndef COMMON_WINDOWS_GUID_STRING_H__
|
||||
#define COMMON_WINDOWS_GUID_STRING_H__
|
||||
|
||||
#include <Guiddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
|
||||
class GUIDString {
|
||||
public:
|
||||
// Converts guid to a string in the format recommended by RFC 4122 and
|
||||
// returns the string.
|
||||
static string GUIDToWString(GUID *guid);
|
||||
|
||||
// Converts guid to a string formatted as uppercase hexadecimal, with
|
||||
// no separators, and returns the string. This is the format used for
|
||||
// symbol server identifiers, although identifiers have an age tacked
|
||||
// on to the string.
|
||||
static string GUIDToSymbolServerWString(GUID *guid);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_WINDOWS_GUID_STRING_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 "stringUtils-inl.h"
|
||||
#include "MinidumpFormat.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 TCHAR* name_arg, const TCHAR* value_arg) {
|
||||
set_name(name_arg);
|
||||
set_value(value_arg);
|
||||
}
|
||||
|
||||
void set_name(const TCHAR* name_arg) {
|
||||
if (!name_arg) {
|
||||
name[0] = L'\0';
|
||||
return;
|
||||
}
|
||||
WindowsStringUtils::safe_wcscpy(name, kNameMaxLength, name_arg);
|
||||
}
|
||||
|
||||
void set_value(const TCHAR* value_arg) {
|
||||
if (!value_arg) {
|
||||
value[0] = L'\0';
|
||||
return;
|
||||
}
|
||||
|
||||
WindowsStringUtils::safe_wcscpy(value, kValueMaxLength, value_arg);
|
||||
}
|
||||
|
||||
void set(const TCHAR* name_arg, const TCHAR* value_arg) {
|
||||
set_name(name_arg);
|
||||
set_value(value_arg);
|
||||
}
|
||||
|
||||
TCHAR name[kNameMaxLength];
|
||||
TCHAR 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__
|
||||
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{AD9DACFB-6A8A-42B5-8FDC-DA5E31C7F107}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>LS_GoogleDump</RootNamespace>
|
||||
<ProjectName>Ls_GoogleDump</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>$(ProjectName)D</TargetName>
|
||||
<EmbedManifest>false</EmbedManifest>
|
||||
<OutDir>..\..\lib\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>..\..\lib\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="autoCriticalSection.h" />
|
||||
<ClInclude Include="BreakpadTypes.h" />
|
||||
<ClInclude Include="GoogleDump.h" />
|
||||
<ClInclude Include="CpuAmd64.h" />
|
||||
<ClInclude Include="CpuArm.h" />
|
||||
<ClInclude Include="CpuMips.h" />
|
||||
<ClInclude Include="CpuPpc.h" />
|
||||
<ClInclude Include="CpuPpc64.h" />
|
||||
<ClInclude Include="CpuSparc.h" />
|
||||
<ClInclude Include="CpuX86.h" />
|
||||
<ClInclude Include="CrashClient.h" />
|
||||
<ClInclude Include="ExceptionHandler.h" />
|
||||
<ClInclude Include="GuidString.h" />
|
||||
<ClInclude Include="IpcProtocol.h" />
|
||||
<ClInclude Include="MinidumpExceptionLinux.h" />
|
||||
<ClInclude Include="MinidumpExceptionMac.h" />
|
||||
<ClInclude Include="MinidumpExceptionPs3.h" />
|
||||
<ClInclude Include="MinidumpExceptionSolaris.h" />
|
||||
<ClInclude Include="MinidumpExceptionWin32.h" />
|
||||
<ClInclude Include="MinidumpFormat.h" />
|
||||
<ClInclude Include="MinidumpGenerator.h" />
|
||||
<ClInclude Include="ScopedPtr.h" />
|
||||
<ClInclude Include="StringUtils-inl.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="GoogleDump.cpp" />
|
||||
<ClCompile Include="CrashClient.cpp" />
|
||||
<ClCompile Include="ExceptionHandler.cpp" />
|
||||
<ClCompile Include="GuidString.cpp" />
|
||||
<ClCompile Include="MinidumpGenerator.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="GuidString.cpp">
|
||||
<Filter>Common\GuidString</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CrashClient.cpp">
|
||||
<Filter>CrashClient</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ExceptionHandler.cpp">
|
||||
<Filter>Exception_Handler</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MinidumpGenerator.cpp">
|
||||
<Filter>minidumpGenerator</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GoogleDump.cpp">
|
||||
<Filter>GoogleDump</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="GuidString.h">
|
||||
<Filter>Common\GuidString</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinidumpExceptionLinux.h">
|
||||
<Filter>Common\MiniDumpException</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinidumpExceptionWin32.h">
|
||||
<Filter>Common\MiniDumpException</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinidumpExceptionMac.h">
|
||||
<Filter>Common\MiniDumpException</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinidumpExceptionPs3.h">
|
||||
<Filter>Common\MiniDumpException</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinidumpExceptionSolaris.h">
|
||||
<Filter>Common\MiniDumpException</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuAmd64.h">
|
||||
<Filter>Common\MiniDumpFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuX86.h">
|
||||
<Filter>Common\MiniDumpFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuArm.h">
|
||||
<Filter>Common\MiniDumpFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuMips.h">
|
||||
<Filter>Common\MiniDumpFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuPpc.h">
|
||||
<Filter>Common\MiniDumpFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuPpc64.h">
|
||||
<Filter>Common\MiniDumpFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuSparc.h">
|
||||
<Filter>Common\MiniDumpFormat</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="autoCriticalSection.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BreakpadTypes.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IpcProtocol.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinidumpFormat.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ScopedPtr.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StringUtils-inl.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CrashClient.h">
|
||||
<Filter>CrashClient</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ExceptionHandler.h">
|
||||
<Filter>Exception_Handler</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MinidumpGenerator.h">
|
||||
<Filter>minidumpGenerator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GoogleDump.h">
|
||||
<Filter>GoogleDump</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Common">
|
||||
<UniqueIdentifier>{397a2ed1-4fc1-4771-b3ef-f96fce76b372}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Common\GuidString">
|
||||
<UniqueIdentifier>{bb96b08d-0019-4ddd-9b05-cb7a3ccf7ced}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Common\MiniDumpException">
|
||||
<UniqueIdentifier>{899b2ab4-db13-44b0-b741-e9073720f247}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Common\MiniDumpFormat">
|
||||
<UniqueIdentifier>{de72d54f-ddab-4a64-a2f1-f29b50569fa4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="CrashClient">
|
||||
<UniqueIdentifier>{b8c83043-fe10-4aff-aacb-a4f3b8e67836}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Exception_Handler">
|
||||
<UniqueIdentifier>{db546706-7017-41be-a593-27b2be39151f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="minidumpGenerator">
|
||||
<UniqueIdentifier>{9e00bdc7-392c-42bd-8698-2bf800007968}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GoogleDump">
|
||||
<UniqueIdentifier>{113d1a5f-c43c-495b-b619-75be2c54447c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,87 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_linux.h: A definition of exception codes for
|
||||
* Linux
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "BreakpadTypes.h"
|
||||
|
||||
|
||||
/* For (MDException).exception_code. These values come from bits/signum.h.
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGURG = 23,
|
||||
/* Urgent condition on socket (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25,
|
||||
/* File size limit exceeded (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */
|
||||
MD_EXCEPTION_CODE_LIN_SIGSYS = 31, /* Bad system call */
|
||||
MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception,
|
||||
dump requested. */
|
||||
} MDExceptionCodeLinux;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */
|
||||
@@ -0,0 +1,205 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_mac.h: A definition of exception codes for Mac
|
||||
* OS X
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "BreakpadTypes.h"
|
||||
|
||||
/* For (MDException).exception_code. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/exception_types.h. This is
|
||||
* what Mac OS X calls an "exception", not a "code". */
|
||||
typedef enum {
|
||||
/* Exception code. The high 16 bits of exception_code contains one of
|
||||
* these values. */
|
||||
MD_EXCEPTION_MAC_BAD_ACCESS = 1, /* code can be a kern_return_t */
|
||||
/* EXC_BAD_ACCESS */
|
||||
MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2, /* code is CPU-specific */
|
||||
/* EXC_BAD_INSTRUCTION */
|
||||
MD_EXCEPTION_MAC_ARITHMETIC = 3, /* code is CPU-specific */
|
||||
/* EXC_ARITHMETIC */
|
||||
MD_EXCEPTION_MAC_EMULATION = 4, /* code is CPU-specific */
|
||||
/* EXC_EMULATION */
|
||||
MD_EXCEPTION_MAC_SOFTWARE = 5,
|
||||
/* EXC_SOFTWARE */
|
||||
MD_EXCEPTION_MAC_BREAKPOINT = 6, /* code is CPU-specific */
|
||||
/* EXC_BREAKPOINT */
|
||||
MD_EXCEPTION_MAC_SYSCALL = 7,
|
||||
/* EXC_SYSCALL */
|
||||
MD_EXCEPTION_MAC_MACH_SYSCALL = 8,
|
||||
/* EXC_MACH_SYSCALL */
|
||||
MD_EXCEPTION_MAC_RPC_ALERT = 9
|
||||
/* EXC_RPC_ALERT */
|
||||
} MDExceptionMac;
|
||||
|
||||
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X
|
||||
* support. Based on Darwin/Mac OS X' mach/ppc/exception.h and
|
||||
* mach/i386/exception.h. This is what Mac OS X calls a "code". */
|
||||
typedef enum {
|
||||
/* With MD_EXCEPTION_BAD_ACCESS. These are relevant kern_return_t values
|
||||
* from mach/kern_return.h. */
|
||||
MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS = 1,
|
||||
/* KERN_INVALID_ADDRESS */
|
||||
MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE = 2,
|
||||
/* KERN_PROTECTION_FAILURE */
|
||||
MD_EXCEPTION_CODE_MAC_NO_ACCESS = 8,
|
||||
/* KERN_NO_ACCESS */
|
||||
MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE = 9,
|
||||
/* KERN_MEMORY_FAILURE */
|
||||
MD_EXCEPTION_CODE_MAC_MEMORY_ERROR = 10,
|
||||
/* KERN_MEMORY_ERROR */
|
||||
|
||||
/* With MD_EXCEPTION_SOFTWARE */
|
||||
MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000, /* Mach SIGSYS */
|
||||
MD_EXCEPTION_CODE_MAC_BAD_PIPE = 0x00010001, /* Mach SIGPIPE */
|
||||
MD_EXCEPTION_CODE_MAC_ABORT = 0x00010002, /* Mach SIGABRT */
|
||||
/* Custom values */
|
||||
MD_EXCEPTION_CODE_MAC_NS_EXCEPTION = 0xDEADC0DE, /* uncaught NSException */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_ACCESS on arm */
|
||||
MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN = 0x0101, /* EXC_ARM_DA_ALIGN */
|
||||
MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG = 0x0102, /* EXC_ARM_DA_DEBUG */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on arm */
|
||||
MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED = 1, /* EXC_ARM_UNDEFINED */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on arm */
|
||||
MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT = 1, /* EXC_ARM_BREAKPOINT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,
|
||||
/* EXC_PPC_VM_PROT_READ */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_BADSPACE = 0x0102,
|
||||
/* EXC_PPC_BADSPACE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED = 0x0103,
|
||||
/* EXC_PPC_UNALIGNED */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL = 1,
|
||||
/* EXC_PPC_INVALID_SYSCALL */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2,
|
||||
/* EXC_PPC_UNIPL_INST */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION = 3,
|
||||
/* EXC_PPC_PRIVINST */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER = 4,
|
||||
/* EXC_PPC_PRIVREG */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_TRACE = 5,
|
||||
/* EXC_PPC_TRACE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR = 6,
|
||||
/* EXC_PPC_PERFMON */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW = 1,
|
||||
/* EXC_PPC_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE = 2,
|
||||
/* EXC_PPC_ZERO_DIVIDE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT = 3,
|
||||
/* EXC_FLT_INEXACT */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE = 4,
|
||||
/* EXC_PPC_FLT_ZERO_DIVIDE */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW = 5,
|
||||
/* EXC_PPC_FLT_UNDERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW = 6,
|
||||
/* EXC_PPC_FLT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7,
|
||||
/* EXC_PPC_FLT_NOT_A_NUMBER */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_EMULATION on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION = 8,
|
||||
/* EXC_PPC_NOEMULATION */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9,
|
||||
/* EXC_PPC_ALTIVECASSIST */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_SOFTWARE on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_TRAP = 0x00000001, /* EXC_PPC_TRAP */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100, /* EXC_PPC_MIGRATE */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */
|
||||
MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1, /* EXC_PPC_BREAKPOINT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt
|
||||
* values below. */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1, /* EXC_I386_INVOP */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */
|
||||
MD_EXCEPTION_CODE_MAC_X86_DIV = 1, /* EXC_I386_DIV */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INTO = 2, /* EXC_I386_INTO */
|
||||
MD_EXCEPTION_CODE_MAC_X86_NOEXT = 3, /* EXC_I386_NOEXT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EXTOVR = 4, /* EXC_I386_EXTOVR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EXTERR = 5, /* EXC_I386_EXTERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_EMERR = 6, /* EXC_I386_EMERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_BOUND = 7, /* EXC_I386_BOUND */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8, /* EXC_I386_SSEEXTERR */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SGL = 1, /* EXC_I386_SGL */
|
||||
MD_EXCEPTION_CODE_MAC_X86_BPT = 2, /* EXC_I386_BPT */
|
||||
|
||||
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86. These are the raw
|
||||
* x86 interrupt codes. Most of these are mapped to other Mach
|
||||
* exceptions and codes, are handled, or should not occur in user space.
|
||||
* A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */
|
||||
/* EXC_I386_DIVERR = 0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */
|
||||
/* EXC_I386_SGLSTP = 1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */
|
||||
/* EXC_I386_NMIFLT = 2: should not occur in user space */
|
||||
/* EXC_I386_BPTFLT = 3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */
|
||||
/* EXC_I386_INTOFLT = 4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */
|
||||
/* EXC_I386_BOUNDFLT = 5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */
|
||||
/* EXC_I386_INVOPFLT = 6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */
|
||||
/* EXC_I386_NOEXTFLT = 7: should be handled by the kernel */
|
||||
/* EXC_I386_DBLFLT = 8: should be handled (if possible) by the kernel */
|
||||
/* EXC_I386_EXTOVRFLT = 9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */
|
||||
MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10,
|
||||
/* EXC_INVTSSFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT = 11,
|
||||
/* EXC_SEGNPFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT = 12,
|
||||
/* EXC_STKFLT */
|
||||
MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT = 13,
|
||||
/* EXC_GPFLT */
|
||||
/* EXC_I386_PGFLT = 14: should not occur in user space */
|
||||
/* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */
|
||||
MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17
|
||||
/* EXC_ALIGNFLT (for vector operations) */
|
||||
/* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */
|
||||
/* EXC_I386_ENDPERR = 33: should not occur */
|
||||
} MDExceptionCodeMac;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Copyright (c) 2013, 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. */
|
||||
|
||||
/* minidump_exception_ps3.h: A definition of exception codes for
|
||||
* PS3 */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "BreakpadTypes.h"
|
||||
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_PS3_UNKNOWN = 0,
|
||||
MD_EXCEPTION_CODE_PS3_TRAP_EXCEP = 1,
|
||||
MD_EXCEPTION_CODE_PS3_PRIV_INSTR = 2,
|
||||
MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR = 3,
|
||||
MD_EXCEPTION_CODE_PS3_INSTR_STORAGE = 4,
|
||||
MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT = 5,
|
||||
MD_EXCEPTION_CODE_PS3_DATA_STORAGE = 6,
|
||||
MD_EXCEPTION_CODE_PS3_DATA_SEGMENT = 7,
|
||||
MD_EXCEPTION_CODE_PS3_FLOAT_POINT = 8,
|
||||
MD_EXCEPTION_CODE_PS3_DABR_MATCH = 9,
|
||||
MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP = 10,
|
||||
MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS = 11,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_ALIGN = 12,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM = 13,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_ERR = 14,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_FIR = 15,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT = 16,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE = 17,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR = 18,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR = 19,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN = 20,
|
||||
MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS = 21,
|
||||
MD_EXCEPTION_CODE_PS3_GRAPHIC = 22
|
||||
} MDExceptionCodePS3;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ */
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_solaris.h: A definition of exception codes for
|
||||
* Solaris
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "BreakpadTypes.h"
|
||||
|
||||
/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h
|
||||
*/
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */
|
||||
MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */
|
||||
MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */
|
||||
MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */
|
||||
MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */
|
||||
MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occurred */
|
||||
MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */
|
||||
MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */
|
||||
MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */
|
||||
MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */
|
||||
MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */
|
||||
MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */
|
||||
MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */
|
||||
MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */
|
||||
} MDExceptionCodeSolaris;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */
|
||||
@@ -0,0 +1,116 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_exception_win32.h: Definitions of exception codes for
|
||||
* Win32 platform
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Split into its own file: Neal Sidhwaney */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "BreakpadTypes.h"
|
||||
|
||||
|
||||
/* For (MDException).exception_code. These values come from WinBase.h
|
||||
* and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h,
|
||||
* they are STATUS_ in WinNT.h). */
|
||||
typedef enum {
|
||||
MD_EXCEPTION_CODE_WIN_CONTROL_C = 0x40010005,
|
||||
/* DBG_CONTROL_C */
|
||||
MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION = 0x80000001,
|
||||
/* EXCEPTION_GUARD_PAGE */
|
||||
MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT = 0x80000002,
|
||||
/* EXCEPTION_DATATYPE_MISALIGNMENT */
|
||||
MD_EXCEPTION_CODE_WIN_BREAKPOINT = 0x80000003,
|
||||
/* EXCEPTION_BREAKPOINT */
|
||||
MD_EXCEPTION_CODE_WIN_SINGLE_STEP = 0x80000004,
|
||||
/* EXCEPTION_SINGLE_STEP */
|
||||
MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION = 0xc0000005,
|
||||
/* EXCEPTION_ACCESS_VIOLATION */
|
||||
MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR = 0xc0000006,
|
||||
/* EXCEPTION_IN_PAGE_ERROR */
|
||||
MD_EXCEPTION_CODE_WIN_INVALID_HANDLE = 0xc0000008,
|
||||
/* EXCEPTION_INVALID_HANDLE */
|
||||
MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION = 0xc000001d,
|
||||
/* EXCEPTION_ILLEGAL_INSTRUCTION */
|
||||
MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025,
|
||||
/* EXCEPTION_NONCONTINUABLE_EXCEPTION */
|
||||
MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION = 0xc0000026,
|
||||
/* EXCEPTION_INVALID_DISPOSITION */
|
||||
MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED = 0xc000008c,
|
||||
/* EXCEPTION_BOUNDS_EXCEEDED */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND = 0xc000008d,
|
||||
/* EXCEPTION_FLT_DENORMAL_OPERAND */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO = 0xc000008e,
|
||||
/* EXCEPTION_FLT_DIVIDE_BY_ZERO */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT = 0xc000008f,
|
||||
/* EXCEPTION_FLT_INEXACT_RESULT */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION = 0xc0000090,
|
||||
/* EXCEPTION_FLT_INVALID_OPERATION */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW = 0xc0000091,
|
||||
/* EXCEPTION_FLT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK = 0xc0000092,
|
||||
/* EXCEPTION_FLT_STACK_CHECK */
|
||||
MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW = 0xc0000093,
|
||||
/* EXCEPTION_FLT_UNDERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO = 0xc0000094,
|
||||
/* EXCEPTION_INT_DIVIDE_BY_ZERO */
|
||||
MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW = 0xc0000095,
|
||||
/* EXCEPTION_INT_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096,
|
||||
/* EXCEPTION_PRIV_INSTRUCTION */
|
||||
MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd,
|
||||
/* EXCEPTION_STACK_OVERFLOW */
|
||||
MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194,
|
||||
/* EXCEPTION_POSSIBLE_DEADLOCK */
|
||||
MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN = 0xc0000409,
|
||||
/* STATUS_STACK_BUFFER_OVERRUN */
|
||||
MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374,
|
||||
/* STATUS_HEAP_CORRUPTION */
|
||||
MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363
|
||||
/* Per http://support.microsoft.com/kb/185294,
|
||||
generated by Visual C++ compiler */
|
||||
} MDExceptionCodeWin;
|
||||
|
||||
// These constants are defined in the MSDN documentation of
|
||||
// the EXCEPTION_RECORD structure.
|
||||
typedef enum {
|
||||
MD_ACCESS_VIOLATION_WIN_READ = 0,
|
||||
MD_ACCESS_VIOLATION_WIN_WRITE = 1,
|
||||
MD_ACCESS_VIOLATION_WIN_EXEC = 8
|
||||
} MDAccessViolationTypeWin;
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */
|
||||
@@ -0,0 +1,949 @@
|
||||
/* Copyright (c) 2006, 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. */
|
||||
|
||||
/* minidump_format.h: A cross-platform reimplementation of minidump-related
|
||||
* portions of DbgHelp.h from the Windows Platform SDK.
|
||||
*
|
||||
* (This is C99 source, please don't corrupt it with C++.)
|
||||
*
|
||||
* Structures that are defined by Microsoft to contain a zero-length array
|
||||
* are instead defined here to contain an array with one element, as
|
||||
* zero-length arrays are forbidden by standard C and C++. In these cases,
|
||||
* *_minsize constants are provided to be used in place of sizeof. For a
|
||||
* cleaner interface to these sizes when using C++, see minidump_size.h.
|
||||
*
|
||||
* These structures are also sufficient to populate minidump files.
|
||||
*
|
||||
* These definitions may be extended to support handling minidump files
|
||||
* for other CPUs and other operating systems.
|
||||
*
|
||||
* Because precise data type sizes are crucial for this implementation to
|
||||
* function properly and portably in terms of interoperability with minidumps
|
||||
* produced by DbgHelp on Windows, a set of primitive types with known sizes
|
||||
* are used as the basis of each structure defined by this file. DbgHelp
|
||||
* on Windows is assumed to be the reference implementation; this file
|
||||
* seeks to provide a cross-platform compatible implementation. To avoid
|
||||
* collisions with the types and values defined and used by DbgHelp in the
|
||||
* event that this implementation is used on Windows, each type and value
|
||||
* defined here is given a new name, beginning with "MD". Names of the
|
||||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai */
|
||||
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
|
||||
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "BreakpadTypes.h"
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* Disable "zero-sized array in struct/union" warnings when compiling in
|
||||
* MSVC. DbgHelp.h does this too. */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
/*
|
||||
* guiddef.h
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t data1;
|
||||
uint16_t data2;
|
||||
uint16_t data3;
|
||||
uint8_t data4[8];
|
||||
} MDGUID; /* GUID */
|
||||
|
||||
|
||||
/*
|
||||
* WinNT.h
|
||||
*/
|
||||
|
||||
/* Non-x86 CPU identifiers found in the high 24 bits of
|
||||
* (MDRawContext*).context_flags. These aren't used by Breakpad, but are
|
||||
* defined here for reference, to avoid assigning values that conflict
|
||||
* (although some values already conflict). */
|
||||
#define MD_CONTEXT_IA64 0x00080000 /* CONTEXT_IA64 */
|
||||
/* Additional values from winnt.h in the Windows CE 5.0 SDK: */
|
||||
#define MD_CONTEXT_SHX 0x000000c0 /* CONTEXT_SH4 (Super-H, includes SH3) */
|
||||
#define MD_CONTEXT_ALPHA 0x00020000 /* CONTEXT_ALPHA */
|
||||
|
||||
/* As of Windows 7 SP1, the number of flag bits has increased to
|
||||
* include 0x40 (CONTEXT_XSTATE):
|
||||
* http://msdn.microsoft.com/en-us/library/hh134238%28v=vs.85%29.aspx */
|
||||
#define MD_CONTEXT_CPU_MASK 0xffffff00
|
||||
|
||||
|
||||
/* This is a base type for MDRawContextX86 and MDRawContextPPC. This
|
||||
* structure should never be allocated directly. The actual structure type
|
||||
* can be determined by examining the context_flags field. */
|
||||
typedef struct {
|
||||
uint32_t context_flags;
|
||||
} MDRawContextBase;
|
||||
|
||||
#include "CpuAmd64.h"
|
||||
#include "CpuArm.h"
|
||||
#include "CpuMips.h"
|
||||
#include "CpuPpc.h"
|
||||
#include "CpuPpc64.h"
|
||||
#include "CpuSparc.h"
|
||||
#include "CpuX86.h"
|
||||
|
||||
/*
|
||||
* WinVer.h
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t signature;
|
||||
uint32_t struct_version;
|
||||
uint32_t file_version_hi;
|
||||
uint32_t file_version_lo;
|
||||
uint32_t product_version_hi;
|
||||
uint32_t product_version_lo;
|
||||
uint32_t file_flags_mask; /* Identifies valid bits in fileFlags */
|
||||
uint32_t file_flags;
|
||||
uint32_t file_os;
|
||||
uint32_t file_type;
|
||||
uint32_t file_subtype;
|
||||
uint32_t file_date_hi;
|
||||
uint32_t file_date_lo;
|
||||
} MDVSFixedFileInfo; /* VS_FIXEDFILEINFO */
|
||||
|
||||
/* For (MDVSFixedFileInfo).signature */
|
||||
#define MD_VSFIXEDFILEINFO_SIGNATURE 0xfeef04bd
|
||||
/* VS_FFI_SIGNATURE */
|
||||
|
||||
/* For (MDVSFixedFileInfo).version */
|
||||
#define MD_VSFIXEDFILEINFO_VERSION 0x00010000
|
||||
/* VS_FFI_STRUCVERSION */
|
||||
|
||||
/* For (MDVSFixedFileInfo).file_flags_mask and
|
||||
* (MDVSFixedFileInfo).file_flags */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG 0x00000001
|
||||
/* VS_FF_DEBUG */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRERELEASE 0x00000002
|
||||
/* VS_FF_PRERELEASE */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PATCHED 0x00000004
|
||||
/* VS_FF_PATCHED */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRIVATEBUILD 0x00000008
|
||||
/* VS_FF_PRIVATEBUILD */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_INFOINFERRED 0x00000010
|
||||
/* VS_FF_INFOINFERRED */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_FLAGS_SPECIALBUILD 0x00000020
|
||||
/* VS_FF_SPECIALBUILD */
|
||||
|
||||
/* For (MDVSFixedFileInfo).file_os: high 16 bits */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_UNKNOWN 0 /* VOS_UNKNOWN */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_DOS (1 << 16) /* VOS_DOS */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_OS216 (2 << 16) /* VOS_OS216 */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_OS232 (3 << 16) /* VOS_OS232 */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_NT (4 << 16) /* VOS_NT */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS_WINCE (5 << 16) /* VOS_WINCE */
|
||||
/* Low 16 bits */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__BASE 0 /* VOS__BASE */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS16 1 /* VOS__WINDOWS16 */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__PM16 2 /* VOS__PM16 */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__PM32 3 /* VOS__PM32 */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32 4 /* VOS__WINDOWS32 */
|
||||
|
||||
/* For (MDVSFixedFileInfo).file_type */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_UNKNOWN 0 /* VFT_UNKNOWN */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_APP 1 /* VFT_APP */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_DLL 2 /* VFT_DLL */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_DRV 3 /* VFT_DLL */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_FONT 4 /* VFT_FONT */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_VXD 5 /* VFT_VXD */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_TYPE_STATIC_LIB 7 /* VFT_STATIC_LIB */
|
||||
|
||||
/* For (MDVSFixedFileInfo).file_subtype */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN 0
|
||||
/* VFT2_UNKNOWN */
|
||||
/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_DRV */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_PRINTER 1
|
||||
/* VFT2_DRV_PRINTER */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_KEYBOARD 2
|
||||
/* VFT2_DRV_KEYBOARD */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_LANGUAGE 3
|
||||
/* VFT2_DRV_LANGUAGE */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_DISPLAY 4
|
||||
/* VFT2_DRV_DISPLAY */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_MOUSE 5
|
||||
/* VFT2_DRV_MOUSE */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_NETWORK 6
|
||||
/* VFT2_DRV_NETWORK */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SYSTEM 7
|
||||
/* VFT2_DRV_SYSTEM */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INSTALLABLE 8
|
||||
/* VFT2_DRV_INSTALLABLE */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SOUND 9
|
||||
/* VFT2_DRV_SOUND */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_COMM 10
|
||||
/* VFT2_DRV_COMM */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INPUTMETHOD 11
|
||||
/* VFT2_DRV_INPUTMETHOD */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_VERSIONED_PRINTER 12
|
||||
/* VFT2_DRV_VERSIONED_PRINTER */
|
||||
/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_FONT */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_RASTER 1
|
||||
/* VFT2_FONT_RASTER */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_VECTOR 2
|
||||
/* VFT2_FONT_VECTOR */
|
||||
#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_TRUETYPE 3
|
||||
/* VFT2_FONT_TRUETYPE */
|
||||
|
||||
|
||||
/*
|
||||
* DbgHelp.h
|
||||
*/
|
||||
|
||||
|
||||
/* An MDRVA is an offset into the minidump file. The beginning of the
|
||||
* MDRawHeader is at offset 0. */
|
||||
typedef uint32_t MDRVA; /* RVA */
|
||||
|
||||
typedef struct {
|
||||
uint32_t data_size;
|
||||
MDRVA rva;
|
||||
} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* The base address of the memory range on the host that produced the
|
||||
* minidump. */
|
||||
uint64_t start_of_memory_range;
|
||||
|
||||
MDLocationDescriptor memory;
|
||||
} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t signature;
|
||||
uint32_t version;
|
||||
uint32_t stream_count;
|
||||
MDRVA stream_directory_rva; /* A |stream_count|-sized array of
|
||||
* MDRawDirectory structures. */
|
||||
uint32_t checksum; /* Can be 0. In fact, that's all that's
|
||||
* been found in minidump files. */
|
||||
uint32_t time_date_stamp; /* time_t */
|
||||
uint64_t flags;
|
||||
} MDRawHeader; /* MINIDUMP_HEADER */
|
||||
|
||||
/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the
|
||||
* low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION. Per the
|
||||
* documentation, the high 16 bits are implementation-specific. */
|
||||
#define MD_HEADER_SIGNATURE 0x504d444d /* 'PMDM' */
|
||||
/* MINIDUMP_SIGNATURE */
|
||||
#define MD_HEADER_VERSION 0x0000a793 /* 42899 */
|
||||
/* MINIDUMP_VERSION */
|
||||
|
||||
/* For (MDRawHeader).flags: */
|
||||
typedef enum {
|
||||
/* MD_NORMAL is the standard type of minidump. It includes full
|
||||
* streams for the thread list, module list, exception, system info,
|
||||
* and miscellaneous info. A memory list stream is also present,
|
||||
* pointing to the same stack memory contained in the thread list,
|
||||
* as well as a 256-byte region around the instruction address that
|
||||
* was executing when the exception occurred. Stack memory is from
|
||||
* 4 bytes below a thread's stack pointer up to the top of the
|
||||
* memory region encompassing the stack. */
|
||||
MD_NORMAL = 0x00000000,
|
||||
MD_WITH_DATA_SEGS = 0x00000001,
|
||||
MD_WITH_FULL_MEMORY = 0x00000002,
|
||||
MD_WITH_HANDLE_DATA = 0x00000004,
|
||||
MD_FILTER_MEMORY = 0x00000008,
|
||||
MD_SCAN_MEMORY = 0x00000010,
|
||||
MD_WITH_UNLOADED_MODULES = 0x00000020,
|
||||
MD_WITH_INDIRECTLY_REFERENCED_MEMORY = 0x00000040,
|
||||
MD_FILTER_MODULE_PATHS = 0x00000080,
|
||||
MD_WITH_PROCESS_THREAD_DATA = 0x00000100,
|
||||
MD_WITH_PRIVATE_READ_WRITE_MEMORY = 0x00000200,
|
||||
MD_WITHOUT_OPTIONAL_DATA = 0x00000400,
|
||||
MD_WITH_FULL_MEMORY_INFO = 0x00000800,
|
||||
MD_WITH_THREAD_INFO = 0x00001000,
|
||||
MD_WITH_CODE_SEGS = 0x00002000,
|
||||
MD_WITHOUT_AUXILLIARY_SEGS = 0x00004000,
|
||||
MD_WITH_FULL_AUXILLIARY_STATE = 0x00008000,
|
||||
MD_WITH_PRIVATE_WRITE_COPY_MEMORY = 0x00010000,
|
||||
MD_IGNORE_INACCESSIBLE_MEMORY = 0x00020000,
|
||||
MD_WITH_TOKEN_INFORMATION = 0x00040000
|
||||
} MDType; /* MINIDUMP_TYPE */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t stream_type;
|
||||
MDLocationDescriptor location;
|
||||
} MDRawDirectory; /* MINIDUMP_DIRECTORY */
|
||||
|
||||
/* For (MDRawDirectory).stream_type */
|
||||
typedef enum {
|
||||
MD_UNUSED_STREAM = 0,
|
||||
MD_RESERVED_STREAM_0 = 1,
|
||||
MD_RESERVED_STREAM_1 = 2,
|
||||
MD_THREAD_LIST_STREAM = 3, /* MDRawThreadList */
|
||||
MD_MODULE_LIST_STREAM = 4, /* MDRawModuleList */
|
||||
MD_MEMORY_LIST_STREAM = 5, /* MDRawMemoryList */
|
||||
MD_EXCEPTION_STREAM = 6, /* MDRawExceptionStream */
|
||||
MD_SYSTEM_INFO_STREAM = 7, /* MDRawSystemInfo */
|
||||
MD_THREAD_EX_LIST_STREAM = 8,
|
||||
MD_MEMORY_64_LIST_STREAM = 9,
|
||||
MD_COMMENT_STREAM_A = 10,
|
||||
MD_COMMENT_STREAM_W = 11,
|
||||
MD_HANDLE_DATA_STREAM = 12,
|
||||
MD_FUNCTION_TABLE_STREAM = 13,
|
||||
MD_UNLOADED_MODULE_LIST_STREAM = 14,
|
||||
MD_MISC_INFO_STREAM = 15, /* MDRawMiscInfo */
|
||||
MD_MEMORY_INFO_LIST_STREAM = 16, /* MDRawMemoryInfoList */
|
||||
MD_THREAD_INFO_LIST_STREAM = 17,
|
||||
MD_HANDLE_OPERATION_LIST_STREAM = 18,
|
||||
MD_LAST_RESERVED_STREAM = 0x0000ffff,
|
||||
|
||||
/* Breakpad extension types. 0x4767 = "Gg" */
|
||||
MD_BREAKPAD_INFO_STREAM = 0x47670001, /* MDRawBreakpadInfo */
|
||||
MD_ASSERTION_INFO_STREAM = 0x47670002, /* MDRawAssertionInfo */
|
||||
/* These are additional minidump stream values which are specific to
|
||||
* the linux breakpad implementation. */
|
||||
MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */
|
||||
MD_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status */
|
||||
MD_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release */
|
||||
MD_LINUX_CMD_LINE = 0x47670006, /* /proc/$x/cmdline */
|
||||
MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */
|
||||
MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */
|
||||
MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */
|
||||
MD_LINUX_DSO_DEBUG = 0x4767000A /* MDRawDebug */
|
||||
} MDStreamType; /* MINIDUMP_STREAM_TYPE */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t length; /* Length of buffer in bytes (not characters),
|
||||
* excluding 0-terminator */
|
||||
uint16_t buffer[1]; /* UTF-16-encoded, 0-terminated */
|
||||
} MDString; /* MINIDUMP_STRING */
|
||||
|
||||
static const size_t MDString_minsize = offsetof(MDString, buffer[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t thread_id;
|
||||
uint32_t suspend_count;
|
||||
uint32_t priority_class;
|
||||
uint32_t priority;
|
||||
uint64_t teb; /* Thread environment block */
|
||||
MDMemoryDescriptor stack;
|
||||
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
|
||||
} MDRawThread; /* MINIDUMP_THREAD */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t number_of_threads;
|
||||
MDRawThread threads[1];
|
||||
} MDRawThreadList; /* MINIDUMP_THREAD_LIST */
|
||||
|
||||
static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList,
|
||||
threads[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint64_t base_of_image;
|
||||
uint32_t size_of_image;
|
||||
uint32_t checksum; /* 0 if unknown */
|
||||
uint32_t time_date_stamp; /* time_t */
|
||||
MDRVA module_name_rva; /* MDString, pathname or filename */
|
||||
MDVSFixedFileInfo version_info;
|
||||
|
||||
/* The next field stores a CodeView record and is populated when a module's
|
||||
* debug information resides in a PDB file. It identifies the PDB file. */
|
||||
MDLocationDescriptor cv_record;
|
||||
|
||||
/* The next field is populated when a module's debug information resides
|
||||
* in a DBG file. It identifies the DBG file. This field is effectively
|
||||
* obsolete with modules built by recent toolchains. */
|
||||
MDLocationDescriptor misc_record;
|
||||
|
||||
/* Alignment problem: reserved0 and reserved1 are defined by the platform
|
||||
* SDK as 64-bit quantities. However, that results in a structure whose
|
||||
* alignment is unpredictable on different CPUs and ABIs. If the ABI
|
||||
* specifies full alignment of 64-bit quantities in structures (as ppc
|
||||
* does), there will be padding between miscRecord and reserved0. If
|
||||
* 64-bit quantities can be aligned on 32-bit boundaries (as on x86),
|
||||
* this padding will not exist. (Note that the structure up to this point
|
||||
* contains 1 64-bit member followed by 21 32-bit members.)
|
||||
* As a workaround, reserved0 and reserved1 are instead defined here as
|
||||
* four 32-bit quantities. This should be harmless, as there are
|
||||
* currently no known uses for these fields. */
|
||||
uint32_t reserved0[2];
|
||||
uint32_t reserved1[2];
|
||||
} MDRawModule; /* MINIDUMP_MODULE */
|
||||
|
||||
/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to
|
||||
* be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC).
|
||||
* This doesn't occur on systems that don't tail-pad in this manner. Define
|
||||
* this macro to be the usable size of the MDRawModule struct, and use it in
|
||||
* place of sizeof(MDRawModule). */
|
||||
#define MD_MODULE_SIZE 108
|
||||
|
||||
|
||||
/* (MDRawModule).cv_record can reference MDCVInfoPDB20 or MDCVInfoPDB70.
|
||||
* Ref.: http://www.debuginfo.com/articles/debuginfomatch.html
|
||||
* MDCVInfoPDB70 is the expected structure type with recent toolchains. */
|
||||
|
||||
typedef struct {
|
||||
uint32_t signature;
|
||||
uint32_t offset; /* Offset to debug data (expect 0 in minidump) */
|
||||
} MDCVHeader;
|
||||
|
||||
typedef struct {
|
||||
MDCVHeader cv_header;
|
||||
uint32_t signature; /* time_t debug information created */
|
||||
uint32_t age; /* revision of PDB file */
|
||||
uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file */
|
||||
} MDCVInfoPDB20;
|
||||
|
||||
static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,
|
||||
pdb_file_name[0]);
|
||||
|
||||
#define MD_CVINFOPDB20_SIGNATURE 0x3031424e /* cvHeader.signature = '01BN' */
|
||||
|
||||
typedef struct {
|
||||
uint32_t cv_signature;
|
||||
MDGUID signature; /* GUID, identifies PDB file */
|
||||
uint32_t age; /* Identifies incremental changes to PDB file */
|
||||
uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file,
|
||||
* 0-terminated 8-bit character data (UTF-8?) */
|
||||
} MDCVInfoPDB70;
|
||||
|
||||
static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70,
|
||||
pdb_file_name[0]);
|
||||
|
||||
#define MD_CVINFOPDB70_SIGNATURE 0x53445352 /* cvSignature = 'SDSR' */
|
||||
|
||||
typedef struct {
|
||||
uint32_t data1[2];
|
||||
uint32_t data2;
|
||||
uint32_t data3;
|
||||
uint32_t data4;
|
||||
uint32_t data5[3];
|
||||
uint8_t extra[2];
|
||||
} MDCVInfoELF;
|
||||
|
||||
/* In addition to the two CodeView record formats above, used for linking
|
||||
* to external pdb files, it is possible for debugging data to be carried
|
||||
* directly in the CodeView record itself. These signature values will
|
||||
* be found in the first 4 bytes of the CodeView record. Additional values
|
||||
* not commonly experienced in the wild are given by "Microsoft Symbol and
|
||||
* Type Information", http://www.x86.org/ftp/manuals/tools/sym.pdf, section
|
||||
* 7.2. An in-depth description of the CodeView 4.1 format is given by
|
||||
* "Undocumented Windows 2000 Secrets", Windows 2000 Debugging Support/
|
||||
* Microsoft Symbol File Internals/CodeView Subsections,
|
||||
* http://www.rawol.com/features/undocumented/sbs-w2k-1-windows-2000-debugging-support.pdf
|
||||
*/
|
||||
#define MD_CVINFOCV41_SIGNATURE 0x3930424e /* '90BN', CodeView 4.10. */
|
||||
#define MD_CVINFOCV50_SIGNATURE 0x3131424e /* '11BN', CodeView 5.0,
|
||||
* MS C7-format (/Z7). */
|
||||
|
||||
#define MD_CVINFOUNKNOWN_SIGNATURE 0xffffffff /* An unlikely value. */
|
||||
|
||||
/* (MDRawModule).miscRecord can reference MDImageDebugMisc. The Windows
|
||||
* structure is actually defined in WinNT.h. This structure is effectively
|
||||
* obsolete with modules built by recent toolchains. */
|
||||
|
||||
typedef struct {
|
||||
uint32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because
|
||||
* this debug record type is mostly obsolete. */
|
||||
uint32_t length; /* Length of entire MDImageDebugMisc structure */
|
||||
uint8_t unicode; /* True if data is multibyte */
|
||||
uint8_t reserved[3];
|
||||
uint8_t data[1];
|
||||
} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */
|
||||
|
||||
static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,
|
||||
data[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t number_of_modules;
|
||||
MDRawModule modules[1];
|
||||
} MDRawModuleList; /* MINIDUMP_MODULE_LIST */
|
||||
|
||||
static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList,
|
||||
modules[0]);
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t number_of_memory_ranges;
|
||||
MDMemoryDescriptor memory_ranges[1];
|
||||
} MDRawMemoryList; /* MINIDUMP_MEMORY_LIST */
|
||||
|
||||
static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList,
|
||||
memory_ranges[0]);
|
||||
|
||||
|
||||
#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15
|
||||
|
||||
typedef struct {
|
||||
uint32_t exception_code; /* Windows: MDExceptionCodeWin,
|
||||
* Mac OS X: MDExceptionMac,
|
||||
* Linux: MDExceptionCodeLinux. */
|
||||
uint32_t exception_flags; /* Windows: 1 if noncontinuable,
|
||||
Mac OS X: MDExceptionCodeMac. */
|
||||
uint64_t exception_record; /* Address (in the minidump-producing host's
|
||||
* memory) of another MDException, for
|
||||
* nested exceptions. */
|
||||
uint64_t exception_address; /* The address that caused the exception.
|
||||
* Mac OS X: exception subcode (which is
|
||||
* typically the address). */
|
||||
uint32_t number_parameters; /* Number of valid elements in
|
||||
* exception_information. */
|
||||
uint32_t __align;
|
||||
uint64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
|
||||
} MDException; /* MINIDUMP_EXCEPTION */
|
||||
|
||||
#include "MinidumpExceptionLinux.h"
|
||||
#include "MinidumpExceptionMac.h"
|
||||
#include "MinidumpExceptionPs3.h"
|
||||
#include "MinidumpExceptionSolaris.h"
|
||||
#include "MinidumpExceptionWin32.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t thread_id; /* Thread in which the exception
|
||||
* occurred. Corresponds to
|
||||
* (MDRawThread).thread_id. */
|
||||
uint32_t __align;
|
||||
MDException exception_record;
|
||||
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
|
||||
} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */
|
||||
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */
|
||||
uint32_t version_information; /* cpuid 1: eax */
|
||||
uint32_t feature_information; /* cpuid 1: edx */
|
||||
uint32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
|
||||
} x86_cpu_info;
|
||||
struct {
|
||||
uint32_t cpuid;
|
||||
uint32_t elf_hwcaps; /* linux specific, 0 otherwise */
|
||||
} arm_cpu_info;
|
||||
struct {
|
||||
uint64_t processor_features[2];
|
||||
} other_cpu_info;
|
||||
} MDCPUInformation; /* CPU_INFORMATION */
|
||||
|
||||
/* For (MDCPUInformation).arm_cpu_info.elf_hwcaps.
|
||||
* This matches the Linux kernel definitions from <asm/hwcaps.h> */
|
||||
typedef enum {
|
||||
MD_CPU_ARM_ELF_HWCAP_SWP = (1 << 0),
|
||||
MD_CPU_ARM_ELF_HWCAP_HALF = (1 << 1),
|
||||
MD_CPU_ARM_ELF_HWCAP_THUMB = (1 << 2),
|
||||
MD_CPU_ARM_ELF_HWCAP_26BIT = (1 << 3),
|
||||
MD_CPU_ARM_ELF_HWCAP_FAST_MULT = (1 << 4),
|
||||
MD_CPU_ARM_ELF_HWCAP_FPA = (1 << 5),
|
||||
MD_CPU_ARM_ELF_HWCAP_VFP = (1 << 6),
|
||||
MD_CPU_ARM_ELF_HWCAP_EDSP = (1 << 7),
|
||||
MD_CPU_ARM_ELF_HWCAP_JAVA = (1 << 8),
|
||||
MD_CPU_ARM_ELF_HWCAP_IWMMXT = (1 << 9),
|
||||
MD_CPU_ARM_ELF_HWCAP_CRUNCH = (1 << 10),
|
||||
MD_CPU_ARM_ELF_HWCAP_THUMBEE = (1 << 11),
|
||||
MD_CPU_ARM_ELF_HWCAP_NEON = (1 << 12),
|
||||
MD_CPU_ARM_ELF_HWCAP_VFPv3 = (1 << 13),
|
||||
MD_CPU_ARM_ELF_HWCAP_VFPv3D16 = (1 << 14),
|
||||
MD_CPU_ARM_ELF_HWCAP_TLS = (1 << 15),
|
||||
MD_CPU_ARM_ELF_HWCAP_VFPv4 = (1 << 16),
|
||||
MD_CPU_ARM_ELF_HWCAP_IDIVA = (1 << 17),
|
||||
MD_CPU_ARM_ELF_HWCAP_IDIVT = (1 << 18),
|
||||
} MDCPUInformationARMElfHwCaps;
|
||||
|
||||
typedef struct {
|
||||
/* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO
|
||||
* structure as returned by GetSystemInfo */
|
||||
uint16_t processor_architecture;
|
||||
uint16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */
|
||||
/* ARM: 6 = ARMv6, 7 = ARMv7 ... */
|
||||
uint16_t processor_revision; /* x86: 0xMMSS, where MM=model,
|
||||
* SS=stepping */
|
||||
/* ARM: 0 */
|
||||
|
||||
uint8_t number_of_processors;
|
||||
uint8_t product_type; /* Windows: VER_NT_* from WinNT.h */
|
||||
|
||||
/* The next 5 fields are from the OSVERSIONINFO structure as returned
|
||||
* by GetVersionEx */
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
uint32_t build_number;
|
||||
uint32_t platform_id;
|
||||
MDRVA csd_version_rva; /* MDString further identifying the
|
||||
* host OS.
|
||||
* Windows: name of the installed OS
|
||||
* service pack.
|
||||
* Mac OS X: the Apple OS build number
|
||||
* (sw_vers -buildVersion).
|
||||
* Linux: uname -srvmo */
|
||||
|
||||
uint16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
|
||||
uint16_t reserved2;
|
||||
|
||||
MDCPUInformation cpu;
|
||||
} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */
|
||||
|
||||
/* For (MDRawSystemInfo).processor_architecture: */
|
||||
typedef enum {
|
||||
MD_CPU_ARCHITECTURE_X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */
|
||||
MD_CPU_ARCHITECTURE_MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */
|
||||
MD_CPU_ARCHITECTURE_ALPHA = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */
|
||||
MD_CPU_ARCHITECTURE_PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */
|
||||
MD_CPU_ARCHITECTURE_SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX
|
||||
* (Super-H) */
|
||||
MD_CPU_ARCHITECTURE_ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */
|
||||
MD_CPU_ARCHITECTURE_IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */
|
||||
MD_CPU_ARCHITECTURE_ALPHA64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */
|
||||
MD_CPU_ARCHITECTURE_MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL
|
||||
* (Microsoft Intermediate Language) */
|
||||
MD_CPU_ARCHITECTURE_AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */
|
||||
MD_CPU_ARCHITECTURE_X86_WIN64 = 10,
|
||||
/* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
|
||||
MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */
|
||||
MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */
|
||||
MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
|
||||
} MDCPUArchitecture;
|
||||
|
||||
/* For (MDRawSystemInfo).platform_id: */
|
||||
typedef enum {
|
||||
MD_OS_WIN32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */
|
||||
MD_OS_WIN32_WINDOWS = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */
|
||||
MD_OS_WIN32_NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */
|
||||
MD_OS_WIN32_CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
|
||||
* (Windows CE, Windows Mobile, "Handheld") */
|
||||
|
||||
/* The following values are Breakpad-defined. */
|
||||
MD_OS_UNIX = 0x8000, /* Generic Unix-ish */
|
||||
MD_OS_MAC_OS_X = 0x8101, /* Mac OS X/Darwin */
|
||||
MD_OS_IOS = 0x8102, /* iOS */
|
||||
MD_OS_LINUX = 0x8201, /* Linux */
|
||||
MD_OS_SOLARIS = 0x8202, /* Solaris */
|
||||
MD_OS_ANDROID = 0x8203, /* Android */
|
||||
MD_OS_PS3 = 0x8204, /* PS3 */
|
||||
MD_OS_NACL = 0x8205 /* Native Client (NaCl) */
|
||||
} MDOSPlatform;
|
||||
|
||||
typedef struct {
|
||||
uint16_t year;
|
||||
uint16_t month;
|
||||
uint16_t day_of_week;
|
||||
uint16_t day;
|
||||
uint16_t hour;
|
||||
uint16_t minute;
|
||||
uint16_t second;
|
||||
uint16_t milliseconds;
|
||||
} MDSystemTime; /* SYSTEMTIME */
|
||||
|
||||
typedef struct {
|
||||
/* Required field. The bias is the difference, in minutes, between
|
||||
* Coordinated Universal Time (UTC) and local time.
|
||||
* Formula: UTC = local time + bias */
|
||||
int32_t bias;
|
||||
/* A description for standard time. For example, "EST" could indicate Eastern
|
||||
* Standard Time. In practice this contains the full time zone names. This
|
||||
* string can be empty. */
|
||||
uint16_t standard_name[32]; /* UTF-16-encoded, 0-terminated */
|
||||
/* A MDSystemTime structure that contains a date and local time when the
|
||||
* transition from daylight saving time to standard time occurs on this
|
||||
* operating system. If the time zone does not support daylight saving time,
|
||||
* the month member in the MDSystemTime structure is zero. */
|
||||
MDSystemTime standard_date;
|
||||
/* The bias value to be used during local time translations that occur during
|
||||
* standard time. */
|
||||
int32_t standard_bias;
|
||||
/* A description for daylight saving time. For example, "PDT" could indicate
|
||||
* Pacific Daylight Time. In practice this contains the full time zone names.
|
||||
* This string can be empty. */
|
||||
uint16_t daylight_name[32]; /* UTF-16-encoded, 0-terminated */
|
||||
/* A MDSystemTime structure that contains a date and local time when the
|
||||
* transition from standard time to daylight saving time occurs on this
|
||||
* operating system. If the time zone does not support daylight saving time,
|
||||
* the month member in the MDSystemTime structure is zero.*/
|
||||
MDSystemTime daylight_date;
|
||||
/* The bias value to be used during local time translations that occur during
|
||||
* daylight saving time. */
|
||||
int32_t daylight_bias;
|
||||
} MDTimeZoneInformation; /* TIME_ZONE_INFORMATION */
|
||||
|
||||
/* MAX_PATH from windef.h */
|
||||
#define MD_MAX_PATH 260
|
||||
|
||||
/* The miscellaneous information stream contains a variety
|
||||
* of small pieces of information. A member is valid if
|
||||
* it's within the available size and its corresponding
|
||||
* bit is set. */
|
||||
typedef struct {
|
||||
uint32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */
|
||||
uint32_t flags1;
|
||||
|
||||
/* The next field is only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROCESS_ID. */
|
||||
uint32_t process_id;
|
||||
|
||||
/* The next 3 fields are only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROCESS_TIMES. */
|
||||
uint32_t process_create_time; /* time_t process started */
|
||||
uint32_t process_user_time; /* seconds of user CPU time */
|
||||
uint32_t process_kernel_time; /* seconds of kernel CPU time */
|
||||
|
||||
/* The following fields are not present in MINIDUMP_MISC_INFO but are
|
||||
* in MINIDUMP_MISC_INFO_2. When this struct is populated, these value
|
||||
* may not be set. Use flags1 or size_of_info to determine whether these
|
||||
* values are present. These are only valid when flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */
|
||||
uint32_t processor_max_mhz;
|
||||
uint32_t processor_current_mhz;
|
||||
uint32_t processor_mhz_limit;
|
||||
uint32_t processor_max_idle_state;
|
||||
uint32_t processor_current_idle_state;
|
||||
|
||||
/* The following fields are not present in MINIDUMP_MISC_INFO_2 but are
|
||||
* in MINIDUMP_MISC_INFO_3. When this struct is populated, these value
|
||||
* may not be set. Use flags1 or size_of_info to determine whether these
|
||||
* values are present. */
|
||||
|
||||
/* The following field is only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY. */
|
||||
uint32_t process_integrity_level;
|
||||
|
||||
/* The following field is only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS. */
|
||||
uint32_t process_execute_flags;
|
||||
|
||||
/* The following field is only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_PROTECTED_PROCESS. */
|
||||
uint32_t protected_process;
|
||||
|
||||
/* The following 2 fields are only valid if flags1 contains
|
||||
* MD_MISCINFO_FLAGS1_TIMEZONE. */
|
||||
uint32_t time_zone_id;
|
||||
MDTimeZoneInformation time_zone;
|
||||
|
||||
/* The following fields are not present in MINIDUMP_MISC_INFO_3 but are
|
||||
* in MINIDUMP_MISC_INFO_4. When this struct is populated, these value
|
||||
* may not be set. Use size_of_info to determine whether these values are
|
||||
* present. */
|
||||
|
||||
/* The following 2 fields are only valid if
|
||||
* size_of_info is >= MD_MISCINFO4_SIZE */
|
||||
uint16_t build_string[MD_MAX_PATH]; /* UTF-16-encoded, 0-terminated */
|
||||
uint16_t dbg_bld_str[40]; /* UTF-16-encoded, 0-terminated */
|
||||
} MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO2,
|
||||
* MINIDUMP_MISC_INFO3, MINIDUMP_MISC_INFO4 */
|
||||
|
||||
static const size_t MD_MISCINFO_SIZE =
|
||||
offsetof(MDRawMiscInfo, processor_max_mhz);
|
||||
static const size_t MD_MISCINFO2_SIZE =
|
||||
offsetof(MDRawMiscInfo, process_integrity_level);
|
||||
static const size_t MD_MISCINFO3_SIZE =
|
||||
offsetof(MDRawMiscInfo, build_string[0]);
|
||||
static const size_t MD_MISCINFO4_SIZE = sizeof(MDRawMiscInfo);
|
||||
|
||||
/* For (MDRawMiscInfo).flags1. These values indicate which fields in the
|
||||
* MDRawMiscInfoStructure are valid. */
|
||||
typedef enum {
|
||||
MD_MISCINFO_FLAGS1_PROCESS_ID = 0x00000001,
|
||||
/* MINIDUMP_MISC1_PROCESS_ID */
|
||||
MD_MISCINFO_FLAGS1_PROCESS_TIMES = 0x00000002,
|
||||
/* MINIDUMP_MISC1_PROCESS_TIMES */
|
||||
MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004,
|
||||
/* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */
|
||||
MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY = 0x00000010,
|
||||
/* MINIDUMP_MISC3_PROCESS_INTEGRITY */
|
||||
MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS = 0x00000020,
|
||||
/* MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS */
|
||||
MD_MISCINFO_FLAGS1_TIMEZONE = 0x00000040,
|
||||
/* MINIDUMP_MISC3_TIMEZONE */
|
||||
MD_MISCINFO_FLAGS1_PROTECTED_PROCESS = 0x00000080,
|
||||
/* MINIDUMP_MISC3_PROTECTED_PROCESS */
|
||||
} MDMiscInfoFlags1;
|
||||
|
||||
/*
|
||||
* Around DbgHelp version 6.0, the style of new LIST structures changed
|
||||
* from including an array of length 1 at the end of the struct to
|
||||
* represent the variable-length data to including explicit
|
||||
* "size of header", "size of entry" and "number of entries" fields
|
||||
* in the header, presumably to allow backwards-compatibly-extending
|
||||
* the structures in the future. The actual list entries follow the
|
||||
* header data directly in this case.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t size_of_header; /* sizeof(MDRawMemoryInfoList) */
|
||||
uint32_t size_of_entry; /* sizeof(MDRawMemoryInfo) */
|
||||
uint64_t number_of_entries;
|
||||
} MDRawMemoryInfoList; /* MINIDUMP_MEMORY_INFO_LIST */
|
||||
|
||||
typedef struct {
|
||||
uint64_t base_address; /* Base address of a region of pages */
|
||||
uint64_t allocation_base; /* Base address of a range of pages
|
||||
* within this region. */
|
||||
uint32_t allocation_protection; /* Memory protection when this region
|
||||
* was originally allocated:
|
||||
* MDMemoryProtection */
|
||||
uint32_t __alignment1;
|
||||
uint64_t region_size;
|
||||
uint32_t state; /* MDMemoryState */
|
||||
uint32_t protection; /* MDMemoryProtection */
|
||||
uint32_t type; /* MDMemoryType */
|
||||
uint32_t __alignment2;
|
||||
} MDRawMemoryInfo; /* MINIDUMP_MEMORY_INFO */
|
||||
|
||||
/* For (MDRawMemoryInfo).state */
|
||||
typedef enum {
|
||||
MD_MEMORY_STATE_COMMIT = 0x1000, /* physical storage has been allocated */
|
||||
MD_MEMORY_STATE_RESERVE = 0x2000, /* reserved, but no physical storage */
|
||||
MD_MEMORY_STATE_FREE = 0x10000 /* available to be allocated */
|
||||
} MDMemoryState;
|
||||
|
||||
/* For (MDRawMemoryInfo).allocation_protection and .protection */
|
||||
typedef enum {
|
||||
MD_MEMORY_PROTECT_NOACCESS = 0x01, /* PAGE_NOACCESS */
|
||||
MD_MEMORY_PROTECT_READONLY = 0x02, /* PAGE_READONLY */
|
||||
MD_MEMORY_PROTECT_READWRITE = 0x04, /* PAGE_READWRITE */
|
||||
MD_MEMORY_PROTECT_WRITECOPY = 0x08, /* PAGE_WRITECOPY */
|
||||
MD_MEMORY_PROTECT_EXECUTE = 0x10, /* PAGE_EXECUTE */
|
||||
MD_MEMORY_PROTECT_EXECUTE_READ = 0x20, /* PAGE_EXECUTE_READ */
|
||||
MD_MEMORY_PROTECT_EXECUTE_READWRITE = 0x40, /* PAGE_EXECUTE_READWRITE */
|
||||
MD_MEMORY_PROTECT_EXECUTE_WRITECOPY = 0x80, /* PAGE_EXECUTE_WRITECOPY */
|
||||
/* These options can be combined with the previous flags. */
|
||||
MD_MEMORY_PROTECT_GUARD = 0x100, /* PAGE_GUARD */
|
||||
MD_MEMORY_PROTECT_NOCACHE = 0x200, /* PAGE_NOCACHE */
|
||||
MD_MEMORY_PROTECT_WRITECOMBINE = 0x400, /* PAGE_WRITECOMBINE */
|
||||
} MDMemoryProtection;
|
||||
|
||||
/* Used to mask the mutually exclusive options from the combinable flags. */
|
||||
const uint32_t MD_MEMORY_PROTECTION_ACCESS_MASK = 0xFF;
|
||||
|
||||
/* For (MDRawMemoryInfo).type */
|
||||
typedef enum {
|
||||
MD_MEMORY_TYPE_PRIVATE = 0x20000, /* not shared by other processes */
|
||||
MD_MEMORY_TYPE_MAPPED = 0x40000, /* mapped into the view of a section */
|
||||
MD_MEMORY_TYPE_IMAGE = 0x1000000 /* mapped into the view of an image */
|
||||
} MDMemoryType;
|
||||
|
||||
/*
|
||||
* Breakpad extension types
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* validity is a bitmask with values from MDBreakpadInfoValidity, indicating
|
||||
* which of the other fields in the structure are valid. */
|
||||
uint32_t validity;
|
||||
|
||||
/* Thread ID of the handler thread. dump_thread_id should correspond to
|
||||
* the thread_id of an MDRawThread in the minidump's MDRawThreadList if
|
||||
* a dedicated thread in that list was used to produce the minidump. If
|
||||
* the MDRawThreadList does not contain a dedicated thread used to produce
|
||||
* the minidump, this field should be set to 0 and the validity field
|
||||
* must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */
|
||||
uint32_t dump_thread_id;
|
||||
|
||||
/* Thread ID of the thread that requested the minidump be produced. As
|
||||
* with dump_thread_id, requesting_thread_id should correspond to the
|
||||
* thread_id of an MDRawThread in the minidump's MDRawThreadList. For
|
||||
* minidumps produced as a result of an exception, requesting_thread_id
|
||||
* will be the same as the MDRawExceptionStream's thread_id field. For
|
||||
* minidumps produced "manually" at the program's request,
|
||||
* requesting_thread_id will indicate which thread caused the dump to be
|
||||
* written. If the minidump was produced at the request of something
|
||||
* other than a thread in the MDRawThreadList, this field should be set
|
||||
* to 0 and the validity field must not contain
|
||||
* MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */
|
||||
uint32_t requesting_thread_id;
|
||||
} MDRawBreakpadInfo;
|
||||
|
||||
/* For (MDRawBreakpadInfo).validity: */
|
||||
typedef enum {
|
||||
/* When set, the dump_thread_id field is valid. */
|
||||
MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID = 1 << 0,
|
||||
|
||||
/* When set, the requesting_thread_id field is valid. */
|
||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID = 1 << 1
|
||||
} MDBreakpadInfoValidity;
|
||||
|
||||
typedef struct {
|
||||
/* expression, function, and file are 0-terminated UTF-16 strings. They
|
||||
* may be truncated if necessary, but should always be 0-terminated when
|
||||
* written to a file.
|
||||
* Fixed-length strings are used because MiniDumpWriteDump doesn't offer
|
||||
* a way for user streams to point to arbitrary RVAs for strings. */
|
||||
uint16_t expression[128]; /* Assertion that failed... */
|
||||
uint16_t function[128]; /* ...within this function... */
|
||||
uint16_t file[128]; /* ...in this file... */
|
||||
uint32_t line; /* ...at this line. */
|
||||
uint32_t type;
|
||||
} MDRawAssertionInfo;
|
||||
|
||||
/* For (MDRawAssertionInfo).type: */
|
||||
typedef enum {
|
||||
MD_ASSERTION_INFO_TYPE_UNKNOWN = 0,
|
||||
|
||||
/* Used for assertions that would be raised by the MSVC CRT but are
|
||||
* directed to an invalid parameter handler instead. */
|
||||
MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER,
|
||||
|
||||
/* Used for assertions that would be raised by the MSVC CRT but are
|
||||
* directed to a pure virtual call handler instead. */
|
||||
MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL
|
||||
} MDAssertionInfoData;
|
||||
|
||||
/* These structs are used to store the DSO debug data in Linux minidumps,
|
||||
* which is necessary for converting minidumps to usable coredumps. */
|
||||
typedef struct {
|
||||
void* addr;
|
||||
MDRVA name;
|
||||
void* ld;
|
||||
} MDRawLinkMap;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
MDRVA map;
|
||||
uint32_t dso_count;
|
||||
void* brk;
|
||||
void* ldbase;
|
||||
void* dynamic;
|
||||
} MDRawDebug;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */
|
||||
@@ -0,0 +1,536 @@
|
||||
#include "MinidumpGenerator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <avrfsdk.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "AutoCriticalSection.h"
|
||||
#include "GuidString.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
// A helper class used to collect handle operations data. Unlike
|
||||
// |MiniDumpWithHandleData| it records the operations for a single handle value
|
||||
// only, making it possible to include this information to a minidump.
|
||||
class HandleTraceData {
|
||||
public:
|
||||
HandleTraceData();
|
||||
~HandleTraceData();
|
||||
|
||||
// Collects the handle operations data and formats a user stream to be added
|
||||
// to the minidump.
|
||||
bool CollectHandleData(HANDLE process_handle,
|
||||
EXCEPTION_POINTERS* exception_pointers);
|
||||
|
||||
// Fills the user dump entry with a pointer to the collected handle operations
|
||||
// data. Returns |true| if the entry was initialized successfully, or |false|
|
||||
// if no trace data is available.
|
||||
bool GetUserStream(MINIDUMP_USER_STREAM* user_stream);
|
||||
|
||||
private:
|
||||
// Reads the exception code from the client process's address space.
|
||||
// This routine assumes that the client process's pointer width matches ours.
|
||||
static bool ReadExceptionCode(HANDLE process_handle,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
DWORD* exception_code);
|
||||
|
||||
// Stores handle operations retrieved by VerifierEnumerateResource().
|
||||
static ULONG CALLBACK RecordHandleOperations(void* resource_description,
|
||||
void* enumeration_context,
|
||||
ULONG* enumeration_level);
|
||||
|
||||
// Function pointer type for VerifierEnumerateResource, which is looked up
|
||||
// dynamically.
|
||||
typedef BOOL (WINAPI* VerifierEnumerateResourceType)(
|
||||
HANDLE Process,
|
||||
ULONG Flags,
|
||||
ULONG ResourceType,
|
||||
AVRF_RESOURCE_ENUMERATE_CALLBACK ResourceCallback,
|
||||
PVOID EnumerationContext);
|
||||
|
||||
// Handle to dynamically loaded verifier.dll.
|
||||
HMODULE verifier_module_;
|
||||
|
||||
// Pointer to the VerifierEnumerateResource function.
|
||||
VerifierEnumerateResourceType enumerate_resource_;
|
||||
|
||||
// Handle value to look for.
|
||||
ULONG64 handle_;
|
||||
|
||||
// List of handle operations for |handle_|.
|
||||
std::list<AVRF_HANDLE_OPERATION> operations_;
|
||||
|
||||
// Minidump stream data.
|
||||
std::vector<char> stream_;
|
||||
};
|
||||
|
||||
HandleTraceData::HandleTraceData()
|
||||
: verifier_module_(NULL),
|
||||
enumerate_resource_(NULL),
|
||||
handle_(NULL) {
|
||||
}
|
||||
|
||||
HandleTraceData::~HandleTraceData() {
|
||||
if (verifier_module_) {
|
||||
FreeLibrary(verifier_module_);
|
||||
}
|
||||
}
|
||||
|
||||
bool HandleTraceData::CollectHandleData(
|
||||
HANDLE process_handle,
|
||||
EXCEPTION_POINTERS* exception_pointers) {
|
||||
DWORD exception_code;
|
||||
if (!ReadExceptionCode(process_handle, exception_pointers, &exception_code)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify whether the execption is STATUS_INVALID_HANDLE. Do not record any
|
||||
// handle information if it is a different exception to keep the minidump
|
||||
// small.
|
||||
if (exception_code != STATUS_INVALID_HANDLE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load verifier!VerifierEnumerateResource() dynamically.
|
||||
verifier_module_ = LoadLibrary(TEXT("verifier.dll"));
|
||||
if (!verifier_module_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
enumerate_resource_ = reinterpret_cast<VerifierEnumerateResourceType>(
|
||||
GetProcAddress(verifier_module_, "VerifierEnumerateResource"));
|
||||
if (!enumerate_resource_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// STATUS_INVALID_HANDLE does not provide the offending handle value in
|
||||
// the exception parameters so we have to guess. At the moment we scan
|
||||
// the handle operations trace looking for the last invalid handle operation
|
||||
// and record only the operations for that handle value.
|
||||
if (enumerate_resource_(process_handle,
|
||||
0,
|
||||
AvrfResourceHandleTrace,
|
||||
&RecordHandleOperations,
|
||||
this) != ERROR_SUCCESS) {
|
||||
// The handle tracing must have not been enabled.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now that |handle_| is initialized, purge all irrelevant operations.
|
||||
std::list<AVRF_HANDLE_OPERATION>::iterator i = operations_.begin();
|
||||
std::list<AVRF_HANDLE_OPERATION>::iterator i_end = operations_.end();
|
||||
while (i != i_end) {
|
||||
if (i->Handle == handle_) {
|
||||
++i;
|
||||
} else {
|
||||
i = operations_.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the list of recorded operations to a minidump stream.
|
||||
stream_.resize(sizeof(MINIDUMP_HANDLE_OPERATION_LIST) +
|
||||
sizeof(AVRF_HANDLE_OPERATION) * operations_.size());
|
||||
|
||||
MINIDUMP_HANDLE_OPERATION_LIST* stream_data =
|
||||
reinterpret_cast<MINIDUMP_HANDLE_OPERATION_LIST*>(
|
||||
&stream_.front());
|
||||
stream_data->SizeOfHeader = sizeof(MINIDUMP_HANDLE_OPERATION_LIST);
|
||||
stream_data->SizeOfEntry = sizeof(AVRF_HANDLE_OPERATION);
|
||||
stream_data->NumberOfEntries = static_cast<ULONG32>(operations_.size());
|
||||
stream_data->Reserved = 0;
|
||||
std::copy(operations_.begin(),
|
||||
operations_.end(),
|
||||
stdext::checked_array_iterator<AVRF_HANDLE_OPERATION*>(
|
||||
reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1),
|
||||
operations_.size()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleTraceData::GetUserStream(MINIDUMP_USER_STREAM* user_stream) {
|
||||
if (stream_.empty()) {
|
||||
return false;
|
||||
} else {
|
||||
user_stream->Type = HandleOperationListStream;
|
||||
user_stream->BufferSize = static_cast<ULONG>(stream_.size());
|
||||
user_stream->Buffer = &stream_.front();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool HandleTraceData::ReadExceptionCode(
|
||||
HANDLE process_handle,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
DWORD* exception_code) {
|
||||
EXCEPTION_POINTERS pointers;
|
||||
if (!ReadProcessMemory(process_handle,
|
||||
exception_pointers,
|
||||
&pointers,
|
||||
sizeof(pointers),
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadProcessMemory(process_handle,
|
||||
pointers.ExceptionRecord,
|
||||
exception_code,
|
||||
sizeof(*exception_code),
|
||||
NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ULONG CALLBACK HandleTraceData::RecordHandleOperations(
|
||||
void* resource_description,
|
||||
void* enumeration_context,
|
||||
ULONG* enumeration_level) {
|
||||
AVRF_HANDLE_OPERATION* description =
|
||||
reinterpret_cast<AVRF_HANDLE_OPERATION*>(resource_description);
|
||||
HandleTraceData* self =
|
||||
reinterpret_cast<HandleTraceData*>(enumeration_context);
|
||||
|
||||
// Remember the last invalid handle operation.
|
||||
if (description->OperationType == OperationDbBADREF) {
|
||||
self->handle_ = description->Handle;
|
||||
}
|
||||
|
||||
// Record all handle operations.
|
||||
self->operations_.push_back(*description);
|
||||
|
||||
*enumeration_level = HeapEnumerationEverything;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
MinidumpGenerator::MinidumpGenerator(const string& dump_path)
|
||||
: dbghelp_module_(NULL),
|
||||
rpcrt4_module_(NULL),
|
||||
dump_path_(dump_path),
|
||||
write_dump_(NULL),
|
||||
create_uuid_(NULL) {
|
||||
InitializeCriticalSection(&module_load_sync_);
|
||||
InitializeCriticalSection(&get_proc_address_sync_);
|
||||
}
|
||||
|
||||
MinidumpGenerator::~MinidumpGenerator() {
|
||||
if (dbghelp_module_) {
|
||||
FreeLibrary(dbghelp_module_);
|
||||
}
|
||||
|
||||
if (rpcrt4_module_) {
|
||||
FreeLibrary(rpcrt4_module_);
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&get_proc_address_sync_);
|
||||
DeleteCriticalSection(&module_load_sync_);
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
string* dump_path) {
|
||||
// Just call the full WriteMinidump with NULL as the full_dump_path.
|
||||
return this->WriteMinidump(process_handle, process_id, thread_id,
|
||||
requesting_thread_id, exception_pointers,
|
||||
assert_info, dump_type, is_client_pointers,
|
||||
dump_path, NULL);
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
string* dump_path,
|
||||
string* full_dump_path) {
|
||||
string dump_file_path;
|
||||
if (!GenerateDumpFilePath(&dump_file_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the client requests a full memory dump, we will write a normal mini
|
||||
// dump and a full memory dump. Both dump files use the same uuid as file
|
||||
// name prefix.
|
||||
bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0;
|
||||
string full_dump_file_path;
|
||||
if (full_memory_dump) {
|
||||
full_dump_file_path.assign(dump_file_path);
|
||||
full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp
|
||||
full_dump_file_path.append(TEXT("-full.dmp"));
|
||||
}
|
||||
|
||||
HANDLE dump_file = CreateFile(dump_file_path.c_str(),
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (dump_file == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE full_dump_file = INVALID_HANDLE_VALUE;
|
||||
if (full_memory_dump) {
|
||||
full_dump_file = CreateFile(full_dump_file_path.c_str(),
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (full_dump_file == INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(dump_file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = WriteMinidump(process_handle,
|
||||
process_id,
|
||||
thread_id,
|
||||
requesting_thread_id,
|
||||
exception_pointers,
|
||||
assert_info,
|
||||
dump_type,
|
||||
is_client_pointers,
|
||||
dump_file,
|
||||
full_dump_file);
|
||||
|
||||
// Store the path of the dump file in the out parameter if dump generation
|
||||
// succeeded.
|
||||
if (result && dump_path) {
|
||||
*dump_path = dump_file_path;
|
||||
}
|
||||
if (result && full_memory_dump && full_dump_path) {
|
||||
*full_dump_path = full_dump_file_path;
|
||||
}
|
||||
|
||||
CloseHandle(dump_file);
|
||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(full_dump_file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
HANDLE dump_file,
|
||||
HANDLE full_dump_file) {
|
||||
bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0;
|
||||
if (dump_file == INVALID_HANDLE_VALUE ||
|
||||
(full_memory_dump && full_dump_file == INVALID_HANDLE_VALUE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MiniDumpWriteDumpType write_dump = GetWriteDump();
|
||||
if (!write_dump) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
|
||||
MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
|
||||
|
||||
// Setup the exception information object only if it's a dump
|
||||
// due to an exception.
|
||||
if (exception_pointers) {
|
||||
dump_exception_pointers = &dump_exception_info;
|
||||
dump_exception_info.ThreadId = thread_id;
|
||||
dump_exception_info.ExceptionPointers = exception_pointers;
|
||||
dump_exception_info.ClientPointers = is_client_pointers;
|
||||
}
|
||||
|
||||
// Add an MDRawBreakpadInfo stream to the minidump, to provide additional
|
||||
// information about the exception handler to the Breakpad processor.
|
||||
// The information will help the processor determine which threads are
|
||||
// relevant. The Breakpad processor does not require this information but
|
||||
// can function better with Breakpad-generated dumps when it is present.
|
||||
// The native debugger is not harmed by the presence of this information.
|
||||
MDRawBreakpadInfo breakpad_info = {0};
|
||||
if (!is_client_pointers) {
|
||||
// Set the dump thread id and requesting thread id only in case of
|
||||
// in-process dump generation.
|
||||
breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
|
||||
MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
|
||||
breakpad_info.dump_thread_id = thread_id;
|
||||
breakpad_info.requesting_thread_id = requesting_thread_id;
|
||||
}
|
||||
|
||||
// Leave room in user_stream_array for possible assertion info and handle
|
||||
// operations streams.
|
||||
MINIDUMP_USER_STREAM user_stream_array[3];
|
||||
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
|
||||
user_stream_array[0].BufferSize = sizeof(breakpad_info);
|
||||
user_stream_array[0].Buffer = &breakpad_info;
|
||||
|
||||
MINIDUMP_USER_STREAM_INFORMATION user_streams;
|
||||
user_streams.UserStreamCount = 1;
|
||||
user_streams.UserStreamArray = user_stream_array;
|
||||
|
||||
MDRawAssertionInfo* actual_assert_info = assert_info;
|
||||
MDRawAssertionInfo client_assert_info = {0};
|
||||
|
||||
if (assert_info) {
|
||||
// If the assertion info object lives in the client process,
|
||||
// read the memory of the client process.
|
||||
if (is_client_pointers) {
|
||||
SIZE_T bytes_read = 0;
|
||||
if (!ReadProcessMemory(process_handle,
|
||||
assert_info,
|
||||
&client_assert_info,
|
||||
sizeof(client_assert_info),
|
||||
&bytes_read)) {
|
||||
CloseHandle(dump_file);
|
||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(full_dump_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bytes_read != sizeof(client_assert_info)) {
|
||||
CloseHandle(dump_file);
|
||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(full_dump_file);
|
||||
return false;
|
||||
}
|
||||
|
||||
actual_assert_info = &client_assert_info;
|
||||
}
|
||||
|
||||
user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
|
||||
user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
|
||||
user_stream_array[1].Buffer = actual_assert_info;
|
||||
++user_streams.UserStreamCount;
|
||||
}
|
||||
|
||||
// If the process is terminated by STATUS_INVALID_HANDLE exception store
|
||||
// the trace of operatios for the offending handle value. Do nothing special
|
||||
// if the client already requested the handle trace to be stored in the dump.
|
||||
HandleTraceData handle_trace_data;
|
||||
if (exception_pointers && (dump_type & MiniDumpWithHandleData) == 0) {
|
||||
if (!handle_trace_data.CollectHandleData(process_handle,
|
||||
exception_pointers)) {
|
||||
CloseHandle(dump_file);
|
||||
if (full_dump_file != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(full_dump_file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool result_full_memory = true;
|
||||
if (full_memory_dump) {
|
||||
result_full_memory = write_dump(
|
||||
process_handle,
|
||||
process_id,
|
||||
full_dump_file,
|
||||
static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpNormal))
|
||||
| MiniDumpWithHandleData),
|
||||
exception_pointers ? &dump_exception_info : NULL,
|
||||
&user_streams,
|
||||
NULL) != FALSE;
|
||||
}
|
||||
|
||||
// Add handle operations trace stream to the minidump if it was collected.
|
||||
if (handle_trace_data.GetUserStream(
|
||||
&user_stream_array[user_streams.UserStreamCount])) {
|
||||
++user_streams.UserStreamCount;
|
||||
}
|
||||
|
||||
bool result_minidump = write_dump(
|
||||
process_handle,
|
||||
process_id,
|
||||
dump_file,
|
||||
static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpWithFullMemory))
|
||||
| MiniDumpNormal),
|
||||
exception_pointers ? &dump_exception_info : NULL,
|
||||
&user_streams,
|
||||
NULL) != FALSE;
|
||||
|
||||
return result_minidump && result_full_memory;
|
||||
}
|
||||
|
||||
HMODULE MinidumpGenerator::GetDbghelpModule() {
|
||||
AutoCriticalSection lock(&module_load_sync_);
|
||||
if (!dbghelp_module_) {
|
||||
dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
|
||||
}
|
||||
|
||||
return dbghelp_module_;
|
||||
}
|
||||
|
||||
MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
|
||||
AutoCriticalSection lock(&get_proc_address_sync_);
|
||||
if (!write_dump_) {
|
||||
HMODULE module = GetDbghelpModule();
|
||||
if (module) {
|
||||
FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
|
||||
write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
|
||||
}
|
||||
}
|
||||
|
||||
return write_dump_;
|
||||
}
|
||||
|
||||
HMODULE MinidumpGenerator::GetRpcrt4Module() {
|
||||
AutoCriticalSection lock(&module_load_sync_);
|
||||
if (!rpcrt4_module_) {
|
||||
rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
|
||||
}
|
||||
|
||||
return rpcrt4_module_;
|
||||
}
|
||||
|
||||
MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
|
||||
AutoCriticalSection lock(&module_load_sync_);
|
||||
if (!create_uuid_) {
|
||||
HMODULE module = GetRpcrt4Module();
|
||||
if (module) {
|
||||
FARPROC proc = GetProcAddress(module, "UuidCreate");
|
||||
create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
|
||||
}
|
||||
}
|
||||
|
||||
return create_uuid_;
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::GenerateDumpFilePath(string* file_path) {
|
||||
UUID id = {0};
|
||||
|
||||
UuidCreateType create_uuid = GetCreateUuid();
|
||||
if (!create_uuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
create_uuid(&id);
|
||||
string id_str = GUIDString::GUIDToWString(&id);
|
||||
|
||||
*file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
@@ -0,0 +1,122 @@
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <rpc.h>
|
||||
#include <list>
|
||||
#include "MinidumpFormat.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Abstraction for various objects and operations needed to generate
|
||||
// minidump on Windows. This abstraction is useful to hide all the gory
|
||||
// details for minidump generation and provide a clean interface to
|
||||
// the clients to generate minidumps.
|
||||
class MinidumpGenerator {
|
||||
public:
|
||||
// Creates an instance with the given dump path.
|
||||
explicit MinidumpGenerator(const std::string& dump_path);
|
||||
|
||||
~MinidumpGenerator();
|
||||
|
||||
// Writes the minidump with the given parameters. Stores the
|
||||
// dump file path in the dump_path parameter if dump generation
|
||||
// succeeds.
|
||||
bool WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
std::string* dump_path);
|
||||
|
||||
// Writes the minidump with the given parameters. Stores the dump file
|
||||
// path in the dump_path (and full_dump_path) parameter if dump
|
||||
// generation succeeds. full_dump_path and dump_path can be NULL.
|
||||
bool WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
std::string* dump_path,
|
||||
std::string* full_dump_path);
|
||||
|
||||
// Writes the minidump with the given parameters. Writes the minidump and
|
||||
// full dump to the file handles supplied. This allows the caller to handle
|
||||
// the creation of the files for the dump. The file handles are not closed
|
||||
// by this function.
|
||||
bool WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
HANDLE dump_file,
|
||||
HANDLE full_dump_file);
|
||||
|
||||
private:
|
||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||
// dynamically.
|
||||
typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
|
||||
HANDLE hProcess,
|
||||
DWORD ProcessId,
|
||||
HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
|
||||
// Function pointer type for UuidCreate, which is looked up dynamically.
|
||||
typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
|
||||
|
||||
// Loads the appropriate DLL lazily in a thread safe way.
|
||||
HMODULE GetDbghelpModule();
|
||||
|
||||
// Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
|
||||
// function lazily and in a thread-safe manner.
|
||||
MiniDumpWriteDumpType GetWriteDump();
|
||||
|
||||
// Loads the appropriate DLL lazily in a thread safe way.
|
||||
HMODULE GetRpcrt4Module();
|
||||
|
||||
// Loads the appropriate DLL and gets a pointer to the UuidCreate
|
||||
// function lazily and in a thread-safe manner.
|
||||
UuidCreateType GetCreateUuid();
|
||||
|
||||
// Returns the path for the file to write dump to.
|
||||
bool GenerateDumpFilePath(std::string* file_path);
|
||||
|
||||
// Handle to dynamically loaded DbgHelp.dll.
|
||||
HMODULE dbghelp_module_;
|
||||
|
||||
// Pointer to the MiniDumpWriteDump function.
|
||||
MiniDumpWriteDumpType write_dump_;
|
||||
|
||||
// Handle to dynamically loaded rpcrt4.dll.
|
||||
HMODULE rpcrt4_module_;
|
||||
|
||||
// Pointer to the UuidCreate function.
|
||||
UuidCreateType create_uuid_;
|
||||
|
||||
// Folder path to store dump files.
|
||||
std::string dump_path_;
|
||||
|
||||
// Critical section to sychronize action of loading modules dynamically.
|
||||
CRITICAL_SECTION module_load_sync_;
|
||||
|
||||
// Critical section to synchronize action of dynamically getting function
|
||||
// addresses from modules.
|
||||
CRITICAL_SECTION get_proc_address_sync_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
|
||||
@@ -0,0 +1,335 @@
|
||||
// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
|
||||
// Copyright (c) 2001, 2002 Peter Dimov
|
||||
//
|
||||
// Permission to copy, use, modify, sell and distribute this software
|
||||
// is granted provided this copyright notice appears in all copies.
|
||||
// This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
//
|
||||
// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
|
||||
//
|
||||
|
||||
// scoped_ptr mimics a built-in pointer except that it guarantees deletion
|
||||
// of the object pointed to, either on destruction of the scoped_ptr or via
|
||||
// an explicit reset(). scoped_ptr is a simple solution for simple needs;
|
||||
// use shared_ptr or std::auto_ptr if your needs are more complex.
|
||||
|
||||
// *** NOTE ***
|
||||
// If your scoped_ptr is a class member of class FOO pointing to a
|
||||
// forward declared type BAR (as shown below), then you MUST use a non-inlined
|
||||
// version of the destructor. The destructor of a scoped_ptr (called from
|
||||
// FOO's destructor) must have a complete definition of BAR in order to
|
||||
// destroy it. Example:
|
||||
//
|
||||
// -- foo.h --
|
||||
// class BAR;
|
||||
//
|
||||
// class FOO {
|
||||
// public:
|
||||
// FOO();
|
||||
// ~FOO(); // Required for sources that instantiate class FOO to compile!
|
||||
//
|
||||
// private:
|
||||
// scoped_ptr<BAR> bar_;
|
||||
// };
|
||||
//
|
||||
// -- foo.cc --
|
||||
// #include "foo.h"
|
||||
// FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition.
|
||||
|
||||
// scoped_ptr_malloc added by Google
|
||||
// When one of these goes out of scope, instead of doing a delete or
|
||||
// delete[], it calls free(). scoped_ptr_malloc<char> is likely to see
|
||||
// much more use than any other specializations.
|
||||
|
||||
// release() added by Google
|
||||
// Use this to conditionally transfer ownership of a heap-allocated object
|
||||
// to the caller, usually on method success.
|
||||
|
||||
#ifndef COMMON_SCOPED_PTR_H_
|
||||
#define COMMON_SCOPED_PTR_H_
|
||||
|
||||
#include <cstddef> // for std::ptrdiff_t
|
||||
#include <assert.h> // for assert
|
||||
#include <stdlib.h> // for free() decl
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
template <typename T>
|
||||
class scoped_ptr {
|
||||
private:
|
||||
|
||||
T* ptr;
|
||||
|
||||
scoped_ptr(scoped_ptr const &);
|
||||
scoped_ptr & operator=(scoped_ptr const &);
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit scoped_ptr(T* p = 0): ptr(p) {}
|
||||
|
||||
~scoped_ptr() {
|
||||
typedef char type_must_be_complete[sizeof(T)];
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void reset(T* p = 0) {
|
||||
typedef char type_must_be_complete[sizeof(T)];
|
||||
|
||||
if (ptr != p) {
|
||||
delete ptr;
|
||||
ptr = p;
|
||||
}
|
||||
}
|
||||
|
||||
T& operator*() const {
|
||||
assert(ptr != 0);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
assert(ptr != 0);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool operator==(T* p) const {
|
||||
return ptr == p;
|
||||
}
|
||||
|
||||
bool operator!=(T* p) const {
|
||||
return ptr != p;
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void swap(scoped_ptr & b) {
|
||||
T* tmp = b.ptr;
|
||||
b.ptr = ptr;
|
||||
ptr = tmp;
|
||||
}
|
||||
|
||||
T* release() {
|
||||
T* tmp = ptr;
|
||||
ptr = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// no reason to use these: each scoped_ptr should have its own object
|
||||
template <typename U> bool operator==(scoped_ptr<U> const& p) const;
|
||||
template <typename U> bool operator!=(scoped_ptr<U> const& p) const;
|
||||
};
|
||||
|
||||
template<typename T> inline
|
||||
void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<typename T> inline
|
||||
bool operator==(T* p, const scoped_ptr<T>& b) {
|
||||
return p == b.get();
|
||||
}
|
||||
|
||||
template<typename T> inline
|
||||
bool operator!=(T* p, const scoped_ptr<T>& b) {
|
||||
return p != b.get();
|
||||
}
|
||||
|
||||
// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
|
||||
// is guaranteed, either on destruction of the scoped_array or via an explicit
|
||||
// reset(). Use shared_array or std::vector if your needs are more complex.
|
||||
|
||||
template<typename T>
|
||||
class scoped_array {
|
||||
private:
|
||||
|
||||
T* ptr;
|
||||
|
||||
scoped_array(scoped_array const &);
|
||||
scoped_array & operator=(scoped_array const &);
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit scoped_array(T* p = 0) : ptr(p) {}
|
||||
|
||||
~scoped_array() {
|
||||
typedef char type_must_be_complete[sizeof(T)];
|
||||
delete[] ptr;
|
||||
}
|
||||
|
||||
void reset(T* p = 0) {
|
||||
typedef char type_must_be_complete[sizeof(T)];
|
||||
|
||||
if (ptr != p) {
|
||||
delete [] ptr;
|
||||
ptr = p;
|
||||
}
|
||||
}
|
||||
|
||||
T& operator[](std::ptrdiff_t i) const {
|
||||
assert(ptr != 0);
|
||||
assert(i >= 0);
|
||||
return ptr[i];
|
||||
}
|
||||
|
||||
bool operator==(T* p) const {
|
||||
return ptr == p;
|
||||
}
|
||||
|
||||
bool operator!=(T* p) const {
|
||||
return ptr != p;
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void swap(scoped_array & b) {
|
||||
T* tmp = b.ptr;
|
||||
b.ptr = ptr;
|
||||
ptr = tmp;
|
||||
}
|
||||
|
||||
T* release() {
|
||||
T* tmp = ptr;
|
||||
ptr = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// no reason to use these: each scoped_array should have its own object
|
||||
template <typename U> bool operator==(scoped_array<U> const& p) const;
|
||||
template <typename U> bool operator!=(scoped_array<U> const& p) const;
|
||||
};
|
||||
|
||||
template<class T> inline
|
||||
void swap(scoped_array<T>& a, scoped_array<T>& b) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<typename T> inline
|
||||
bool operator==(T* p, const scoped_array<T>& b) {
|
||||
return p == b.get();
|
||||
}
|
||||
|
||||
template<typename T> inline
|
||||
bool operator!=(T* p, const scoped_array<T>& b) {
|
||||
return p != b.get();
|
||||
}
|
||||
|
||||
|
||||
// This class wraps the c library function free() in a class that can be
|
||||
// passed as a template argument to scoped_ptr_malloc below.
|
||||
class ScopedPtrMallocFree {
|
||||
public:
|
||||
inline void operator()(void* x) const {
|
||||
free(x);
|
||||
}
|
||||
};
|
||||
|
||||
// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
|
||||
// second template argument, the functor used to free the object.
|
||||
|
||||
template<typename T, typename FreeProc = ScopedPtrMallocFree>
|
||||
class scoped_ptr_malloc {
|
||||
private:
|
||||
|
||||
T* ptr;
|
||||
|
||||
scoped_ptr_malloc(scoped_ptr_malloc const &);
|
||||
scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
|
||||
|
||||
public:
|
||||
|
||||
typedef T element_type;
|
||||
|
||||
explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
|
||||
|
||||
~scoped_ptr_malloc() {
|
||||
typedef char type_must_be_complete[sizeof(T)];
|
||||
free_((void*) ptr);
|
||||
}
|
||||
|
||||
void reset(T* p = 0) {
|
||||
typedef char type_must_be_complete[sizeof(T)];
|
||||
|
||||
if (ptr != p) {
|
||||
free_((void*) ptr);
|
||||
ptr = p;
|
||||
}
|
||||
}
|
||||
|
||||
T& operator*() const {
|
||||
assert(ptr != 0);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
assert(ptr != 0);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool operator==(T* p) const {
|
||||
return ptr == p;
|
||||
}
|
||||
|
||||
bool operator!=(T* p) const {
|
||||
return ptr != p;
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void swap(scoped_ptr_malloc & b) {
|
||||
T* tmp = b.ptr;
|
||||
b.ptr = ptr;
|
||||
ptr = tmp;
|
||||
}
|
||||
|
||||
T* release() {
|
||||
T* tmp = ptr;
|
||||
ptr = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// no reason to use these: each scoped_ptr_malloc should have its own object
|
||||
template <typename U, typename GP>
|
||||
bool operator==(scoped_ptr_malloc<U, GP> const& p) const;
|
||||
template <typename U, typename GP>
|
||||
bool operator!=(scoped_ptr_malloc<U, GP> const& p) const;
|
||||
|
||||
static FreeProc const free_;
|
||||
};
|
||||
|
||||
template<typename T, typename FP>
|
||||
FP const scoped_ptr_malloc<T,FP>::free_ = FP();
|
||||
|
||||
template<typename T, typename FP> inline
|
||||
void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
template<typename T, typename FP> inline
|
||||
bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) {
|
||||
return p == b.get();
|
||||
}
|
||||
|
||||
template<typename T, typename FP> inline
|
||||
bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) {
|
||||
return p != b.get();
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_SCOPED_PTR_H_
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2006, 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.
|
||||
|
||||
// string_utils-inl.h: Safer string manipulation on Windows, supporting
|
||||
// pre-MSVC8 environments.
|
||||
|
||||
#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__
|
||||
#define COMMON_WINDOWS_STRING_UTILS_INL_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
#include <tchar.h>
|
||||
#include <string>
|
||||
|
||||
// The "ll" printf format size specifier corresponding to |long long| was
|
||||
// intrudced in MSVC8. Earlier versions did not provide this size specifier,
|
||||
// but "I64" can be used to print 64-bit types. Don't use "I64" where "ll"
|
||||
// is available, in the event of oddball systems where |long long| is not
|
||||
// 64 bits wide.
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
#define WIN_STRING_FORMAT_LL "ll"
|
||||
#else // MSC_VER >= 1400
|
||||
#define WIN_STRING_FORMAT_LL "I64"
|
||||
#endif // MSC_VER >= 1400
|
||||
|
||||
// A nonconforming version of sprintf, without the length argument, was
|
||||
// included with the CRT prior to MSVC8. Although a conforming version was
|
||||
// also available via an overload, it is not reliably chosen. _snwprintf
|
||||
// behaves as a standards-confirming sprintf should, so force the use of
|
||||
// _snwprintf when using older CRTs.
|
||||
#if _MSC_VER < 1400 // MSVC 2005/8
|
||||
#define sprintf _snwprintf
|
||||
#else
|
||||
// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently,
|
||||
// it takes the same argument list as sprintf.
|
||||
//#define sprintf swprintf_s
|
||||
#endif // MSC_VER < 1400
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
using std::string;
|
||||
|
||||
class WindowsStringUtils {
|
||||
public:
|
||||
// Roughly equivalent to MSVC8's strcpy_s, except pre-MSVC8, this does
|
||||
// not fail if source is longer than destination_size. The destination
|
||||
// buffer is always 0-terminated.
|
||||
static void safe_wcscpy(TCHAR *destination, size_t destination_size,
|
||||
const TCHAR *source);
|
||||
|
||||
// Roughly equivalent to MSVC8's strncpy_s, except that _TRUNCATE cannot
|
||||
// be passed directly, and pre-MSVC8, this will not fail if source or count
|
||||
// are longer than destination_size. The destination buffer is always
|
||||
// 0-terminated.
|
||||
static void safe_wcsncpy(TCHAR *destination, size_t destination_size,
|
||||
const TCHAR *source, size_t count);
|
||||
|
||||
// Performs multi-byte to wide character conversion on C++ strings, using
|
||||
// mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8). Returns false on failure,
|
||||
// without setting wcs.
|
||||
static bool safe_mbstowcs(const string &mbs, string *wcs);
|
||||
|
||||
// The inverse of safe_mbstowcs.
|
||||
static bool safe_wcstombs(const string &wcs, string *mbs);
|
||||
|
||||
// Returns the base name of a file, e.g. strips off the path.
|
||||
static string GetBaseName(const string &filename);
|
||||
|
||||
private:
|
||||
// Disallow instantiation and other object-based operations.
|
||||
WindowsStringUtils();
|
||||
WindowsStringUtils(const WindowsStringUtils&);
|
||||
~WindowsStringUtils();
|
||||
void operator=(const WindowsStringUtils&);
|
||||
};
|
||||
|
||||
// static
|
||||
inline void WindowsStringUtils::safe_wcscpy(TCHAR *destination,
|
||||
size_t destination_size,
|
||||
const TCHAR *source) {
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
_tcscpy_s(destination, destination_size, source);
|
||||
#else // _MSC_VER >= 1400
|
||||
// Pre-MSVC 2005/8 doesn't have strcpy_s. Simulate it with wcsncpy.
|
||||
// wcsncpy doesn't 0-terminate the destination buffer if the source string
|
||||
// is longer than size. Ensure that the destination is 0-terminated.
|
||||
wcsncpy(destination, source, destination_size);
|
||||
if (destination && destination_size)
|
||||
destination[destination_size - 1] = 0;
|
||||
#endif // _MSC_VER >= 1400
|
||||
}
|
||||
|
||||
// static
|
||||
inline void WindowsStringUtils::safe_wcsncpy(TCHAR *destination,
|
||||
size_t destination_size,
|
||||
const TCHAR *source,
|
||||
size_t count) {
|
||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
||||
_tcsncpy_s(destination, destination_size, source, count);
|
||||
#else // _MSC_VER >= 1400
|
||||
// Pre-MSVC 2005/8 doesn't have strncpy_s. Simulate it with wcsncpy.
|
||||
// wcsncpy doesn't 0-terminate the destination buffer if the source string
|
||||
// is longer than size. Ensure that the destination is 0-terminated.
|
||||
if (destination_size < count)
|
||||
count = destination_size;
|
||||
|
||||
wcsncpy(destination, source, count);
|
||||
if (destination && count)
|
||||
destination[count - 1] = 0;
|
||||
#endif // _MSC_VER >= 1400
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_WINDOWS_STRING_UTILS_INL_H__
|
||||
@@ -0,0 +1,52 @@
|
||||
#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__
|
||||
Binary file not shown.
Reference in new issue
Block a user