Index: components/crash/app/breakpad_win.cc |
diff --git a/components/crash/app/breakpad_win.cc b/components/crash/app/breakpad_win.cc |
index b0dba9899e593ca3967444c2b5bf713293dc96d0..5fe19c4d187bfa721b1f488bca4a290aee814d99 100644 |
--- a/components/crash/app/breakpad_win.cc |
+++ b/components/crash/app/breakpad_win.cc |
@@ -21,6 +21,7 @@ |
#include "base/debug/dump_without_crashing.h" |
#include "base/environment.h" |
#include "base/memory/scoped_ptr.h" |
+#include "base/numerics/safe_conversions.h" |
#include "base/strings/string16.h" |
#include "base/strings/string_split.h" |
#include "base/strings/string_util.h" |
@@ -45,6 +46,19 @@ |
#pragma intrinsic(_AddressOfReturnAddress) |
#pragma intrinsic(_ReturnAddress) |
+#ifdef _WIN64 |
+// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx |
+typedef struct _UNWIND_INFO { |
+ unsigned char Version : 3; |
+ unsigned char Flags : 5; |
+ unsigned char SizeOfProlog; |
+ unsigned char CountOfCodes; |
+ unsigned char FrameRegister : 4; |
+ unsigned char FrameOffset : 4; |
+ ULONG ExceptionHandler; |
+} UNWIND_INFO, *PUNWIND_INFO; |
+#endif |
+ |
namespace breakpad { |
using crash_reporter::GetCrashReporterClient; |
@@ -611,4 +625,73 @@ extern "C" void __declspec(dllexport) __cdecl |
env->UnSetVar(kPipeNameVar); |
} |
+#ifdef _WIN64 |
+int CrashForExceptionInNonABICompliantCodeRange( |
+ PEXCEPTION_RECORD ExceptionRecord, |
+ ULONG64 EstablisherFrame, |
+ PCONTEXT ContextRecord, |
+ PDISPATCHER_CONTEXT DispatcherContext) { |
+ EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord }; |
+ return CrashForException(&info); |
+} |
+ |
+struct ExceptionHandlerRecord { |
+ RUNTIME_FUNCTION runtime_function; |
+ UNWIND_INFO unwind_info; |
+ unsigned char thunk[12]; |
+}; |
+ |
+extern "C" void __declspec(dllexport) __cdecl |
+RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { |
+ ExceptionHandlerRecord* record = |
+ reinterpret_cast<ExceptionHandlerRecord*>(start); |
+ |
+ // We assume that the first page of the code range is executable and |
+ // committed and reserved for breakpad. What could possibly go wrong? |
+ |
+ // All addresses are 32bit relative offsets to start. |
+ record->runtime_function.BeginAddress = 0; |
+ record->runtime_function.EndAddress = |
+ base::checked_cast<DWORD>(size_in_bytes); |
+ record->runtime_function.UnwindData = |
+ offsetof(ExceptionHandlerRecord, unwind_info); |
+ |
+ // Create unwind info that only specifies an exception handler. |
+ record->unwind_info.Version = 1; |
+ record->unwind_info.Flags = UNW_FLAG_EHANDLER; |
+ record->unwind_info.SizeOfProlog = 0; |
+ record->unwind_info.CountOfCodes = 0; |
+ record->unwind_info.FrameRegister = 0; |
+ record->unwind_info.FrameOffset = 0; |
+ record->unwind_info.ExceptionHandler = |
+ offsetof(ExceptionHandlerRecord, thunk); |
+ |
+ // Hardcoded thunk. |
+ // mov imm64, rax |
+ record->thunk[0] = 0x48; |
+ record->thunk[1] = 0xb8; |
+ void* handler = &CrashForExceptionInNonABICompliantCodeRange; |
+ memcpy(&record->thunk[2], &handler, 8); |
+ |
+ // jmp rax |
+ record->thunk[10] = 0xff; |
+ record->thunk[11] = 0xe0; |
+ |
+ // Protect reserved page against modifications. |
+ DWORD old_protect; |
+ CHECK(VirtualProtect( |
+ start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect)); |
+ CHECK(RtlAddFunctionTable( |
+ &record->runtime_function, 1, reinterpret_cast<DWORD64>(start))); |
+} |
+ |
+extern "C" void __declspec(dllexport) __cdecl |
+UnregisterNonABICompliantCodeRange(void* start) { |
+ ExceptionHandlerRecord* record = |
+ reinterpret_cast<ExceptionHandlerRecord*>(start); |
+ |
+ CHECK(RtlDeleteFunctionTable(&record->runtime_function)); |
+} |
+#endif |
+ |
} // namespace breakpad |