aboutsummaryrefslogtreecommitdiff
path: root/src/client/windows/crash_generation
diff options
context:
space:
mode:
authorcdn@chromium.org <cdn@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-07-10 18:52:07 +0000
committercdn@chromium.org <cdn@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-07-10 18:52:07 +0000
commite05aab7b6bbf2e5ddb80c2f5a1192b97be6f4047 (patch)
treea99cab04e3b4463d50e11eea4a4c2a7cbc70544d /src/client/windows/crash_generation
parentAdd Android NDK module definition + sample application (diff)
downloadbreakpad-e05aab7b6bbf2e5ddb80c2f5a1192b97be6f4047.tar.xz
Add the capability to include an arbitrary data stream within minidumps
This is supplied via a custom field "custom-data-stream" Review URL: https://breakpad.appspot.com/408002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@984 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/windows/crash_generation')
-rw-r--r--src/client/windows/crash_generation/client_info.cc45
-rw-r--r--src/client/windows/crash_generation/client_info.h8
-rw-r--r--src/client/windows/crash_generation/crash_generation_server.cc2
-rw-r--r--src/client/windows/crash_generation/minidump_generator.cc22
-rw-r--r--src/client/windows/crash_generation/minidump_generator.h3
5 files changed, 75 insertions, 5 deletions
diff --git a/src/client/windows/crash_generation/client_info.cc b/src/client/windows/crash_generation/client_info.cc
index 60bbac82..294096f3 100644
--- a/src/client/windows/crash_generation/client_info.cc
+++ b/src/client/windows/crash_generation/client_info.cc
@@ -31,6 +31,8 @@
#include "client/windows/common/ipc_protocol.h"
static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
+static const wchar_t kCustomDataStreamCustomFieldName[] = L"custom-data-stream";
+static const size_t kMaxCustomDataStreamSize = 100 * 1024 * 1024;
static const size_t kMaxCustomInfoEntries = 4096;
namespace google_breakpad {
@@ -48,6 +50,7 @@ ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
ex_info_(ex_info),
assert_info_(assert_info),
custom_client_info_(custom_client_info),
+ custom_data_stream_(NULL),
thread_id_(thread_id),
process_handle_(NULL),
dump_requested_handle_(NULL),
@@ -86,6 +89,11 @@ bool ClientInfo::Initialize() {
}
ClientInfo::~ClientInfo() {
+ if (custom_data_stream_) {
+ delete custom_data_stream_;
+ custom_data_stream_ = NULL;
+ }
+
if (dump_request_wait_handle_) {
// Wait for callbacks that might already be running to finish.
UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
@@ -199,6 +207,43 @@ bool ClientInfo::PopulateCustomInfo() {
return (bytes_count != read_count);
}
+bool ClientInfo::PopulateCustomDataStream() {
+ for (SIZE_T i = 0; i < custom_client_info_.count; ++i) {
+ if (_wcsicmp(kCustomDataStreamCustomFieldName,
+ custom_client_info_.entries[i].name) != 0) {
+ continue;
+ }
+ wchar_t address_str[CustomInfoEntry::kValueMaxLength];
+ memcpy(address_str, custom_client_info_.entries[i].value,
+ CustomInfoEntry::kValueMaxLength);
+ wchar_t* size_str = wcschr(address_str, ':');
+ if (!size_str)
+ return false;
+
+ size_str[0] = 0;
+ ++size_str;
+ void* address = reinterpret_cast<void*>(_wcstoi64(address_str, NULL, 16));
+ long size = wcstol(size_str, NULL, 16);
+ if (size <= 0 || size > kMaxCustomDataStreamSize)
+ return false;
+
+ custom_data_stream_ = reinterpret_cast<CustomDataStream*>(
+ new u_int8_t[sizeof(CustomDataStream) + size - 1]);
+
+ SIZE_T bytes_count = 0;
+ if (!ReadProcessMemory(process_handle_, address,
+ custom_data_stream_->stream, size, &bytes_count)) {
+ delete custom_data_stream_;
+ custom_data_stream_ = NULL;
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
CustomClientInfo ClientInfo::GetCustomInfo() const {
CustomClientInfo custom_info;
custom_info.entries = custom_info_entries_.get();
diff --git a/src/client/windows/crash_generation/client_info.h b/src/client/windows/crash_generation/client_info.h
index 999e6678..3d88ffd4 100644
--- a/src/client/windows/crash_generation/client_info.h
+++ b/src/client/windows/crash_generation/client_info.h
@@ -61,6 +61,7 @@ class ClientInfo {
MINIDUMP_TYPE dump_type() const { return dump_type_; }
EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
MDRawAssertionInfo* assert_info() const { return assert_info_; }
+ CustomDataStream* custom_data_stream() const { return custom_data_stream_; }
DWORD* thread_id() const { return thread_id_; }
HANDLE process_handle() const { return process_handle_; }
HANDLE dump_requested_handle() const { return dump_requested_handle_; }
@@ -90,6 +91,10 @@ class ClientInfo {
bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
bool GetClientThreadId(DWORD* thread_id) const;
+ // Reads the custom data stream (if supplied) from the client process
+ // address space.
+ bool PopulateCustomDataStream();
+
// Reads the custom information from the client process address space.
bool PopulateCustomInfo();
@@ -130,6 +135,9 @@ class ClientInfo {
// Custom information about the client.
CustomClientInfo custom_client_info_;
+ // Custom data stream supplied by the client.
+ CustomDataStream* custom_data_stream_;
+
// Contains the custom client info entries read from the client process
// memory. This will be populated only if the method GetClientCustomInfo
// is called.
diff --git a/src/client/windows/crash_generation/crash_generation_server.cc b/src/client/windows/crash_generation/crash_generation_server.cc
index 477973c1..de3d3fce 100644
--- a/src/client/windows/crash_generation/crash_generation_server.cc
+++ b/src/client/windows/crash_generation/crash_generation_server.cc
@@ -796,6 +796,7 @@ void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
assert(context);
ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
client_info->PopulateCustomInfo();
+ client_info->PopulateCustomDataStream();
CrashGenerationServer* crash_server = client_info->crash_server();
assert(crash_server);
@@ -892,6 +893,7 @@ bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
GetCurrentThreadId(),
client_ex_info,
client.assert_info(),
+ client.custom_data_stream(),
client.dump_type(),
true,
dump_path);
diff --git a/src/client/windows/crash_generation/minidump_generator.cc b/src/client/windows/crash_generation/minidump_generator.cc
index fe4937aa..34aa8a97 100644
--- a/src/client/windows/crash_generation/minidump_generator.cc
+++ b/src/client/windows/crash_generation/minidump_generator.cc
@@ -271,14 +271,15 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
+ CustomDataStream* custom_data_stream,
MINIDUMP_TYPE dump_type,
bool is_client_pointers,
wstring* 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);
+ assert_info, custom_data_stream, dump_type,
+ is_client_pointers, dump_path, NULL);
}
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
@@ -287,6 +288,7 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
+ CustomDataStream* custom_data_stream,
MINIDUMP_TYPE dump_type,
bool is_client_pointers,
wstring* dump_path,
@@ -368,9 +370,9 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
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];
+ // Leave room in user_stream_array for possible assertion info, handle
+ // operations, and custom data streams.
+ MINIDUMP_USER_STREAM user_stream_array[4];
user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
user_stream_array[0].BufferSize = sizeof(breakpad_info);
user_stream_array[0].Buffer = &breakpad_info;
@@ -414,6 +416,16 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
++user_streams.UserStreamCount;
}
+ if (custom_data_stream) {
+ user_stream_array[user_streams.UserStreamCount].Type =
+ MD_CUSTOM_DATA_STREAM;
+ user_stream_array[user_streams.UserStreamCount].BufferSize =
+ custom_data_stream->size;
+ user_stream_array[user_streams.UserStreamCount].Buffer =
+ custom_data_stream->stream;
+ ++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.
diff --git a/src/client/windows/crash_generation/minidump_generator.h b/src/client/windows/crash_generation/minidump_generator.h
index 5f9e4b54..b2e973e6 100644
--- a/src/client/windows/crash_generation/minidump_generator.h
+++ b/src/client/windows/crash_generation/minidump_generator.h
@@ -33,6 +33,7 @@
#include <windows.h>
#include <dbghelp.h>
#include <list>
+#include "client/windows/common/ipc_protocol.h"
#include "google_breakpad/common/minidump_format.h"
namespace google_breakpad {
@@ -57,6 +58,7 @@ class MinidumpGenerator {
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
+ CustomDataStream* custom_data_stream,
MINIDUMP_TYPE dump_type,
bool is_client_pointers,
std::wstring* dump_path);
@@ -70,6 +72,7 @@ class MinidumpGenerator {
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exception_pointers,
MDRawAssertionInfo* assert_info,
+ CustomDataStream* custom_data_stream,
MINIDUMP_TYPE dump_type,
bool is_client_pointers,
std::wstring* dump_path,