Bug 1286802 - Part 6: Implement CrashGenerationServer::set_include_context_heap() for OOP crash generation. r?ted
MozReview-Commit-ID: 2W0VATExXmE
--- a/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.cc
+++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.cc
@@ -22,16 +22,18 @@
// 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.
+#include <cassert>
+
#include "windows/crash_generation/client_info.h"
#include "windows/common/ipc_protocol.h"
static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
static const size_t kMaxCustomInfoEntries = 4096;
namespace google_breakpad {
@@ -128,27 +130,60 @@ ClientInfo::~ClientInfo() {
CloseHandle(dump_requested_handle_);
}
if (dump_generated_handle_) {
CloseHandle(dump_generated_handle_);
}
}
-bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {
+bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info_ptr) const {
SIZE_T bytes_count = 0;
+
+ static_assert(sizeof(*ex_info_ptr) == sizeof(void*),
+ "Expected to read sizeof(void*) bytes.");
if (!ReadProcessMemory(process_handle_,
ex_info_,
- ex_info,
- sizeof(*ex_info),
+ ex_info_ptr,
+ sizeof(*ex_info_ptr),
&bytes_count)) {
return false;
}
- return bytes_count == sizeof(*ex_info);
+ return bytes_count == sizeof(*ex_info_ptr);
+}
+
+bool ClientInfo::PopulateClientExceptionContext(EXCEPTION_POINTERS* ex_info_ptr,
+ CONTEXT* out_context) const {
+ SIZE_T bytes_count = 0;
+
+ EXCEPTION_POINTERS ex_info;
+ if (!ReadProcessMemory(process_handle_,
+ ex_info_ptr,
+ &ex_info,
+ sizeof(ex_info),
+ &bytes_count)) {
+ return false;
+ }
+
+ if (bytes_count != sizeof(ex_info)) {
+ return false;
+ }
+
+ static_assert(sizeof(*out_context) == sizeof(CONTEXT),
+ "Expected to read sizeof(CONTEXT) bytes.");
+ if (!ReadProcessMemory(process_handle_,
+ ex_info.ContextRecord,
+ out_context,
+ sizeof(*out_context),
+ &bytes_count)) {
+ return false;
+ }
+
+ return bytes_count == sizeof(*out_context);
}
bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
SIZE_T bytes_count = 0;
if (!ReadProcessMemory(process_handle_,
thread_id_,
thread_id,
sizeof(*thread_id),
--- a/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.h
+++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.h
@@ -83,17 +83,22 @@ class ClientInfo {
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 GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info_ptr) const;
+
+ // Reads the content of exception CONTEXT from the client process.
+ bool PopulateClientExceptionContext(EXCEPTION_POINTERS* ex_info,
+ CONTEXT* out_context) 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;
--- a/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.cc
+++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.cc
@@ -893,45 +893,85 @@ void CrashGenerationServer::HandleDumpRe
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());
}
void CrashGenerationServer::set_include_context_heap(bool enabled) {
-
include_context_heap_ = enabled;
}
bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
std::wstring* dump_path) {
assert(client.pid() != 0);
assert(client.process_handle());
+ DWORD client_thread_id = 0;
+ if (!client.GetClientThreadId(&client_thread_id)) {
+ return false;
+ }
+
// We have to get the address of EXCEPTION_INFORMATION from
// the client process address space.
EXCEPTION_POINTERS* client_ex_info = NULL;
+
+ // Only needs to read the value of a remote pointer in client_ex_info.
if (!client.GetClientExceptionInfo(&client_ex_info)) {
return false;
}
- DWORD client_thread_id = 0;
- if (!client.GetClientThreadId(&client_thread_id)) {
- return false;
+ if (include_context_heap_) {
+ CONTEXT context_content;
+
+ // Needs to read the content of CONTEXT from the client.
+ if (!client.PopulateClientExceptionContext(client_ex_info,
+ &context_content)) {
+ include_context_heap_ = false;
+ }
+
+ // Allocate AppMemory instances for exception context.
+ for (int i = 0; i < kExceptionAppMemoryRegions; i++) {
+ AppMemory app_memory;
+ app_memory.ptr = reinterpret_cast<ULONG64>(nullptr);
+ app_memory.length = 0;
+ app_memory.preallocated = true;
+ app_memory_info_.push_back(app_memory);
+ }
+
+ IncludeAppMemoryFromExceptionContext(client.process_handle(),
+ client_thread_id,
+ app_memory_info_,
+ &context_content,
+ !include_context_heap_);
}
MinidumpGenerator dump_generator(dump_path_,
client.process_handle(),
client.pid(),
client_thread_id,
GetCurrentThreadId(),
client_ex_info,
client.assert_info(),
client.dump_type(),
true);
- if (!dump_generator.GenerateDumpFile(dump_path)) {
+
+ MinidumpCallbackContext callback_context;
+ MINIDUMP_CALLBACK_INFORMATION callback;
+ if (include_context_heap_) {
+ // Set memory callback to include heap regions.
+ callback_context.iter = app_memory_info_.cbegin();
+ callback_context.end = app_memory_info_.cend();
+
+ callback.CallbackRoutine = MinidumpWriteDumpCallback;
+ callback.CallbackParam = &callback_context;
+
+ dump_generator.SetCallback(&callback);
+ }
+
+ if (!dump_generator.GenerateDumpFile(dump_path)) {
return false;
}
return dump_generator.WriteMinidump();
}
} // namespace google_breakpad
--- a/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.h
+++ b/toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.h
@@ -27,16 +27,17 @@
// (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_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
#include <list>
#include <string>
+#include "windows/common/minidump_callback.h"
#include "windows/common/ipc_protocol.h"
#include "windows/crash_generation/minidump_generator.h"
#include "common/scoped_ptr.h"
namespace google_breakpad {
class ClientInfo;
// Abstraction for server side implementation of out-of-process crash
@@ -292,16 +293,18 @@ class CrashGenerationServer {
ProtocolMessage msg_;
// Client Info for the client that's connecting to the server.
ClientInfo* client_info_;
// Whether to include heap regions of the crashing context.
bool include_context_heap_;
+ AppMemoryList app_memory_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__