From e05aab7b6bbf2e5ddb80c2f5a1192b97be6f4047 Mon Sep 17 00:00:00 2001 From: "cdn@chromium.org" Date: Tue, 10 Jul 2012 18:52:07 +0000 Subject: 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 --- src/client/windows/crash_generation/client_info.cc | 45 ++++++++++++++++++++++ src/client/windows/crash_generation/client_info.h | 8 ++++ .../crash_generation/crash_generation_server.cc | 2 + .../windows/crash_generation/minidump_generator.cc | 22 ++++++++--- .../windows/crash_generation/minidump_generator.h | 3 ++ 5 files changed, 75 insertions(+), 5 deletions(-) (limited to 'src/client/windows/crash_generation') 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(_wcstoi64(address_str, NULL, 16)); + long size = wcstol(size_str, NULL, 16); + if (size <= 0 || size > kMaxCustomDataStreamSize) + return false; + + custom_data_stream_ = reinterpret_cast( + 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(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 #include #include +#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, -- cgit v1.2.1