Bug 1286802 - Part 6: Implement CrashGenerationServer::set_include_context_heap() for OOP crash generation. r?ted draft
authorCervantes Yu <cyu@mozilla.com>
Fri, 24 Mar 2017 19:57:57 +0800
changeset 580339 b6c23fbfda5d6f91c7cf8ac1d3744a4301bb4013
parent 580338 52795bf3ebf3d6fa230247dad4de8b3fb361b8f6
child 580340 cafc5ef54d121bc666930c887dfc8125394468f3
push id59519
push usercyu@mozilla.com
push dateThu, 18 May 2017 11:09:20 +0000
reviewersted
bugs1286802
milestone55.0a1
Bug 1286802 - Part 6: Implement CrashGenerationServer::set_include_context_heap() for OOP crash generation. r?ted MozReview-Commit-ID: 2W0VATExXmE
toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.cc
toolkit/crashreporter/breakpad-client/windows/crash_generation/client_info.h
toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.cc
toolkit/crashreporter/breakpad-client/windows/crash_generation/crash_generation_server.h
--- 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__