mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-07-10 15:37:34 +00:00
Fix some newlines.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@838 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
1f17be3171
commit
494fa83886
|
@ -1,61 +1,61 @@
|
||||||
# Copyright (c) 2010, Google Inc.
|
# Copyright (c) 2010, Google Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
# modification, are permitted provided that the following conditions are
|
# modification, are permitted provided that the following conditions are
|
||||||
# met:
|
# met:
|
||||||
#
|
#
|
||||||
# * Redistributions of source code must retain the above copyright
|
# * Redistributions of source code must retain the above copyright
|
||||||
# notice, this list of conditions and the following disclaimer.
|
# notice, this list of conditions and the following disclaimer.
|
||||||
# * Redistributions in binary form must reproduce the above
|
# * Redistributions in binary form must reproduce the above
|
||||||
# copyright notice, this list of conditions and the following disclaimer
|
# copyright notice, this list of conditions and the following disclaimer
|
||||||
# in the documentation and/or other materials provided with the
|
# in the documentation and/or other materials provided with the
|
||||||
# distribution.
|
# distribution.
|
||||||
# * Neither the name of Google Inc. nor the names of its
|
# * Neither the name of Google Inc. nor the names of its
|
||||||
# contributors may be used to endorse or promote products derived from
|
# contributors may be used to endorse or promote products derived from
|
||||||
# this software without specific prior written permission.
|
# this software without specific prior written permission.
|
||||||
#
|
#
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
{
|
{
|
||||||
'includes': [
|
'includes': [
|
||||||
'../../build/common.gypi',
|
'../../build/common.gypi',
|
||||||
],
|
],
|
||||||
'targets': [
|
'targets': [
|
||||||
{
|
{
|
||||||
'target_name': 'crash_generation_app',
|
'target_name': 'crash_generation_app',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'sources': [
|
'sources': [
|
||||||
'abstract_class.cc',
|
'abstract_class.cc',
|
||||||
'abstract_class.h',
|
'abstract_class.h',
|
||||||
'crash_generation_app.cc',
|
'crash_generation_app.cc',
|
||||||
'crash_generation_app.h',
|
'crash_generation_app.h',
|
||||||
'crash_generation_app.ico',
|
'crash_generation_app.ico',
|
||||||
'crash_generation_app.rc',
|
'crash_generation_app.rc',
|
||||||
'resource.h',
|
'resource.h',
|
||||||
'small.ico',
|
'small.ico',
|
||||||
],
|
],
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'../../breakpad_client.gyp:common',
|
'../../breakpad_client.gyp:common',
|
||||||
'../../crash_generation/crash_generation.gyp:crash_generation_server',
|
'../../crash_generation/crash_generation.gyp:crash_generation_server',
|
||||||
'../../crash_generation/crash_generation.gyp:crash_generation_client',
|
'../../crash_generation/crash_generation.gyp:crash_generation_client',
|
||||||
'../../handler/exception_handler.gyp:exception_handler',
|
'../../handler/exception_handler.gyp:exception_handler',
|
||||||
],
|
],
|
||||||
'msvs_settings': {
|
'msvs_settings': {
|
||||||
'VCLinkerTool': {
|
'VCLinkerTool': {
|
||||||
'SubSystem': '2', # Windows Subsystem as opposed to a console app
|
'SubSystem': '2', # Windows Subsystem as opposed to a console app
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,298 +1,298 @@
|
||||||
// Copyright 2010, Google Inc.
|
// Copyright 2010, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright
|
// * Redistributions of source code must retain the above copyright
|
||||||
// notice, this list of conditions and the following disclaimer.
|
// notice, this list of conditions and the following disclaimer.
|
||||||
// * Redistributions in binary form must reproduce the above
|
// * Redistributions in binary form must reproduce the above
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
// in the documentation and/or other materials provided with the
|
// in the documentation and/or other materials provided with the
|
||||||
// distribution.
|
// distribution.
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
||||||
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
||||||
//
|
//
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
#include "testing/include/gmock/gmock.h"
|
#include "testing/include/gmock/gmock.h"
|
||||||
|
|
||||||
#include "client/windows/crash_generation/crash_generation_server.h"
|
#include "client/windows/crash_generation/crash_generation_server.h"
|
||||||
#include "client/windows/common/ipc_protocol.h"
|
#include "client/windows/common/ipc_protocol.h"
|
||||||
|
|
||||||
using testing::_;
|
using testing::_;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const wchar_t kPipeName[] =
|
const wchar_t kPipeName[] =
|
||||||
L"\\\\.\\pipe\\CrashGenerationServerTest\\TestCaseServer";
|
L"\\\\.\\pipe\\CrashGenerationServerTest\\TestCaseServer";
|
||||||
|
|
||||||
const DWORD kPipeDesiredAccess = FILE_READ_DATA |
|
const DWORD kPipeDesiredAccess = FILE_READ_DATA |
|
||||||
FILE_WRITE_DATA |
|
FILE_WRITE_DATA |
|
||||||
FILE_WRITE_ATTRIBUTES;
|
FILE_WRITE_ATTRIBUTES;
|
||||||
|
|
||||||
const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
|
const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
|
||||||
SECURITY_SQOS_PRESENT;
|
SECURITY_SQOS_PRESENT;
|
||||||
|
|
||||||
const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
|
const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
|
||||||
|
|
||||||
int kCustomInfoCount = 2;
|
int kCustomInfoCount = 2;
|
||||||
|
|
||||||
google_breakpad::CustomInfoEntry kCustomInfoEntries[] = {
|
google_breakpad::CustomInfoEntry kCustomInfoEntries[] = {
|
||||||
google_breakpad::CustomInfoEntry(L"prod", L"CrashGenerationServerTest"),
|
google_breakpad::CustomInfoEntry(L"prod", L"CrashGenerationServerTest"),
|
||||||
google_breakpad::CustomInfoEntry(L"ver", L"1.0"),
|
google_breakpad::CustomInfoEntry(L"ver", L"1.0"),
|
||||||
};
|
};
|
||||||
|
|
||||||
class CrashGenerationServerTest : public ::testing::Test {
|
class CrashGenerationServerTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
CrashGenerationServerTest()
|
CrashGenerationServerTest()
|
||||||
: crash_generation_server_(kPipeName,
|
: crash_generation_server_(kPipeName,
|
||||||
NULL,
|
NULL,
|
||||||
CallOnClientConnected, &mock_callbacks_,
|
CallOnClientConnected, &mock_callbacks_,
|
||||||
CallOnClientDumpRequested, &mock_callbacks_,
|
CallOnClientDumpRequested, &mock_callbacks_,
|
||||||
CallOnClientExited, &mock_callbacks_,
|
CallOnClientExited, &mock_callbacks_,
|
||||||
false,
|
false,
|
||||||
NULL),
|
NULL),
|
||||||
thread_id_(0),
|
thread_id_(0),
|
||||||
exception_pointers_(NULL) {
|
exception_pointers_(NULL) {
|
||||||
memset(&assert_info_, 0, sizeof(assert_info_));
|
memset(&assert_info_, 0, sizeof(assert_info_));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class MockCrashGenerationServerCallbacks {
|
class MockCrashGenerationServerCallbacks {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD1(OnClientConnected,
|
MOCK_METHOD1(OnClientConnected,
|
||||||
void(const google_breakpad::ClientInfo* client_info));
|
void(const google_breakpad::ClientInfo* client_info));
|
||||||
MOCK_METHOD2(OnClientDumpRequested,
|
MOCK_METHOD2(OnClientDumpRequested,
|
||||||
void(const google_breakpad::ClientInfo* client_info,
|
void(const google_breakpad::ClientInfo* client_info,
|
||||||
const std::wstring* file_path));
|
const std::wstring* file_path));
|
||||||
MOCK_METHOD1(OnClientExited,
|
MOCK_METHOD1(OnClientExited,
|
||||||
void(const google_breakpad::ClientInfo* client_info));
|
void(const google_breakpad::ClientInfo* client_info));
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ClientFault {
|
enum ClientFault {
|
||||||
NO_FAULT,
|
NO_FAULT,
|
||||||
CLOSE_AFTER_CONNECT,
|
CLOSE_AFTER_CONNECT,
|
||||||
SEND_INVALID_REGISTRATION,
|
SEND_INVALID_REGISTRATION,
|
||||||
TRUNCATE_REGISTRATION,
|
TRUNCATE_REGISTRATION,
|
||||||
CLOSE_AFTER_REGISTRATION,
|
CLOSE_AFTER_REGISTRATION,
|
||||||
RESPONSE_BUFFER_TOO_SMALL,
|
RESPONSE_BUFFER_TOO_SMALL,
|
||||||
CLOSE_AFTER_RESPONSE,
|
CLOSE_AFTER_RESPONSE,
|
||||||
SEND_INVALID_ACK
|
SEND_INVALID_ACK
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetUp() {
|
void SetUp() {
|
||||||
ASSERT_TRUE(crash_generation_server_.Start());
|
ASSERT_TRUE(crash_generation_server_.Start());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FaultyClient(ClientFault fault_type) {
|
void FaultyClient(ClientFault fault_type) {
|
||||||
HANDLE pipe = CreateFile(kPipeName,
|
HANDLE pipe = CreateFile(kPipeName,
|
||||||
kPipeDesiredAccess,
|
kPipeDesiredAccess,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
kPipeFlagsAndAttributes,
|
kPipeFlagsAndAttributes,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (pipe == INVALID_HANDLE_VALUE) {
|
if (pipe == INVALID_HANDLE_VALUE) {
|
||||||
ASSERT_EQ(ERROR_PIPE_BUSY, GetLastError());
|
ASSERT_EQ(ERROR_PIPE_BUSY, GetLastError());
|
||||||
|
|
||||||
// Cannot continue retrying if wait on pipe fails.
|
// Cannot continue retrying if wait on pipe fails.
|
||||||
ASSERT_TRUE(WaitNamedPipe(kPipeName, 500));
|
ASSERT_TRUE(WaitNamedPipe(kPipeName, 500));
|
||||||
|
|
||||||
pipe = CreateFile(kPipeName,
|
pipe = CreateFile(kPipeName,
|
||||||
kPipeDesiredAccess,
|
kPipeDesiredAccess,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
kPipeFlagsAndAttributes,
|
kPipeFlagsAndAttributes,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_NE(pipe, INVALID_HANDLE_VALUE);
|
ASSERT_NE(pipe, INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
DWORD mode = kPipeMode;
|
DWORD mode = kPipeMode;
|
||||||
ASSERT_TRUE(SetNamedPipeHandleState(pipe, &mode, NULL, NULL));
|
ASSERT_TRUE(SetNamedPipeHandleState(pipe, &mode, NULL, NULL));
|
||||||
|
|
||||||
DoFaultyClient(fault_type, pipe);
|
DoFaultyClient(fault_type, pipe);
|
||||||
|
|
||||||
CloseHandle(pipe);
|
CloseHandle(pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoTestFault(ClientFault fault) {
|
void DoTestFault(ClientFault fault) {
|
||||||
EXPECT_CALL(mock_callbacks_, OnClientConnected(_)).Times(0);
|
EXPECT_CALL(mock_callbacks_, OnClientConnected(_)).Times(0);
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(fault));
|
||||||
|
|
||||||
EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
|
EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
|
||||||
|
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
|
||||||
|
|
||||||
// Slight hack. The OnClientConnected is only invoked after the ack is
|
// Slight hack. The OnClientConnected is only invoked after the ack is
|
||||||
// received by the server. At that point, the FaultyClient call has already
|
// received by the server. At that point, the FaultyClient call has already
|
||||||
// returned. The best way to wait until the server is done handling that is
|
// returned. The best way to wait until the server is done handling that is
|
||||||
// to send one more ping, whose processing will be blocked by delivery of
|
// to send one more ping, whose processing will be blocked by delivery of
|
||||||
// the OnClientConnected message.
|
// the OnClientConnected message.
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
MockCrashGenerationServerCallbacks mock_callbacks_;
|
MockCrashGenerationServerCallbacks mock_callbacks_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Depends on the caller to successfully open the pipe before invocation and
|
// Depends on the caller to successfully open the pipe before invocation and
|
||||||
// to close it immediately afterwards.
|
// to close it immediately afterwards.
|
||||||
void DoFaultyClient(ClientFault fault_type, HANDLE pipe) {
|
void DoFaultyClient(ClientFault fault_type, HANDLE pipe) {
|
||||||
if (fault_type == CLOSE_AFTER_CONNECT) {
|
if (fault_type == CLOSE_AFTER_CONNECT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries,
|
google_breakpad::CustomClientInfo custom_info = {kCustomInfoEntries,
|
||||||
kCustomInfoCount};
|
kCustomInfoCount};
|
||||||
|
|
||||||
google_breakpad::ProtocolMessage msg(
|
google_breakpad::ProtocolMessage msg(
|
||||||
fault_type == SEND_INVALID_REGISTRATION ?
|
fault_type == SEND_INVALID_REGISTRATION ?
|
||||||
google_breakpad::MESSAGE_TAG_NONE :
|
google_breakpad::MESSAGE_TAG_NONE :
|
||||||
google_breakpad::MESSAGE_TAG_REGISTRATION_REQUEST,
|
google_breakpad::MESSAGE_TAG_REGISTRATION_REQUEST,
|
||||||
GetCurrentProcessId(),
|
GetCurrentProcessId(),
|
||||||
MiniDumpNormal,
|
MiniDumpNormal,
|
||||||
&thread_id_,
|
&thread_id_,
|
||||||
&exception_pointers_,
|
&exception_pointers_,
|
||||||
&assert_info_,
|
&assert_info_,
|
||||||
custom_info,
|
custom_info,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
DWORD bytes_count = 0;
|
DWORD bytes_count = 0;
|
||||||
|
|
||||||
ASSERT_TRUE(WriteFile(pipe,
|
ASSERT_TRUE(WriteFile(pipe,
|
||||||
&msg,
|
&msg,
|
||||||
fault_type == TRUNCATE_REGISTRATION ?
|
fault_type == TRUNCATE_REGISTRATION ?
|
||||||
sizeof(msg) / 2 : sizeof(msg),
|
sizeof(msg) / 2 : sizeof(msg),
|
||||||
&bytes_count,
|
&bytes_count,
|
||||||
NULL));
|
NULL));
|
||||||
|
|
||||||
if (fault_type == CLOSE_AFTER_REGISTRATION) {
|
if (fault_type == CLOSE_AFTER_REGISTRATION) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
google_breakpad::ProtocolMessage reply;
|
google_breakpad::ProtocolMessage reply;
|
||||||
|
|
||||||
if (!ReadFile(pipe,
|
if (!ReadFile(pipe,
|
||||||
&reply,
|
&reply,
|
||||||
fault_type == RESPONSE_BUFFER_TOO_SMALL ?
|
fault_type == RESPONSE_BUFFER_TOO_SMALL ?
|
||||||
sizeof(google_breakpad::ProtocolMessage) / 2 :
|
sizeof(google_breakpad::ProtocolMessage) / 2 :
|
||||||
sizeof(google_breakpad::ProtocolMessage),
|
sizeof(google_breakpad::ProtocolMessage),
|
||||||
&bytes_count,
|
&bytes_count,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
switch (fault_type) {
|
switch (fault_type) {
|
||||||
case TRUNCATE_REGISTRATION:
|
case TRUNCATE_REGISTRATION:
|
||||||
case RESPONSE_BUFFER_TOO_SMALL:
|
case RESPONSE_BUFFER_TOO_SMALL:
|
||||||
case SEND_INVALID_REGISTRATION:
|
case SEND_INVALID_REGISTRATION:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
FAIL() << "Unexpectedly failed to register.";
|
FAIL() << "Unexpectedly failed to register.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fault_type == CLOSE_AFTER_RESPONSE) {
|
if (fault_type == CLOSE_AFTER_RESPONSE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
google_breakpad::ProtocolMessage ack_msg;
|
google_breakpad::ProtocolMessage ack_msg;
|
||||||
ack_msg.tag = google_breakpad::MESSAGE_TAG_REGISTRATION_ACK;
|
ack_msg.tag = google_breakpad::MESSAGE_TAG_REGISTRATION_ACK;
|
||||||
|
|
||||||
ASSERT_TRUE(WriteFile(pipe,
|
ASSERT_TRUE(WriteFile(pipe,
|
||||||
&ack_msg,
|
&ack_msg,
|
||||||
SEND_INVALID_ACK ?
|
SEND_INVALID_ACK ?
|
||||||
sizeof(ack_msg) : sizeof(ack_msg) / 2,
|
sizeof(ack_msg) : sizeof(ack_msg) / 2,
|
||||||
&bytes_count,
|
&bytes_count,
|
||||||
NULL));
|
NULL));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CallOnClientConnected(
|
static void CallOnClientConnected(
|
||||||
void* context, const google_breakpad::ClientInfo* client_info) {
|
void* context, const google_breakpad::ClientInfo* client_info) {
|
||||||
static_cast<MockCrashGenerationServerCallbacks*>(context)->
|
static_cast<MockCrashGenerationServerCallbacks*>(context)->
|
||||||
OnClientConnected(client_info);
|
OnClientConnected(client_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CallOnClientDumpRequested(
|
static void CallOnClientDumpRequested(
|
||||||
void* context,
|
void* context,
|
||||||
const google_breakpad::ClientInfo* client_info,
|
const google_breakpad::ClientInfo* client_info,
|
||||||
const std::wstring* file_path) {
|
const std::wstring* file_path) {
|
||||||
static_cast<MockCrashGenerationServerCallbacks*>(context)->
|
static_cast<MockCrashGenerationServerCallbacks*>(context)->
|
||||||
OnClientDumpRequested(client_info, file_path);
|
OnClientDumpRequested(client_info, file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CallOnClientExited(
|
static void CallOnClientExited(
|
||||||
void* context, const google_breakpad::ClientInfo* client_info) {
|
void* context, const google_breakpad::ClientInfo* client_info) {
|
||||||
static_cast<MockCrashGenerationServerCallbacks*>(context)->
|
static_cast<MockCrashGenerationServerCallbacks*>(context)->
|
||||||
OnClientExited(client_info);
|
OnClientExited(client_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD thread_id_;
|
DWORD thread_id_;
|
||||||
EXCEPTION_POINTERS* exception_pointers_;
|
EXCEPTION_POINTERS* exception_pointers_;
|
||||||
MDRawAssertionInfo assert_info_;
|
MDRawAssertionInfo assert_info_;
|
||||||
|
|
||||||
google_breakpad::CrashGenerationServer crash_generation_server_;
|
google_breakpad::CrashGenerationServer crash_generation_server_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(CrashGenerationServerTest, PingServerTest) {
|
TEST_F(CrashGenerationServerTest, PingServerTest) {
|
||||||
DoTestFault(CLOSE_AFTER_CONNECT);
|
DoTestFault(CLOSE_AFTER_CONNECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CrashGenerationServerTest, InvalidRegistration) {
|
TEST_F(CrashGenerationServerTest, InvalidRegistration) {
|
||||||
DoTestFault(SEND_INVALID_REGISTRATION);
|
DoTestFault(SEND_INVALID_REGISTRATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CrashGenerationServerTest, TruncateRegistration) {
|
TEST_F(CrashGenerationServerTest, TruncateRegistration) {
|
||||||
DoTestFault(TRUNCATE_REGISTRATION);
|
DoTestFault(TRUNCATE_REGISTRATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CrashGenerationServerTest, CloseAfterRegistration) {
|
TEST_F(CrashGenerationServerTest, CloseAfterRegistration) {
|
||||||
DoTestFault(CLOSE_AFTER_REGISTRATION);
|
DoTestFault(CLOSE_AFTER_REGISTRATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CrashGenerationServerTest, ResponseBufferTooSmall) {
|
TEST_F(CrashGenerationServerTest, ResponseBufferTooSmall) {
|
||||||
DoTestFault(RESPONSE_BUFFER_TOO_SMALL);
|
DoTestFault(RESPONSE_BUFFER_TOO_SMALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CrashGenerationServerTest, CloseAfterResponse) {
|
TEST_F(CrashGenerationServerTest, CloseAfterResponse) {
|
||||||
DoTestFault(CLOSE_AFTER_RESPONSE);
|
DoTestFault(CLOSE_AFTER_RESPONSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It turns out that, as long as you send one byte, the ACK is accepted and
|
// It turns out that, as long as you send one byte, the ACK is accepted and
|
||||||
// registration succeeds.
|
// registration succeeds.
|
||||||
TEST_F(CrashGenerationServerTest, SendInvalidAck) {
|
TEST_F(CrashGenerationServerTest, SendInvalidAck) {
|
||||||
EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
|
EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(SEND_INVALID_ACK));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(SEND_INVALID_ACK));
|
||||||
|
|
||||||
// See DoTestFault for an explanation of this line
|
// See DoTestFault for an explanation of this line
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
|
||||||
|
|
||||||
EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
|
EXPECT_CALL(mock_callbacks_, OnClientConnected(_));
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(NO_FAULT));
|
||||||
|
|
||||||
// See DoTestFault for an explanation of this line
|
// See DoTestFault for an explanation of this line
|
||||||
ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
|
ASSERT_NO_FATAL_FAILURE(FaultyClient(CLOSE_AFTER_CONNECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -1,184 +1,184 @@
|
||||||
// Copyright (c) 2010, Google Inc.
|
// Copyright (c) 2010, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright
|
// * Redistributions of source code must retain the above copyright
|
||||||
// notice, this list of conditions and the following disclaimer.
|
// notice, this list of conditions and the following disclaimer.
|
||||||
// * Redistributions in binary form must reproduce the above
|
// * Redistributions in binary form must reproduce the above
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
// in the documentation and/or other materials provided with the
|
// in the documentation and/or other materials provided with the
|
||||||
// distribution.
|
// distribution.
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
||||||
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
||||||
//
|
//
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
|
|
||||||
#include "dump_analysis.h" // NOLINT
|
#include "dump_analysis.h" // NOLINT
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
DumpAnalysis::~DumpAnalysis() {
|
DumpAnalysis::~DumpAnalysis() {
|
||||||
if (dump_file_view_ != NULL) {
|
if (dump_file_view_ != NULL) {
|
||||||
EXPECT_TRUE(::UnmapViewOfFile(dump_file_view_));
|
EXPECT_TRUE(::UnmapViewOfFile(dump_file_view_));
|
||||||
::CloseHandle(dump_file_mapping_);
|
::CloseHandle(dump_file_mapping_);
|
||||||
dump_file_mapping_ = NULL;
|
dump_file_mapping_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dump_file_handle_ != NULL) {
|
if (dump_file_handle_ != NULL) {
|
||||||
::CloseHandle(dump_file_handle_);
|
::CloseHandle(dump_file_handle_);
|
||||||
dump_file_handle_ = NULL;
|
dump_file_handle_ = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DumpAnalysis::EnsureDumpMapped() {
|
void DumpAnalysis::EnsureDumpMapped() {
|
||||||
if (dump_file_view_ == NULL) {
|
if (dump_file_view_ == NULL) {
|
||||||
dump_file_handle_ = ::CreateFile(dump_file_.c_str(),
|
dump_file_handle_ = ::CreateFile(dump_file_.c_str(),
|
||||||
GENERIC_READ,
|
GENERIC_READ,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
OPEN_EXISTING,
|
OPEN_EXISTING,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
ASSERT_TRUE(dump_file_handle_ != NULL);
|
ASSERT_TRUE(dump_file_handle_ != NULL);
|
||||||
ASSERT_TRUE(dump_file_mapping_ == NULL);
|
ASSERT_TRUE(dump_file_mapping_ == NULL);
|
||||||
|
|
||||||
dump_file_mapping_ = ::CreateFileMapping(dump_file_handle_,
|
dump_file_mapping_ = ::CreateFileMapping(dump_file_handle_,
|
||||||
NULL,
|
NULL,
|
||||||
PAGE_READONLY,
|
PAGE_READONLY,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
ASSERT_TRUE(dump_file_mapping_ != NULL);
|
ASSERT_TRUE(dump_file_mapping_ != NULL);
|
||||||
|
|
||||||
dump_file_view_ = ::MapViewOfFile(dump_file_mapping_,
|
dump_file_view_ = ::MapViewOfFile(dump_file_mapping_,
|
||||||
FILE_MAP_READ,
|
FILE_MAP_READ,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
ASSERT_TRUE(dump_file_view_ != NULL);
|
ASSERT_TRUE(dump_file_view_ != NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpAnalysis::HasTebs() const {
|
bool DumpAnalysis::HasTebs() const {
|
||||||
MINIDUMP_THREAD_LIST* thread_list = NULL;
|
MINIDUMP_THREAD_LIST* thread_list = NULL;
|
||||||
size_t thread_list_size = GetStream(ThreadListStream, &thread_list);
|
size_t thread_list_size = GetStream(ThreadListStream, &thread_list);
|
||||||
|
|
||||||
if (thread_list_size > 0 && thread_list != NULL) {
|
if (thread_list_size > 0 && thread_list != NULL) {
|
||||||
for (ULONG i = 0; i < thread_list->NumberOfThreads; ++i) {
|
for (ULONG i = 0; i < thread_list->NumberOfThreads; ++i) {
|
||||||
if (!HasMemory(thread_list->Threads[i].Teb))
|
if (!HasMemory(thread_list->Threads[i].Teb))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No thread list, no TEB info.
|
// No thread list, no TEB info.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpAnalysis::HasPeb() const {
|
bool DumpAnalysis::HasPeb() const {
|
||||||
MINIDUMP_THREAD_LIST* thread_list = NULL;
|
MINIDUMP_THREAD_LIST* thread_list = NULL;
|
||||||
size_t thread_list_size = GetStream(ThreadListStream, &thread_list);
|
size_t thread_list_size = GetStream(ThreadListStream, &thread_list);
|
||||||
|
|
||||||
if (thread_list_size > 0 && thread_list != NULL &&
|
if (thread_list_size > 0 && thread_list != NULL &&
|
||||||
thread_list->NumberOfThreads > 0) {
|
thread_list->NumberOfThreads > 0) {
|
||||||
FakeTEB* teb = NULL;
|
FakeTEB* teb = NULL;
|
||||||
if (!HasMemory(thread_list->Threads[0].Teb, &teb))
|
if (!HasMemory(thread_list->Threads[0].Teb, &teb))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return HasMemory(teb->peb);
|
return HasMemory(teb->peb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpAnalysis::HasStream(ULONG stream_number) const {
|
bool DumpAnalysis::HasStream(ULONG stream_number) const {
|
||||||
void* stream = NULL;
|
void* stream = NULL;
|
||||||
size_t stream_size = GetStreamImpl(stream_number, &stream);
|
size_t stream_size = GetStreamImpl(stream_number, &stream);
|
||||||
return stream_size > 0 && stream != NULL;
|
return stream_size > 0 && stream != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const {
|
size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const {
|
||||||
MINIDUMP_DIRECTORY* directory = NULL;
|
MINIDUMP_DIRECTORY* directory = NULL;
|
||||||
ULONG memory_list_size = 0;
|
ULONG memory_list_size = 0;
|
||||||
BOOL ret = ::MiniDumpReadDumpStream(dump_file_view_,
|
BOOL ret = ::MiniDumpReadDumpStream(dump_file_view_,
|
||||||
stream_number,
|
stream_number,
|
||||||
&directory,
|
&directory,
|
||||||
stream,
|
stream,
|
||||||
&memory_list_size);
|
&memory_list_size);
|
||||||
|
|
||||||
return ret ? memory_list_size : 0;
|
return ret ? memory_list_size : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpAnalysis::HasMemoryImpl(const void *addr_in, size_t structuresize,
|
bool DumpAnalysis::HasMemoryImpl(const void *addr_in, size_t structuresize,
|
||||||
void **structure) const {
|
void **structure) const {
|
||||||
uintptr_t address = reinterpret_cast<uintptr_t>(addr_in);
|
uintptr_t address = reinterpret_cast<uintptr_t>(addr_in);
|
||||||
MINIDUMP_MEMORY_LIST* memory_list = NULL;
|
MINIDUMP_MEMORY_LIST* memory_list = NULL;
|
||||||
size_t memory_list_size = GetStream(MemoryListStream, &memory_list);
|
size_t memory_list_size = GetStream(MemoryListStream, &memory_list);
|
||||||
if (memory_list_size > 0 && memory_list != NULL) {
|
if (memory_list_size > 0 && memory_list != NULL) {
|
||||||
for (ULONG i = 0; i < memory_list->NumberOfMemoryRanges; ++i) {
|
for (ULONG i = 0; i < memory_list->NumberOfMemoryRanges; ++i) {
|
||||||
MINIDUMP_MEMORY_DESCRIPTOR& descr = memory_list->MemoryRanges[i];
|
MINIDUMP_MEMORY_DESCRIPTOR& descr = memory_list->MemoryRanges[i];
|
||||||
const uintptr_t range_start =
|
const uintptr_t range_start =
|
||||||
static_cast<uintptr_t>(descr.StartOfMemoryRange);
|
static_cast<uintptr_t>(descr.StartOfMemoryRange);
|
||||||
uintptr_t range_end = range_start + descr.Memory.DataSize;
|
uintptr_t range_end = range_start + descr.Memory.DataSize;
|
||||||
|
|
||||||
if (address >= range_start &&
|
if (address >= range_start &&
|
||||||
address + structuresize < range_end) {
|
address + structuresize < range_end) {
|
||||||
// The start address falls in the range, and the end address is
|
// The start address falls in the range, and the end address is
|
||||||
// in bounds, return a pointer to the structure if requested.
|
// in bounds, return a pointer to the structure if requested.
|
||||||
if (structure != NULL)
|
if (structure != NULL)
|
||||||
*structure = RVA_TO_ADDR(dump_file_view_, descr.Memory.Rva);
|
*structure = RVA_TO_ADDR(dump_file_view_, descr.Memory.Rva);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We didn't find the range in a MINIDUMP_MEMORY_LIST, so maybe this
|
// We didn't find the range in a MINIDUMP_MEMORY_LIST, so maybe this
|
||||||
// is a full dump using MINIDUMP_MEMORY64_LIST with all the memory at the
|
// is a full dump using MINIDUMP_MEMORY64_LIST with all the memory at the
|
||||||
// end of the dump file.
|
// end of the dump file.
|
||||||
MINIDUMP_MEMORY64_LIST* memory64_list = NULL;
|
MINIDUMP_MEMORY64_LIST* memory64_list = NULL;
|
||||||
memory_list_size = GetStream(Memory64ListStream, &memory64_list);
|
memory_list_size = GetStream(Memory64ListStream, &memory64_list);
|
||||||
if (memory_list_size > 0 && memory64_list != NULL) {
|
if (memory_list_size > 0 && memory64_list != NULL) {
|
||||||
// Keep track of where the current descriptor maps to.
|
// Keep track of where the current descriptor maps to.
|
||||||
RVA64 curr_rva = memory64_list->BaseRva;
|
RVA64 curr_rva = memory64_list->BaseRva;
|
||||||
for (ULONG i = 0; i < memory64_list->NumberOfMemoryRanges; ++i) {
|
for (ULONG i = 0; i < memory64_list->NumberOfMemoryRanges; ++i) {
|
||||||
MINIDUMP_MEMORY_DESCRIPTOR64& descr = memory64_list->MemoryRanges[i];
|
MINIDUMP_MEMORY_DESCRIPTOR64& descr = memory64_list->MemoryRanges[i];
|
||||||
uintptr_t range_start =
|
uintptr_t range_start =
|
||||||
static_cast<uintptr_t>(descr.StartOfMemoryRange);
|
static_cast<uintptr_t>(descr.StartOfMemoryRange);
|
||||||
uintptr_t range_end = range_start + static_cast<size_t>(descr.DataSize);
|
uintptr_t range_end = range_start + static_cast<size_t>(descr.DataSize);
|
||||||
|
|
||||||
if (address >= range_start &&
|
if (address >= range_start &&
|
||||||
address + structuresize < range_end) {
|
address + structuresize < range_end) {
|
||||||
// The start address falls in the range, and the end address is
|
// The start address falls in the range, and the end address is
|
||||||
// in bounds, return a pointer to the structure if requested.
|
// in bounds, return a pointer to the structure if requested.
|
||||||
if (structure != NULL)
|
if (structure != NULL)
|
||||||
*structure = RVA_TO_ADDR(dump_file_view_, curr_rva);
|
*structure = RVA_TO_ADDR(dump_file_view_, curr_rva);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance the current RVA.
|
// Advance the current RVA.
|
||||||
curr_rva += descr.DataSize;
|
curr_rva += descr.DataSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,102 +1,102 @@
|
||||||
// Copyright (c) 2010, Google Inc.
|
// Copyright (c) 2010, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright
|
// * Redistributions of source code must retain the above copyright
|
||||||
// notice, this list of conditions and the following disclaimer.
|
// notice, this list of conditions and the following disclaimer.
|
||||||
// * Redistributions in binary form must reproduce the above
|
// * Redistributions in binary form must reproduce the above
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
// in the documentation and/or other materials provided with the
|
// in the documentation and/or other materials provided with the
|
||||||
// distribution.
|
// distribution.
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
||||||
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
||||||
//
|
//
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#ifndef CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
#ifndef CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
||||||
#define CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
#define CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
||||||
|
|
||||||
#include "../crash_generation/minidump_generator.h"
|
#include "../crash_generation/minidump_generator.h"
|
||||||
|
|
||||||
// Convenience to get to the PEB pointer in a TEB.
|
// Convenience to get to the PEB pointer in a TEB.
|
||||||
struct FakeTEB {
|
struct FakeTEB {
|
||||||
char dummy[0x30];
|
char dummy[0x30];
|
||||||
void* peb;
|
void* peb;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DumpAnalysis {
|
class DumpAnalysis {
|
||||||
public:
|
public:
|
||||||
explicit DumpAnalysis(const std::wstring& file_path)
|
explicit DumpAnalysis(const std::wstring& file_path)
|
||||||
: dump_file_(file_path), dump_file_view_(NULL), dump_file_mapping_(NULL),
|
: dump_file_(file_path), dump_file_view_(NULL), dump_file_mapping_(NULL),
|
||||||
dump_file_handle_(NULL) {
|
dump_file_handle_(NULL) {
|
||||||
EnsureDumpMapped();
|
EnsureDumpMapped();
|
||||||
}
|
}
|
||||||
~DumpAnalysis();
|
~DumpAnalysis();
|
||||||
|
|
||||||
bool HasStream(ULONG stream_number) const;
|
bool HasStream(ULONG stream_number) const;
|
||||||
|
|
||||||
// This is template to keep type safety in the front, but we end up casting
|
// This is template to keep type safety in the front, but we end up casting
|
||||||
// to void** inside the implementation to pass the pointer to Win32. So
|
// to void** inside the implementation to pass the pointer to Win32. So
|
||||||
// casting here is considered safe.
|
// casting here is considered safe.
|
||||||
template <class StreamType>
|
template <class StreamType>
|
||||||
size_t GetStream(ULONG stream_number, StreamType** stream) const {
|
size_t GetStream(ULONG stream_number, StreamType** stream) const {
|
||||||
return GetStreamImpl(stream_number, reinterpret_cast<void**>(stream));
|
return GetStreamImpl(stream_number, reinterpret_cast<void**>(stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasTebs() const;
|
bool HasTebs() const;
|
||||||
bool HasPeb() const;
|
bool HasPeb() const;
|
||||||
bool HasMemory(ULONG64 address) const {
|
bool HasMemory(ULONG64 address) const {
|
||||||
return HasMemory<BYTE>(address, NULL);
|
return HasMemory<BYTE>(address, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasMemory(const void* address) const {
|
bool HasMemory(const void* address) const {
|
||||||
return HasMemory<BYTE>(address, NULL);
|
return HasMemory<BYTE>(address, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class StructureType>
|
template <class StructureType>
|
||||||
bool HasMemory(ULONG64 address, StructureType** structure = NULL) const {
|
bool HasMemory(ULONG64 address, StructureType** structure = NULL) const {
|
||||||
// We can't cope with 64 bit addresses for now.
|
// We can't cope with 64 bit addresses for now.
|
||||||
if (address > 0xFFFFFFFFUL)
|
if (address > 0xFFFFFFFFUL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return HasMemory(reinterpret_cast<void*>(address), structure);
|
return HasMemory(reinterpret_cast<void*>(address), structure);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class StructureType>
|
template <class StructureType>
|
||||||
bool HasMemory(const void* addr_in, StructureType** structure = NULL) const {
|
bool HasMemory(const void* addr_in, StructureType** structure = NULL) const {
|
||||||
return HasMemoryImpl(addr_in, sizeof(StructureType),
|
return HasMemoryImpl(addr_in, sizeof(StructureType),
|
||||||
reinterpret_cast<void**>(structure));
|
reinterpret_cast<void**>(structure));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void EnsureDumpMapped();
|
void EnsureDumpMapped();
|
||||||
|
|
||||||
HANDLE dump_file_mapping_;
|
HANDLE dump_file_mapping_;
|
||||||
HANDLE dump_file_handle_;
|
HANDLE dump_file_handle_;
|
||||||
void* dump_file_view_;
|
void* dump_file_view_;
|
||||||
std::wstring dump_file_;
|
std::wstring dump_file_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This is the implementation of GetStream<>.
|
// This is the implementation of GetStream<>.
|
||||||
size_t GetStreamImpl(ULONG stream_number, void** stream) const;
|
size_t GetStreamImpl(ULONG stream_number, void** stream) const;
|
||||||
|
|
||||||
// This is the implementation of HasMemory<>.
|
// This is the implementation of HasMemory<>.
|
||||||
bool HasMemoryImpl(const void* addr_in, size_t pointersize,
|
bool HasMemoryImpl(const void* addr_in, size_t pointersize,
|
||||||
void** structure) const;
|
void** structure) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
#endif // CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
||||||
|
|
|
@ -1,332 +1,332 @@
|
||||||
// Copyright (c) 2010, Google Inc.
|
// Copyright (c) 2010, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright
|
// * Redistributions of source code must retain the above copyright
|
||||||
// notice, this list of conditions and the following disclaimer.
|
// notice, this list of conditions and the following disclaimer.
|
||||||
// * Redistributions in binary form must reproduce the above
|
// * Redistributions in binary form must reproduce the above
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
// in the documentation and/or other materials provided with the
|
// in the documentation and/or other materials provided with the
|
||||||
// distribution.
|
// distribution.
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
||||||
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
||||||
//
|
//
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
|
|
||||||
#include "../crash_generation/minidump_generator.h"
|
#include "../crash_generation/minidump_generator.h"
|
||||||
#include "dump_analysis.h" // NOLINT
|
#include "dump_analysis.h" // NOLINT
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Minidump with stacks, PEB, TEB, and unloaded module list.
|
// Minidump with stacks, PEB, TEB, and unloaded module list.
|
||||||
const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
|
const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
|
||||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||||
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
||||||
|
|
||||||
// Minidump with all of the above, plus memory referenced from stack.
|
// Minidump with all of the above, plus memory referenced from stack.
|
||||||
const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
|
const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
|
||||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||||
MiniDumpWithUnloadedModules | // Get unloaded modules when available.
|
MiniDumpWithUnloadedModules | // Get unloaded modules when available.
|
||||||
MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack.
|
MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack.
|
||||||
|
|
||||||
// Large dump with all process memory.
|
// Large dump with all process memory.
|
||||||
const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
|
const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
|
||||||
MiniDumpWithFullMemory | // Full memory from process.
|
MiniDumpWithFullMemory | // Full memory from process.
|
||||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||||
MiniDumpWithHandleData | // Get all handle information.
|
MiniDumpWithHandleData | // Get all handle information.
|
||||||
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
||||||
|
|
||||||
class MinidumpTest: public testing::Test {
|
class MinidumpTest: public testing::Test {
|
||||||
public:
|
public:
|
||||||
MinidumpTest() {
|
MinidumpTest() {
|
||||||
wchar_t temp_dir_path[ MAX_PATH ] = {0};
|
wchar_t temp_dir_path[ MAX_PATH ] = {0};
|
||||||
::GetTempPath(MAX_PATH, temp_dir_path);
|
::GetTempPath(MAX_PATH, temp_dir_path);
|
||||||
dump_path_ = temp_dir_path;
|
dump_path_ = temp_dir_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
// Make sure URLMon isn't loaded into our process.
|
// Make sure URLMon isn't loaded into our process.
|
||||||
ASSERT_EQ(NULL, ::GetModuleHandle(L"urlmon.dll"));
|
ASSERT_EQ(NULL, ::GetModuleHandle(L"urlmon.dll"));
|
||||||
|
|
||||||
// Then load and unload it to ensure we have something to
|
// Then load and unload it to ensure we have something to
|
||||||
// stock the unloaded module list with.
|
// stock the unloaded module list with.
|
||||||
HMODULE urlmon = ::LoadLibrary(L"urlmon.dll");
|
HMODULE urlmon = ::LoadLibrary(L"urlmon.dll");
|
||||||
ASSERT_TRUE(urlmon != NULL);
|
ASSERT_TRUE(urlmon != NULL);
|
||||||
ASSERT_TRUE(::FreeLibrary(urlmon));
|
ASSERT_TRUE(::FreeLibrary(urlmon));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void TearDown() {
|
virtual void TearDown() {
|
||||||
if (!dump_file_.empty()) {
|
if (!dump_file_.empty()) {
|
||||||
::DeleteFile(dump_file_.c_str());
|
::DeleteFile(dump_file_.c_str());
|
||||||
dump_file_ = L"";
|
dump_file_ = L"";
|
||||||
}
|
}
|
||||||
if (!full_dump_file_.empty()) {
|
if (!full_dump_file_.empty()) {
|
||||||
::DeleteFile(full_dump_file_.c_str());
|
::DeleteFile(full_dump_file_.c_str());
|
||||||
full_dump_file_ = L"";
|
full_dump_file_ = L"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteDump(ULONG flags) {
|
bool WriteDump(ULONG flags) {
|
||||||
using google_breakpad::MinidumpGenerator;
|
using google_breakpad::MinidumpGenerator;
|
||||||
|
|
||||||
// Fake exception is access violation on write to this.
|
// Fake exception is access violation on write to this.
|
||||||
EXCEPTION_RECORD ex_record = {
|
EXCEPTION_RECORD ex_record = {
|
||||||
STATUS_ACCESS_VIOLATION, // ExceptionCode
|
STATUS_ACCESS_VIOLATION, // ExceptionCode
|
||||||
0, // ExceptionFlags
|
0, // ExceptionFlags
|
||||||
NULL, // ExceptionRecord;
|
NULL, // ExceptionRecord;
|
||||||
reinterpret_cast<void*>(0xCAFEBABE), // ExceptionAddress;
|
reinterpret_cast<void*>(0xCAFEBABE), // ExceptionAddress;
|
||||||
2, // NumberParameters;
|
2, // NumberParameters;
|
||||||
{ EXCEPTION_WRITE_FAULT, reinterpret_cast<ULONG_PTR>(this) }
|
{ EXCEPTION_WRITE_FAULT, reinterpret_cast<ULONG_PTR>(this) }
|
||||||
};
|
};
|
||||||
CONTEXT ctx_record = {};
|
CONTEXT ctx_record = {};
|
||||||
EXCEPTION_POINTERS ex_ptrs = {
|
EXCEPTION_POINTERS ex_ptrs = {
|
||||||
&ex_record,
|
&ex_record,
|
||||||
&ctx_record,
|
&ctx_record,
|
||||||
};
|
};
|
||||||
|
|
||||||
MinidumpGenerator generator(dump_path_);
|
MinidumpGenerator generator(dump_path_);
|
||||||
|
|
||||||
// And write a dump
|
// And write a dump
|
||||||
bool result = generator.WriteMinidump(::GetCurrentProcess(),
|
bool result = generator.WriteMinidump(::GetCurrentProcess(),
|
||||||
::GetCurrentProcessId(),
|
::GetCurrentProcessId(),
|
||||||
::GetCurrentThreadId(),
|
::GetCurrentThreadId(),
|
||||||
::GetCurrentThreadId(),
|
::GetCurrentThreadId(),
|
||||||
&ex_ptrs,
|
&ex_ptrs,
|
||||||
NULL,
|
NULL,
|
||||||
static_cast<MINIDUMP_TYPE>(flags),
|
static_cast<MINIDUMP_TYPE>(flags),
|
||||||
TRUE,
|
TRUE,
|
||||||
&dump_file_,
|
&dump_file_,
|
||||||
&full_dump_file_);
|
&full_dump_file_);
|
||||||
return result == TRUE;
|
return result == TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::wstring dump_file_;
|
std::wstring dump_file_;
|
||||||
std::wstring full_dump_file_;
|
std::wstring full_dump_file_;
|
||||||
|
|
||||||
std::wstring dump_path_;
|
std::wstring dump_path_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need to be able to get file information from Windows
|
// We need to be able to get file information from Windows
|
||||||
bool HasFileInfo(const std::wstring& file_path) {
|
bool HasFileInfo(const std::wstring& file_path) {
|
||||||
DWORD dummy;
|
DWORD dummy;
|
||||||
const wchar_t* path = file_path.c_str();
|
const wchar_t* path = file_path.c_str();
|
||||||
DWORD length = ::GetFileVersionInfoSize(path, &dummy);
|
DWORD length = ::GetFileVersionInfoSize(path, &dummy);
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
void* data = calloc(length, 1);
|
void* data = calloc(length, 1);
|
||||||
if (!data)
|
if (!data)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!::GetFileVersionInfo(path, dummy, length, data)) {
|
if (!::GetFileVersionInfo(path, dummy, length, data)) {
|
||||||
free(data);
|
free(data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* translate = NULL;
|
void* translate = NULL;
|
||||||
UINT page_count;
|
UINT page_count;
|
||||||
BOOL query_result = VerQueryValue(
|
BOOL query_result = VerQueryValue(
|
||||||
data,
|
data,
|
||||||
L"\\VarFileInfo\\Translation",
|
L"\\VarFileInfo\\Translation",
|
||||||
static_cast<void**>(&translate),
|
static_cast<void**>(&translate),
|
||||||
&page_count);
|
&page_count);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
if (query_result && translate) {
|
if (query_result && translate) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MinidumpTest, Version) {
|
TEST_F(MinidumpTest, Version) {
|
||||||
API_VERSION* version = ::ImagehlpApiVersion();
|
API_VERSION* version = ::ImagehlpApiVersion();
|
||||||
|
|
||||||
HMODULE dbg_help = ::GetModuleHandle(L"dbghelp.dll");
|
HMODULE dbg_help = ::GetModuleHandle(L"dbghelp.dll");
|
||||||
ASSERT_TRUE(dbg_help != NULL);
|
ASSERT_TRUE(dbg_help != NULL);
|
||||||
|
|
||||||
wchar_t dbg_help_file[1024] = {};
|
wchar_t dbg_help_file[1024] = {};
|
||||||
ASSERT_TRUE(::GetModuleFileName(dbg_help,
|
ASSERT_TRUE(::GetModuleFileName(dbg_help,
|
||||||
dbg_help_file,
|
dbg_help_file,
|
||||||
sizeof(dbg_help_file) /
|
sizeof(dbg_help_file) /
|
||||||
sizeof(*dbg_help_file)));
|
sizeof(*dbg_help_file)));
|
||||||
ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != NULL);
|
ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != NULL);
|
||||||
|
|
||||||
// LOG(INFO) << "DbgHelp.dll version: " << file_info->file_version();
|
// LOG(INFO) << "DbgHelp.dll version: " << file_info->file_version();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MinidumpTest, Normal) {
|
TEST_F(MinidumpTest, Normal) {
|
||||||
EXPECT_TRUE(WriteDump(MiniDumpNormal));
|
EXPECT_TRUE(WriteDump(MiniDumpNormal));
|
||||||
DumpAnalysis mini(dump_file_);
|
DumpAnalysis mini(dump_file_);
|
||||||
|
|
||||||
// We expect threads, modules and some memory.
|
// We expect threads, modules and some memory.
|
||||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||||
|
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||||
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
||||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||||
EXPECT_FALSE(mini.HasStream(UnloadedModuleListStream));
|
EXPECT_FALSE(mini.HasStream(UnloadedModuleListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||||
|
|
||||||
// We expect no PEB nor TEBs in this dump.
|
// We expect no PEB nor TEBs in this dump.
|
||||||
EXPECT_FALSE(mini.HasTebs());
|
EXPECT_FALSE(mini.HasTebs());
|
||||||
EXPECT_FALSE(mini.HasPeb());
|
EXPECT_FALSE(mini.HasPeb());
|
||||||
|
|
||||||
// We expect no off-stack memory in this dump.
|
// We expect no off-stack memory in this dump.
|
||||||
EXPECT_FALSE(mini.HasMemory(this));
|
EXPECT_FALSE(mini.HasMemory(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MinidumpTest, SmallDump) {
|
TEST_F(MinidumpTest, SmallDump) {
|
||||||
ASSERT_TRUE(WriteDump(kSmallDumpType));
|
ASSERT_TRUE(WriteDump(kSmallDumpType));
|
||||||
DumpAnalysis mini(dump_file_);
|
DumpAnalysis mini(dump_file_);
|
||||||
|
|
||||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||||
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||||
|
|
||||||
// We expect PEB and TEBs in this dump.
|
// We expect PEB and TEBs in this dump.
|
||||||
EXPECT_TRUE(mini.HasTebs());
|
EXPECT_TRUE(mini.HasTebs());
|
||||||
EXPECT_TRUE(mini.HasPeb());
|
EXPECT_TRUE(mini.HasPeb());
|
||||||
|
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||||
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
||||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||||
|
|
||||||
// We expect no off-stack memory in this dump.
|
// We expect no off-stack memory in this dump.
|
||||||
EXPECT_FALSE(mini.HasMemory(this));
|
EXPECT_FALSE(mini.HasMemory(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MinidumpTest, LargerDump) {
|
TEST_F(MinidumpTest, LargerDump) {
|
||||||
ASSERT_TRUE(WriteDump(kLargerDumpType));
|
ASSERT_TRUE(WriteDump(kLargerDumpType));
|
||||||
DumpAnalysis mini(dump_file_);
|
DumpAnalysis mini(dump_file_);
|
||||||
|
|
||||||
// The dump should have all of these streams.
|
// The dump should have all of these streams.
|
||||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||||
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||||
|
|
||||||
// We expect memory referenced by stack in this dump.
|
// We expect memory referenced by stack in this dump.
|
||||||
EXPECT_TRUE(mini.HasMemory(this));
|
EXPECT_TRUE(mini.HasMemory(this));
|
||||||
|
|
||||||
// We expect PEB and TEBs in this dump.
|
// We expect PEB and TEBs in this dump.
|
||||||
EXPECT_TRUE(mini.HasTebs());
|
EXPECT_TRUE(mini.HasTebs());
|
||||||
EXPECT_TRUE(mini.HasPeb());
|
EXPECT_TRUE(mini.HasPeb());
|
||||||
|
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||||
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
||||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MinidumpTest, FullDump) {
|
TEST_F(MinidumpTest, FullDump) {
|
||||||
ASSERT_TRUE(WriteDump(kFullDumpType));
|
ASSERT_TRUE(WriteDump(kFullDumpType));
|
||||||
ASSERT_TRUE(dump_file_ != L"");
|
ASSERT_TRUE(dump_file_ != L"");
|
||||||
ASSERT_TRUE(full_dump_file_ != L"");
|
ASSERT_TRUE(full_dump_file_ != L"");
|
||||||
DumpAnalysis mini(dump_file_);
|
DumpAnalysis mini(dump_file_);
|
||||||
DumpAnalysis full(full_dump_file_);
|
DumpAnalysis full(full_dump_file_);
|
||||||
|
|
||||||
// Either dumps can contain part of the information.
|
// Either dumps can contain part of the information.
|
||||||
|
|
||||||
// The dump should have all of these streams.
|
// The dump should have all of these streams.
|
||||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||||
EXPECT_TRUE(full.HasStream(ThreadListStream));
|
EXPECT_TRUE(full.HasStream(ThreadListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||||
EXPECT_TRUE(full.HasStream(ModuleListStream));
|
EXPECT_TRUE(full.HasStream(ModuleListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||||
EXPECT_TRUE(full.HasStream(ExceptionStream));
|
EXPECT_TRUE(full.HasStream(ExceptionStream));
|
||||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||||
EXPECT_TRUE(full.HasStream(SystemInfoStream));
|
EXPECT_TRUE(full.HasStream(SystemInfoStream));
|
||||||
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
||||||
EXPECT_TRUE(full.HasStream(UnloadedModuleListStream));
|
EXPECT_TRUE(full.HasStream(UnloadedModuleListStream));
|
||||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||||
EXPECT_TRUE(full.HasStream(MiscInfoStream));
|
EXPECT_TRUE(full.HasStream(MiscInfoStream));
|
||||||
EXPECT_TRUE(mini.HasStream(HandleDataStream));
|
EXPECT_TRUE(mini.HasStream(HandleDataStream));
|
||||||
EXPECT_TRUE(full.HasStream(HandleDataStream));
|
EXPECT_TRUE(full.HasStream(HandleDataStream));
|
||||||
|
|
||||||
// We expect memory referenced by stack in this dump.
|
// We expect memory referenced by stack in this dump.
|
||||||
EXPECT_FALSE(mini.HasMemory(this));
|
EXPECT_FALSE(mini.HasMemory(this));
|
||||||
EXPECT_TRUE(full.HasMemory(this));
|
EXPECT_TRUE(full.HasMemory(this));
|
||||||
|
|
||||||
// We expect PEB and TEBs in this dump.
|
// We expect PEB and TEBs in this dump.
|
||||||
EXPECT_TRUE(mini.HasTebs() || full.HasTebs());
|
EXPECT_TRUE(mini.HasTebs() || full.HasTebs());
|
||||||
EXPECT_TRUE(mini.HasPeb() || full.HasPeb());
|
EXPECT_TRUE(mini.HasPeb() || full.HasPeb());
|
||||||
|
|
||||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||||
EXPECT_TRUE(full.HasStream(Memory64ListStream));
|
EXPECT_TRUE(full.HasStream(Memory64ListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||||
EXPECT_FALSE(full.HasStream(MemoryListStream));
|
EXPECT_FALSE(full.HasStream(MemoryListStream));
|
||||||
|
|
||||||
// This is the only place we don't use OR because we want both not
|
// This is the only place we don't use OR because we want both not
|
||||||
// to have the streams.
|
// to have the streams.
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||||
EXPECT_FALSE(full.HasStream(ThreadExListStream));
|
EXPECT_FALSE(full.HasStream(ThreadExListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||||
EXPECT_FALSE(full.HasStream(CommentStreamA));
|
EXPECT_FALSE(full.HasStream(CommentStreamA));
|
||||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||||
EXPECT_FALSE(full.HasStream(CommentStreamW));
|
EXPECT_FALSE(full.HasStream(CommentStreamW));
|
||||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||||
EXPECT_FALSE(full.HasStream(FunctionTableStream));
|
EXPECT_FALSE(full.HasStream(FunctionTableStream));
|
||||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||||
EXPECT_FALSE(full.HasStream(MemoryInfoListStream));
|
EXPECT_FALSE(full.HasStream(MemoryInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||||
EXPECT_FALSE(full.HasStream(ThreadInfoListStream));
|
EXPECT_FALSE(full.HasStream(ThreadInfoListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||||
EXPECT_FALSE(full.HasStream(HandleOperationListStream));
|
EXPECT_FALSE(full.HasStream(HandleOperationListStream));
|
||||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||||
EXPECT_FALSE(full.HasStream(TokenStream));
|
EXPECT_FALSE(full.HasStream(TokenStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -24,4 +24,4 @@ echo Repository information (output of 'svn info') follows: >> %TEMP%\checkin.tx
|
||||||
call svn info >> %TEMP%\checkin.txt
|
call svn info >> %TEMP%\checkin.txt
|
||||||
echo Done!
|
echo Done!
|
||||||
echo type 'svn commit -F %%TEMP%%\checkin.txt' to commit.
|
echo type 'svn commit -F %%TEMP%%\checkin.txt' to commit.
|
||||||
popd
|
popd
|
||||||
|
|
Loading…
Reference in a new issue