summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThanos Doukoudakis <thanos.doukoudakis@isode.com>2017-10-16 11:53:42 (GMT)
committerKevin Smith <kevin.smith@isode.com>2017-10-19 09:22:57 (GMT)
commiteb07238e9c1a09a640dae06e8a433d7dba77f490 (patch)
tree51b618bbdf933bcca2b8deb915e131c48d80d5f7 /3rdParty/Breakpad/src/client/mac/handler
parent80ef26c165a08d5251d7ee56e0bd07b86fc82f55 (diff)
downloadswift-eb07238e9c1a09a640dae06e8a433d7dba77f490.zip
swift-eb07238e9c1a09a640dae06e8a433d7dba77f490.tar.bz2
Upgrade Breakpad to latest
This commit will upgrade breakpad to version 1.0.86 (I9957f27cd134f862b9831e4b1d90f8a014eb37b6) from https://chromium.googlesource.com/breakpad/breakpad Added a script(BreakpadSwiftCleanup.sh) that remove files from Breakpad's repository that are not used by Swift. This commit also re-applies the changes that were introduced in commit 7f0fe603be200c09c74cf9cc295a972f3c3dbdfd, that change the minidump filename format to include version and date Test-Information: https://travis-ci.org/google/breakpad/builds/283789304 https://ci.appveyor.com/project/vapier/breakpad/build/job/1bu73ysmcfpwg9e4 Tested by adding some code that forces a crash to the client on Windows 10 with VS2015. Verified the name and contents of the generated crash dump. Change-Id: Ied9e74088e43137845edc09d070c2c27494aeade
Diffstat (limited to '3rdParty/Breakpad/src/client/mac/handler')
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc17
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc19
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h2
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc170
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/exception_handler.h8
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h7
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc324
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h36
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc92
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h85
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h47
11 files changed, 620 insertions, 187 deletions
diff --git a/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc b/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc
index b50aa03..3492b82 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc
@@ -202,17 +202,6 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC ||
/* The following is the big-endian ppc64 check */
*((unsigned int *)&buf) == FAT_MAGIC) {
- /* Get host info */
- host_t host = mach_host_self();
- unsigned i = HOST_BASIC_INFO_COUNT;
- struct host_basic_info hbi;
- kern_return_t kr;
- if ((kr = host_info(host, HOST_BASIC_INFO,
- (host_info_t)(&hbi), &i)) != KERN_SUCCESS) {
- return -1;
- }
- mach_port_deallocate(mach_task_self(), host);
-
/* Read in the fat header */
struct fat_header fh;
if (lseek(fd, 0, SEEK_SET) == -1) {
@@ -281,7 +270,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
off_t sa; /* symbol address */
off_t ss; /* start of strings */
- register register_t n;
+ register_t n;
if (*((unsigned int *)&buf) == magic) {
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
@@ -354,14 +343,14 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
// and look for a match
while (n) {
nlist_type space[BUFSIZ/sizeof (nlist_type)];
- register register_t m = sizeof (space);
+ register_t m = sizeof (space);
if (n < m)
m = n;
if (read(fd, (char *)space, m) != m)
break;
n -= m;
- long savpos = lseek(fd, 0, SEEK_CUR);
+ off_t savpos = lseek(fd, 0, SEEK_CUR);
if (savpos == -1) {
return -1;
}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc
index ef5743c..cdba6df 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc
@@ -41,6 +41,7 @@ extern "C" { // needed to compile on Leopard
#include <mach/task_info.h>
#include <sys/sysctl.h>
#include <TargetConditionals.h>
+#include <unistd.h>
#include <algorithm>
#include <string>
@@ -261,8 +262,8 @@ bool FindTextSection(DynamicImage& image) {
reinterpret_cast<const mach_segment_command_type *>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
- image.vmaddr_ = seg->vmaddr;
- image.vmsize_ = seg->vmsize;
+ image.vmaddr_ = static_cast<mach_vm_address_t>(seg->vmaddr);
+ image.vmsize_ = static_cast<mach_vm_size_t>(seg->vmsize);
image.slide_ = 0;
if (seg->fileoff == 0 && seg->filesize != 0) {
@@ -363,7 +364,7 @@ static uint64_t LookupSymbol(const char* symbol_name,
return list.n_value;
}
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
static bool HasTaskDyldInfo() {
return true;
}
@@ -380,13 +381,9 @@ static SInt32 GetOSVersion() {
}
static bool HasTaskDyldInfo() {
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
- return true;
-#else
return GetOSVersion() >= 0x1060;
-#endif
}
-#endif // TARGET_OS_IPHONE
+#endif // TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= 10_6
uint64_t DynamicImages::GetDyldAllImageInfosPointer() {
if (HasTaskDyldInfo()) {
@@ -475,8 +472,6 @@ void ReadImageInfo(DynamicImages& images,
mach_header_bytes) != KERN_SUCCESS)
continue;
- header = reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]);
-
// Read the file name from the task's memory space.
string file_path;
if (info.file_path_) {
@@ -492,7 +487,7 @@ void ReadImageInfo(DynamicImages& images,
header_size,
info.load_address_,
file_path,
- info.file_mod_date_,
+ static_cast<uintptr_t>(info.file_mod_date_),
images.task_,
images.cpu_type_);
@@ -568,7 +563,7 @@ cpu_type_t DynamicImages::DetermineTaskCPUType(task_t task) {
cpu_type_t cpu_type;
size_t cpuTypeSize = sizeof(cpu_type);
- sysctl(mib, mibLen, &cpu_type, &cpuTypeSize, 0, 0);
+ sysctl(mib, static_cast<u_int>(mibLen), &cpu_type, &cpuTypeSize, 0, 0);
return cpu_type;
}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h
index d039eda..6514790 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h
@@ -285,6 +285,8 @@ class DynamicImages {
return CPU_TYPE_POWERPC64;
#elif defined(__arm__)
return CPU_TYPE_ARM;
+#elif defined(__aarch64__)
+ return CPU_TYPE_ARM64;
#else
#error "GetNativeCPUType not implemented for this architecture"
#endif
diff --git a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc
index 4043019..2a19d46 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc
@@ -27,19 +27,32 @@
// (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 <map>
#include <mach/exc.h>
#include <mach/mig.h>
#include <pthread.h>
#include <signal.h>
#include <TargetConditionals.h>
+#include <map>
+
#include "client/mac/handler/exception_handler.h"
#include "client/mac/handler/minidump_generator.h"
#include "common/mac/macho_utilities.h"
#include "common/mac/scoped_task_suspend-inl.h"
#include "google_breakpad/common/minidump_exception_mac.h"
+#ifndef __EXCEPTIONS
+// This file uses C++ try/catch (but shouldn't). Duplicate the macros from
+// <c++/4.2.1/exception_defines.h> allowing this file to work properly with
+// exceptions disabled even when other C++ libraries are used. #undef the try
+// and catch macros first in case libstdc++ is in use and has already provided
+// its own definitions.
+#undef try
+#define try if (true)
+#undef catch
+#define catch(X) if (false)
+#endif // __EXCEPTIONS
+
#ifndef USE_PROTECTED_ALLOCATIONS
#if TARGET_OS_IPHONE
#define USE_PROTECTED_ALLOCATIONS 1
@@ -61,8 +74,12 @@ namespace google_breakpad {
static union {
#if USE_PROTECTED_ALLOCATIONS
+#if defined PAGE_MAX_SIZE
+ char protected_buffer[PAGE_MAX_SIZE] __attribute__((aligned(PAGE_MAX_SIZE)));
+#else
char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
-#endif
+#endif // defined PAGE_MAX_SIZE
+#endif // USE_PROTECTED_ALLOCATIONS
google_breakpad::ExceptionHandler *handler;
} gProtectedData;
@@ -103,14 +120,13 @@ exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |
EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;
#if !TARGET_OS_IPHONE
-extern "C"
-{
+extern "C" {
// Forward declarations for functions that need "C" style compilation
- boolean_t exc_server(mach_msg_header_t *request,
- mach_msg_header_t *reply);
+ boolean_t exc_server(mach_msg_header_t* request,
+ mach_msg_header_t* reply);
// This symbol must be visible to dlsym() - see
- // http://code.google.com/p/google-breakpad/issues/detail?id=345 for details.
+ // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=345 for details.
kern_return_t catch_exception_raise(mach_port_t target_port,
mach_port_t failed_thread,
mach_port_t task,
@@ -129,19 +145,19 @@ kern_return_t ForwardException(mach_port_t task,
#if TARGET_OS_IPHONE
// Implementation is based on the implementation generated by mig.
-boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
- mach_msg_header_t *OutHeadP) {
- OutHeadP->msgh_bits =
- MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0);
- OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port;
- /* Minimal size: routine() will update it if different */
- OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
- OutHeadP->msgh_local_port = MACH_PORT_NULL;
- OutHeadP->msgh_id = InHeadP->msgh_id + 100;
+boolean_t breakpad_exc_server(mach_msg_header_t* InHeadP,
+ mach_msg_header_t* OutHeadP) {
+ OutHeadP->msgh_bits =
+ MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0);
+ OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port;
+ /* Minimal size: routine() will update it if different */
+ OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
+ OutHeadP->msgh_local_port = MACH_PORT_NULL;
+ OutHeadP->msgh_id = InHeadP->msgh_id + 100;
if (InHeadP->msgh_id != 2401) {
- ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
- ((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
+ ((mig_reply_error_t*)OutHeadP)->NDR = NDR_record;
+ ((mig_reply_error_t*)OutHeadP)->RetCode = MIG_BAD_ID;
return FALSE;
}
@@ -171,8 +187,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
#pragma pack()
#endif
- Request *In0P = (Request *)InHeadP;
- Reply *OutP = (Reply *)OutHeadP;
+ Request* In0P = (Request*)InHeadP;
+ Reply* OutP = (Reply*)OutHeadP;
if (In0P->task.name != mach_task_self()) {
return FALSE;
@@ -186,8 +202,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
return TRUE;
}
#else
-boolean_t breakpad_exc_server(mach_msg_header_t *request,
- mach_msg_header_t *reply) {
+boolean_t breakpad_exc_server(mach_msg_header_t* request,
+ mach_msg_header_t* reply) {
return exc_server(request, reply);
}
@@ -207,9 +223,9 @@ kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
ExceptionHandler::ExceptionHandler(const string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler,
- const char *port_name)
+ const char* port_name)
: dump_path_(),
filter_(filter),
callback_(callback),
@@ -235,7 +251,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
// special constructor if we want to bypass minidump writing and
// simply get a callback with the exception information
ExceptionHandler::ExceptionHandler(DirectCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler)
: dump_path_(),
filter_(NULL),
@@ -269,9 +285,13 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
if (pthread_mutex_lock(&minidump_write_mutex_) == 0) {
// Send an empty message to the handle port so that a minidump will
// be written
- SendMessageToHandlerThread(write_exception_stream ?
- kWriteDumpWithExceptionMessage :
- kWriteDumpMessage);
+ bool result = SendMessageToHandlerThread(write_exception_stream ?
+ kWriteDumpWithExceptionMessage :
+ kWriteDumpMessage);
+ if (!result) {
+ pthread_mutex_unlock(&minidump_write_mutex_);
+ return false;
+ }
// Wait for the minidump writer to complete its writing. It will unlock
// the mutex when completed
@@ -287,18 +307,18 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
bool ExceptionHandler::WriteMinidump(const string &dump_path,
bool write_exception_stream,
MinidumpCallback callback,
- void *callback_context) {
+ void* callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false,
- NULL);
+ NULL);
return handler.WriteMinidump(write_exception_stream);
}
// static
bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
- mach_port_t child_blamed_thread,
- const string &dump_path,
- MinidumpCallback callback,
- void *callback_context) {
+ mach_port_t child_blamed_thread,
+ const string &dump_path,
+ MinidumpCallback callback,
+ void* callback_context) {
ScopedTaskSuspend suspend(child);
MinidumpGenerator generator(child, MACH_PORT_NULL);
@@ -306,34 +326,41 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id);
generator.SetExceptionInformation(EXC_BREAKPOINT,
-#if defined (__i386__) || defined(__x86_64__)
- EXC_I386_BPT,
-#elif defined (__ppc__) || defined (__ppc64__)
- EXC_PPC_BREAKPOINT,
-#elif defined (__arm__)
- EXC_ARM_BREAKPOINT,
+#if defined(__i386__) || defined(__x86_64__)
+ EXC_I386_BPT,
+#elif defined(__ppc__) || defined(__ppc64__)
+ EXC_PPC_BREAKPOINT,
+#elif defined(__arm__) || defined(__aarch64__)
+ EXC_ARM_BREAKPOINT,
#else
#error architecture not supported
#endif
- 0,
- child_blamed_thread);
+ 0,
+ child_blamed_thread);
bool result = generator.Write(dump_filename.c_str());
if (callback) {
return callback(dump_path.c_str(), dump_id.c_str(),
- callback_context, result);
+ callback_context, result);
}
return result;
}
-bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
- int exception_code,
- int exception_subcode,
- mach_port_t thread_name,
- bool exit_after_write,
- bool report_current_thread) {
+bool ExceptionHandler::WriteMinidumpWithException(
+ int exception_type,
+ int exception_code,
+ int exception_subcode,
+ breakpad_ucontext_t* task_context,
+ mach_port_t thread_name,
+ bool exit_after_write,
+ bool report_current_thread) {
bool result = false;
+#if TARGET_OS_IPHONE
+ // _exit() should never be called on iOS.
+ exit_after_write = false;
+#endif
+
if (directCallback_) {
if (directCallback_(callback_context_,
exception_type,
@@ -349,12 +376,15 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
// If this is a real exception, give the filter (if any) a chance to
// decide if this should be sent.
if (filter_ && !filter_(callback_context_))
- return false;
- return crash_generation_client_->RequestDumpForException(
- exception_type,
- exception_code,
- exception_subcode,
- thread_name);
+ return false;
+ result = crash_generation_client_->RequestDumpForException(
+ exception_type,
+ exception_code,
+ exception_subcode,
+ thread_name);
+ if (result && exit_after_write) {
+ _exit(exception_type);
+ }
}
#endif
} else {
@@ -366,6 +396,7 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
MinidumpGenerator md(mach_task_self(),
report_current_thread ? MACH_PORT_NULL :
mach_thread_self());
+ md.SetTaskContext(task_context);
if (exception_type && exception_code) {
// If this is a real exception, give the filter (if any) a chance to
// decide if this should be sent.
@@ -432,12 +463,13 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
exception_behavior_t target_behavior = current.behaviors[found];
kern_return_t result;
+ // TODO: Handle the case where |target_behavior| has MACH_EXCEPTION_CODES
+ // set. https://bugs.chromium.org/p/google-breakpad/issues/detail?id=551
switch (target_behavior) {
case EXCEPTION_DEFAULT:
result = exception_raise(target_port, failed_thread, task, exception,
code, code_count);
break;
-
default:
fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior);
result = KERN_FAILURE;
@@ -448,9 +480,9 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
}
// static
-void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
- ExceptionHandler *self =
- reinterpret_cast<ExceptionHandler *>(exception_handler_class);
+void* ExceptionHandler::WaitForMessage(void* exception_handler_class) {
+ ExceptionHandler* self =
+ reinterpret_cast<ExceptionHandler*>(exception_handler_class);
ExceptionMessage receive;
// Wait for the exception info
@@ -495,11 +527,11 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) {
thread = receive.thread.name;
exception_type = EXC_BREAKPOINT;
-#if defined (__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__)
exception_code = EXC_I386_BPT;
-#elif defined (__ppc__) || defined (__ppc64__)
+#elif defined(__ppc__) || defined(__ppc64__)
exception_code = EXC_PPC_BREAKPOINT;
-#elif defined (__arm__)
+#elif defined(__arm__) || defined(__aarch64__)
exception_code = EXC_ARM_BREAKPOINT;
#else
#error architecture not supported
@@ -509,7 +541,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// Write out the dump and save the result for later retrieval
self->last_minidump_write_result_ =
self->WriteMinidumpWithException(exception_type, exception_code,
- 0, thread,
+ 0, NULL, thread,
false, false);
#if USE_PROTECTED_ALLOCATIONS
@@ -544,8 +576,8 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// Generate the minidump with the exception data.
self->WriteMinidumpWithException(receive.exception, receive.code[0],
- subcode, receive.thread.name, true,
- false);
+ subcode, NULL, receive.thread.name,
+ true, false);
#if USE_PROTECTED_ALLOCATIONS
// This may have become protected again within
@@ -580,7 +612,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
return NULL;
}
-//static
+// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
#if USE_PROTECTED_ALLOCATIONS
if (gBreakpadAllocator)
@@ -590,6 +622,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
EXC_SOFTWARE,
MD_EXCEPTION_CODE_MAC_ABORT,
0,
+ static_cast<breakpad_ucontext_t*>(uc),
mach_thread_self(),
true,
true);
@@ -604,7 +637,6 @@ bool ExceptionHandler::InstallHandler() {
if (gProtectedData.handler != NULL) {
return false;
}
-#if TARGET_OS_IPHONE
if (!IsOutOfProcess()) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
@@ -624,7 +656,6 @@ bool ExceptionHandler::InstallHandler() {
mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ);
#endif
}
-#endif
try {
#if USE_PROTECTED_ALLOCATIONS
@@ -633,7 +664,6 @@ bool ExceptionHandler::InstallHandler() {
#else
previous_ = new ExceptionParameters();
#endif
-
}
catch (std::bad_alloc) {
return false;
@@ -732,7 +762,7 @@ bool ExceptionHandler::Setup(bool install_handler) {
result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS;
}
- return result == KERN_SUCCESS ? true : false;
+ return result == KERN_SUCCESS;
}
bool ExceptionHandler::Teardown() {
diff --git a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h
index ec09134..f1d9ae9 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h
@@ -41,7 +41,8 @@
#include <string>
-#include "processor/scoped_ptr.h"
+#include "client/mac/handler/ucontext_compat.h"
+#include "common/scoped_ptr.h"
#if !TARGET_OS_IPHONE
#include "client/mac/crash_generation/crash_generation_client.h"
@@ -182,10 +183,13 @@ class ExceptionHandler {
// success, false otherwise.
bool SendMessageToHandlerThread(HandlerThreadMessage message_id);
- // All minidump writing goes through this one routine
+ // All minidump writing goes through this one routine.
+ // |task_context| can be NULL. If not, it will be used to retrieve the
+ // context of the current thread, instead of using |thread_get_state|.
bool WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
+ breakpad_ucontext_t *task_context,
mach_port_t thread_name,
bool exit_after_write,
bool report_current_thread);
diff --git a/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h b/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h
index e0459be..9e9028b 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h
@@ -32,15 +32,14 @@
#include <TargetConditionals.h>
-// On iOS 5, mach/mach_vm.h is not supported anymore. As the architecture is 32
-// bits, we can use the simple vm_ functions instead of the mach_vm_ ones.
+// On iOS 5 and higher, mach/mach_vm.h is not supported. Use the corresponding
+// vm_map functions instead.
#if TARGET_OS_IPHONE
#include <mach/vm_map.h>
#define mach_vm_address_t vm_address_t
#define mach_vm_deallocate vm_deallocate
#define mach_vm_read vm_read
-#define mach_vm_region vm_region
-#define mach_vm_region_recurse vm_region_recurse
+#define mach_vm_region_recurse vm_region_recurse_64
#define mach_vm_size_t vm_size_t
#else
#include <mach/mach_vm.h>
diff --git a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc
index b1d429c..48cd2e9 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc
@@ -31,6 +31,7 @@
#include <cstdio>
#include <mach/host_info.h>
+#include <mach/machine.h>
#include <mach/vm_statistics.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
@@ -41,7 +42,7 @@
#include "client/mac/handler/minidump_generator.h"
-#ifdef HAS_ARM_SUPPORT
+#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
#include <mach/arm/thread_status.h>
#endif
#ifdef HAS_PPC_SUPPORT
@@ -61,7 +62,7 @@ using MacStringUtils::IntegerValueAtIndex;
namespace google_breakpad {
-#if __LP64__
+#if defined(__LP64__) && __LP64__
#define LC_SEGMENT_ARCH LC_SEGMENT_64
#else
#define LC_SEGMENT_ARCH LC_SEGMENT
@@ -77,6 +78,7 @@ MinidumpGenerator::MinidumpGenerator()
crashing_task_(mach_task_self()),
handler_thread_(mach_thread_self()),
cpu_type_(DynamicImages::GetNativeCPUType()),
+ task_context_(NULL),
dynamic_images_(NULL),
memory_blocks_(&allocator_) {
GatherSystemInformation();
@@ -94,6 +96,7 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,
crashing_task_(crashing_task),
handler_thread_(handler_thread),
cpu_type_(DynamicImages::GetNativeCPUType()),
+ task_context_(NULL),
dynamic_images_(NULL),
memory_blocks_(&allocator_) {
if (crashing_task != mach_task_self()) {
@@ -130,25 +133,47 @@ void MinidumpGenerator::GatherSystemInformation() {
vers_path,
kCFURLPOSIXPathStyle,
false);
- CFDataRef data;
- SInt32 error;
- CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL,
- &error);
-
+ CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers);
+ CFRelease(sys_vers);
+ if (!read_stream) {
+ return;
+ }
+ if (!CFReadStreamOpen(read_stream)) {
+ CFRelease(read_stream);
+ return;
+ }
+ CFMutableDataRef data = NULL;
+ while (true) {
+ // Actual data file tests: Mac at 480 bytes and iOS at 413 bytes.
+ const CFIndex kMaxBufferLength = 1024;
+ UInt8 data_bytes[kMaxBufferLength];
+ CFIndex num_bytes_read =
+ CFReadStreamRead(read_stream, data_bytes, kMaxBufferLength);
+ if (num_bytes_read < 0) {
+ if (data) {
+ CFRelease(data);
+ data = NULL;
+ }
+ break;
+ } else if (num_bytes_read == 0) {
+ break;
+ } else if (!data) {
+ data = CFDataCreateMutable(NULL, 0);
+ }
+ CFDataAppendBytes(data, data_bytes, num_bytes_read);
+ }
+ CFReadStreamClose(read_stream);
+ CFRelease(read_stream);
if (!data) {
- CFRelease(sys_vers);
return;
}
-
- CFDictionaryRef list = static_cast<CFDictionaryRef>
- (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
- NULL));
+ CFDictionaryRef list =
+ static_cast<CFDictionaryRef>(CFPropertyListCreateWithData(
+ NULL, data, kCFPropertyListImmutable, NULL, NULL));
+ CFRelease(data);
if (!list) {
- CFRelease(sys_vers);
- CFRelease(data);
return;
}
-
CFStringRef build_version = static_cast<CFStringRef>
(CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
CFStringRef product_version = static_cast<CFStringRef>
@@ -157,8 +182,6 @@ void MinidumpGenerator::GatherSystemInformation() {
string product_str = ConvertToString(product_version);
CFRelease(list);
- CFRelease(sys_vers);
- CFRelease(data);
strlcpy(build_string_, build_str.c_str(), sizeof(build_string_));
@@ -168,6 +191,10 @@ void MinidumpGenerator::GatherSystemInformation() {
os_build_number_ = IntegerValueAtIndex(product_str, 2);
}
+void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) {
+ task_context_ = task_context;
+}
+
string MinidumpGenerator::UniqueNameInDirectory(const string &dir,
string *unique_name) {
CFUUIDRef uuid = CFUUIDCreate(NULL);
@@ -288,7 +315,7 @@ size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {
mach_vm_address_t proposed_next_region_base = next_region_base;
mach_vm_size_t next_region_size;
nesting_level = 0;
- mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
+ info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
result = mach_vm_region_recurse(crashing_task_, &next_region_base,
&next_region_size, &nesting_level,
region_info, &info_count);
@@ -362,6 +389,10 @@ bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
case CPU_TYPE_ARM:
return WriteStackARM(state, stack_location);
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ return WriteStackARM64(state, stack_location);
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
return WriteStackPPC(state, stack_location);
@@ -386,6 +417,10 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
case CPU_TYPE_ARM:
return WriteContextARM(state, register_location);
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ return WriteContextARM64(state, register_location);
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
return WriteContextPPC(state, register_location);
@@ -403,13 +438,17 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
}
}
-u_int64_t MinidumpGenerator::CurrentPCForStack(
+uint64_t MinidumpGenerator::CurrentPCForStack(
breakpad_thread_state_data_t state) {
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
case CPU_TYPE_ARM:
return CurrentPCForStackARM(state);
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ return CurrentPCForStackARM64(state);
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
return CurrentPCForStackPPC(state);
@@ -423,7 +462,7 @@ u_int64_t MinidumpGenerator::CurrentPCForStack(
return CurrentPCForStackX86_64(state);
#endif
default:
- assert("Unknown CPU type!");
+ assert(0 && "Unknown CPU type!");
return 0;
}
}
@@ -437,7 +476,7 @@ bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state,
return WriteStackFromStartAddress(start_addr, stack_location);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) {
arm_thread_state_t *machine_state =
reinterpret_cast<arm_thread_state_t *>(state);
@@ -479,7 +518,82 @@ bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,
AddGPR(10);
AddGPR(11);
AddGPR(12);
-#undef AddReg
+#undef AddGPR
+
+ return true;
+}
+#endif
+
+#ifdef HAS_ARM64_SUPPORT
+bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state,
+ MDMemoryDescriptor *stack_location) {
+ arm_thread_state64_t *machine_state =
+ reinterpret_cast<arm_thread_state64_t *>(state);
+ mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
+ return WriteStackFromStartAddress(start_addr, stack_location);
+}
+
+uint64_t
+MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) {
+ arm_thread_state64_t *machine_state =
+ reinterpret_cast<arm_thread_state64_t *>(state);
+
+ return REGISTER_FROM_THREADSTATE(machine_state, pc);
+}
+
+bool
+MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location)
+{
+ TypedMDRVA<MDRawContextARM64> context(&writer_);
+ arm_thread_state64_t *machine_state =
+ reinterpret_cast<arm_thread_state64_t *>(state);
+
+ if (!context.Allocate())
+ return false;
+
+ *register_location = context.location();
+ MDRawContextARM64 *context_ptr = context.get();
+ context_ptr->context_flags = MD_CONTEXT_ARM64_FULL;
+
+#define AddGPR(a) context_ptr->iregs[a] = \
+ REGISTER_FROM_THREADSTATE(machine_state, x[a])
+
+ context_ptr->iregs[29] = REGISTER_FROM_THREADSTATE(machine_state, fp);
+ context_ptr->iregs[30] = REGISTER_FROM_THREADSTATE(machine_state, lr);
+ context_ptr->iregs[31] = REGISTER_FROM_THREADSTATE(machine_state, sp);
+ context_ptr->iregs[32] = REGISTER_FROM_THREADSTATE(machine_state, pc);
+ context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr);
+
+ AddGPR(0);
+ AddGPR(1);
+ AddGPR(2);
+ AddGPR(3);
+ AddGPR(4);
+ AddGPR(5);
+ AddGPR(6);
+ AddGPR(7);
+ AddGPR(8);
+ AddGPR(9);
+ AddGPR(10);
+ AddGPR(11);
+ AddGPR(12);
+ AddGPR(13);
+ AddGPR(14);
+ AddGPR(15);
+ AddGPR(16);
+ AddGPR(17);
+ AddGPR(18);
+ AddGPR(19);
+ AddGPR(20);
+ AddGPR(21);
+ AddGPR(22);
+ AddGPR(23);
+ AddGPR(24);
+ AddGPR(25);
+ AddGPR(26);
+ AddGPR(27);
+ AddGPR(28);
#undef AddGPR
return true;
@@ -503,7 +617,7 @@ bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state,
return WriteStackFromStartAddress(start_addr, stack_location);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
ppc_thread_state_t *machine_state =
reinterpret_cast<ppc_thread_state_t *>(state);
@@ -511,7 +625,7 @@ MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
return REGISTER_FROM_THREADSTATE(machine_state, srr0);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) {
ppc_thread_state64_t *machine_state =
reinterpret_cast<ppc_thread_state64_t *>(state);
@@ -533,8 +647,11 @@ bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,
MDRawContextPPC *context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
-#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
+#define AddGPR(a) context_ptr->gpr[a] = \
+ static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, r ## a)
AddReg(srr0);
AddReg(cr);
@@ -596,8 +713,11 @@ bool MinidumpGenerator::WriteContextPPC64(
MDRawContextPPC64 *context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
-#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
+#define AddGPR(a) context_ptr->gpr[a] = \
+ static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, r ## a)
AddReg(srr0);
AddReg(cr);
@@ -661,11 +781,12 @@ bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,
x86_thread_state64_t *machine_state =
reinterpret_cast<x86_thread_state64_t *>(state);
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp);
+ mach_vm_address_t start_addr = static_cast<mach_vm_address_t>(
+ REGISTER_FROM_THREADSTATE(machine_state, rsp));
return WriteStackFromStartAddress(start_addr, stack_location);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
i386_thread_state_t *machine_state =
reinterpret_cast<i386_thread_state_t *>(state);
@@ -673,7 +794,7 @@ MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
return REGISTER_FROM_THREADSTATE(machine_state, eip);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) {
x86_thread_state64_t *machine_state =
reinterpret_cast<x86_thread_state64_t *>(state);
@@ -694,7 +815,8 @@ bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,
*register_location = context.location();
MDRawContextX86 *context_ptr = context.get();
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
context_ptr->context_flags = MD_CONTEXT_X86;
AddReg(eax);
@@ -733,7 +855,8 @@ bool MinidumpGenerator::WriteContextX86_64(
*register_location = context.location();
MDRawContextAMD64 *context_ptr = context.get();
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
context_ptr->context_flags = MD_CONTEXT_AMD64;
AddReg(rax);
@@ -757,7 +880,7 @@ bool MinidumpGenerator::WriteContextX86_64(
// not used in the flags register. Since the minidump format
// specifies 32 bits for the flags register, we can truncate safely
// with no loss.
- context_ptr->eflags = static_cast<u_int32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));
+ context_ptr->eflags = static_cast<uint32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));
AddReg(cs);
AddReg(fs);
AddReg(gs);
@@ -770,6 +893,40 @@ bool MinidumpGenerator::WriteContextX86_64(
bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
thread_state_t state,
mach_msg_type_number_t *count) {
+ if (task_context_ && target_thread == mach_thread_self()) {
+ switch (cpu_type_) {
+#ifdef HAS_ARM_SUPPORT
+ case CPU_TYPE_ARM:
+ size_t final_size =
+ std::min(static_cast<size_t>(*count), sizeof(arm_thread_state_t));
+ memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
+ *count = static_cast<mach_msg_type_number_t>(final_size);
+ return true;
+#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64: {
+ size_t final_size =
+ std::min(static_cast<size_t>(*count), sizeof(arm_thread_state64_t));
+ memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
+ *count = static_cast<mach_msg_type_number_t>(final_size);
+ return true;
+ }
+#endif
+#ifdef HAS_X86_SUPPORT
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64: {
+ size_t state_size = cpu_type_ == CPU_TYPE_I386 ?
+ sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t);
+ size_t final_size =
+ std::min(static_cast<size_t>(*count), state_size);
+ memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
+ *count = static_cast<mach_msg_type_number_t>(final_size);
+ return true;
+ }
+#endif
+ }
+ }
+
thread_state_flavor_t flavor;
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
@@ -777,6 +934,11 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
flavor = ARM_THREAD_STATE;
break;
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ flavor = ARM_THREAD_STATE64;
+ break;
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
flavor = PPC_THREAD_STATE;
@@ -878,26 +1040,25 @@ bool MinidumpGenerator::WriteMemoryListStream(
mach_msg_type_number_t stateCount
= static_cast<mach_msg_type_number_t>(sizeof(state));
- if (thread_get_state(exception_thread_,
- BREAKPAD_MACHINE_THREAD_STATE,
- state,
- &stateCount) == KERN_SUCCESS) {
- u_int64_t ip = CurrentPCForStack(state);
+ if (GetThreadState(exception_thread_, state, &stateCount)) {
+ uint64_t ip = CurrentPCForStack(state);
// Bound it to the upper and lower bounds of the region
// it's contained within. If it's not in a known memory region,
// don't bother trying to write it.
- mach_vm_address_t addr = ip;
+ mach_vm_address_t addr = static_cast<vm_address_t>(ip);
mach_vm_size_t size;
natural_t nesting_level = 0;
vm_region_submap_info_64 info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
+ vm_region_recurse_info_t recurse_info;
+ recurse_info = reinterpret_cast<vm_region_recurse_info_t>(&info);
kern_return_t ret =
mach_vm_region_recurse(crashing_task_,
&addr,
&size,
&nesting_level,
- (vm_region_recurse_info_t)&info,
+ recurse_info,
&info_count);
if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) {
// Try to get 128 bytes before and after the IP, but
@@ -908,8 +1069,9 @@ bool MinidumpGenerator::WriteMemoryListStream(
uintptr_t end_of_range =
std::min(uintptr_t(ip + (kIPMemorySize / 2)),
uintptr_t(addr + size));
- ip_memory_d.memory.data_size =
- end_of_range - ip_memory_d.start_of_memory_range;
+ uintptr_t range_diff = end_of_range -
+ static_cast<uintptr_t>(ip_memory_d.start_of_memory_range);
+ ip_memory_d.memory.data_size = static_cast<uint32_t>(range_diff);
have_ip_memory = true;
// This needs to get appended to the list even though
// the memory bytes aren't filled in yet so the entire
@@ -921,7 +1083,7 @@ bool MinidumpGenerator::WriteMemoryListStream(
}
// Now fill in the memory list and write it.
- unsigned memory_count = memory_blocks_.size();
+ size_t memory_count = memory_blocks_.size();
if (!list.AllocateObjectAndArray(memory_count,
sizeof(MDMemoryDescriptor)))
return false;
@@ -929,7 +1091,7 @@ bool MinidumpGenerator::WriteMemoryListStream(
memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM;
memory_list_stream->location = list.location();
- list.get()->number_of_memory_ranges = memory_count;
+ list.get()->number_of_memory_ranges = static_cast<uint32_t>(memory_count);
unsigned int i;
for (i = 0; i < memory_count; ++i) {
@@ -1027,6 +1189,11 @@ bool MinidumpGenerator::WriteSystemInfoStream(
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM;
break;
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64;
+ break;
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
case CPU_TYPE_POWERPC64:
@@ -1078,9 +1245,9 @@ bool MinidumpGenerator::WriteSystemInfoStream(
info_ptr->processor_level =
(info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8;
// 0xMMSS (Model, Stepping)
- info_ptr->processor_revision =
- (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
- ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4);
+ info_ptr->processor_revision = static_cast<uint16_t>(
+ (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
+ ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4));
// decode extended model info
if (info_ptr->processor_level == 0xF ||
@@ -1103,7 +1270,7 @@ bool MinidumpGenerator::WriteSystemInfoStream(
break;
}
- info_ptr->number_of_processors = number_of_processors;
+ info_ptr->number_of_processors = static_cast<uint8_t>(number_of_processors);
#if TARGET_OS_IPHONE
info_ptr->platform_id = MD_OS_IOS;
#else
@@ -1142,13 +1309,13 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
return false;
module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide();
- module->size_of_image = static_cast<u_int32_t>(image->GetVMSize());
+ module->size_of_image = static_cast<uint32_t>(image->GetVMSize());
module->module_name_rva = string_location.rva;
// We'll skip the executable module, because they don't have
// LC_ID_DYLIB load commands, and the crash processing server gets
// version information from the Plist file, anyway.
- if (index != (uint32_t)FindExecutableModule()) {
+ if (index != static_cast<uint32_t>(FindExecutableModule())) {
module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;
module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;
// Convert MAC dylib version format, which is a 32 bit number, to the
@@ -1208,7 +1375,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
return false;
module->base_of_image = seg->vmaddr + slide;
- module->size_of_image = static_cast<u_int32_t>(seg->vmsize);
+ module->size_of_image = static_cast<uint32_t>(seg->vmsize);
module->module_name_rva = string_location.rva;
bool in_memory = false;
@@ -1267,7 +1434,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
size_t module_name_length = strlen(module_name);
- if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
+ if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_t)))
return false;
if (!cv.CopyIndexAfterObject(0, module_name, module_name_length))
@@ -1285,22 +1452,27 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
MacFileUtilities::MachoID macho(module_path,
reinterpret_cast<void *>(module->base_of_image),
static_cast<size_t>(module->size_of_image));
- result = macho.UUIDCommand(cpu_type, identifier);
+ result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
if (!result)
- result = macho.MD5(cpu_type, identifier);
+ result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
}
if (!result) {
FileID file_id(module_path);
- result = file_id.MachoIdentifier(cpu_type, identifier);
+ result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE,
+ identifier);
}
if (result) {
- cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
- (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 |
- (uint32_t)identifier[3];
- cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5];
- cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7];
+ cv_ptr->signature.data1 =
+ static_cast<uint32_t>(identifier[0]) << 24 |
+ static_cast<uint32_t>(identifier[1]) << 16 |
+ static_cast<uint32_t>(identifier[2]) << 8 |
+ static_cast<uint32_t>(identifier[3]);
+ cv_ptr->signature.data2 =
+ static_cast<uint16_t>(identifier[4] << 8) | identifier[5];
+ cv_ptr->signature.data3 =
+ static_cast<uint16_t>(identifier[6] << 8) | identifier[7];
cv_ptr->signature.data4[0] = identifier[8];
cv_ptr->signature.data4[1] = identifier[9];
cv_ptr->signature.data4[2] = identifier[10];
@@ -1318,8 +1490,8 @@ bool MinidumpGenerator::WriteModuleListStream(
MDRawDirectory *module_list_stream) {
TypedMDRVA<MDRawModuleList> list(&writer_);
- size_t image_count = dynamic_images_ ?
- static_cast<size_t>(dynamic_images_->GetImageCount()) :
+ uint32_t image_count = dynamic_images_ ?
+ dynamic_images_->GetImageCount() :
_dyld_image_count();
if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE))
@@ -1327,22 +1499,22 @@ bool MinidumpGenerator::WriteModuleListStream(
module_list_stream->stream_type = MD_MODULE_LIST_STREAM;
module_list_stream->location = list.location();
- list.get()->number_of_modules = image_count;
+ list.get()->number_of_modules = static_cast<uint32_t>(image_count);
// Write out the executable module as the first one
MDRawModule module;
- size_t executableIndex = FindExecutableModule();
+ uint32_t executableIndex = FindExecutableModule();
- if (!WriteModuleStream(executableIndex, &module)) {
+ if (!WriteModuleStream(static_cast<unsigned>(executableIndex), &module)) {
return false;
}
list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);
int destinationIndex = 1; // Write all other modules after this one
- for (size_t i = 0; i < image_count; ++i) {
+ for (uint32_t i = 0; i < image_count; ++i) {
if (i != executableIndex) {
- if (!WriteModuleStream(i, &module)) {
+ if (!WriteModuleStream(static_cast<unsigned>(i), &module)) {
return false;
}
@@ -1363,7 +1535,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
misc_info_stream->location = info.location();
MDRawMiscInfo *info_ptr = info.get();
- info_ptr->size_of_info = static_cast<u_int32_t>(sizeof(MDRawMiscInfo));
+ info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo));
info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID |
MD_MISCINFO_FLAGS1_PROCESS_TIMES |
MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO;
@@ -1376,18 +1548,18 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
if (getrusage(RUSAGE_SELF, &usage) != -1) {
// Omit the fractional time since the MDRawMiscInfo only wants seconds
info_ptr->process_user_time =
- static_cast<u_int32_t>(usage.ru_utime.tv_sec);
+ static_cast<uint32_t>(usage.ru_utime.tv_sec);
info_ptr->process_kernel_time =
- static_cast<u_int32_t>(usage.ru_stime.tv_sec);
+ static_cast<uint32_t>(usage.ru_stime.tv_sec);
}
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
static_cast<int>(info_ptr->process_id) };
- u_int mibsize = static_cast<u_int>(sizeof(mib) / sizeof(mib[0]));
+ uint mibsize = static_cast<uint>(sizeof(mib) / sizeof(mib[0]));
struct kinfo_proc proc;
size_t size = sizeof(proc);
if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) {
info_ptr->process_create_time =
- static_cast<u_int32_t>(proc.kp_proc.p_starttime.tv_sec);
+ static_cast<uint32_t>(proc.kp_proc.p_starttime.tv_sec);
}
// Speed
@@ -1395,11 +1567,11 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
const uint64_t kOneMillion = 1000 * 1000;
size = sizeof(speed);
sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0);
- info_ptr->processor_max_mhz = static_cast<u_int32_t>(speed / kOneMillion);
- info_ptr->processor_mhz_limit = static_cast<u_int32_t>(speed / kOneMillion);
+ info_ptr->processor_max_mhz = static_cast<uint32_t>(speed / kOneMillion);
+ info_ptr->processor_mhz_limit = static_cast<uint32_t>(speed / kOneMillion);
size = sizeof(speed);
sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0);
- info_ptr->processor_current_mhz = static_cast<u_int32_t>(speed / kOneMillion);
+ info_ptr->processor_current_mhz = static_cast<uint32_t>(speed / kOneMillion);
return true;
}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h
index 8394ce6..4e4b4a6 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h
@@ -37,6 +37,7 @@
#include <string>
+#include "client/mac/handler/ucontext_compat.h"
#include "client/minidump_file_writer.h"
#include "common/memory.h"
#include "common/mac/macho_utilities.h"
@@ -49,7 +50,9 @@
#define HAS_PPC_SUPPORT
#endif
#if defined(__arm__)
- #define HAS_ARM_SUPPORT
+#define HAS_ARM_SUPPORT
+#elif defined(__aarch64__)
+#define HAS_ARM64_SUPPORT
#elif defined(__i386__) || defined(__x86_64__)
#define HAS_X86_SUPPORT
#endif
@@ -102,6 +105,11 @@ class MinidumpGenerator {
exception_thread_ = thread_name;
}
+ // Specify the task context. If |task_context| is not NULL, it will be used
+ // to retrieve the context of the current thread, instead of using
+ // |thread_get_state|.
+ void SetTaskContext(breakpad_ucontext_t *task_context);
+
// Gather system information. This should be call at least once before using
// the MinidumpGenerator class.
static void GatherSystemInformation();
@@ -125,7 +133,7 @@ class MinidumpGenerator {
bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream);
// Helpers
- u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStack(breakpad_thread_state_data_t state);
bool GetThreadState(thread_act_t target_thread, thread_state_t state,
mach_msg_type_number_t *count);
bool WriteStackFromStartAddress(mach_vm_address_t start_addr,
@@ -146,31 +154,38 @@ class MinidumpGenerator {
MDMemoryDescriptor *stack_location);
bool WriteContextARM(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
+#endif
+#ifdef HAS_ARM64_SUPPORT
+ bool WriteStackARM64(breakpad_thread_state_data_t state,
+ MDMemoryDescriptor *stack_location);
+ bool WriteContextARM64(breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location);
+ uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_PPC_SUPPORT
bool WriteStackPPC(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
bool WriteStackPPC64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_X86_SUPPORT
bool WriteStackX86(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
bool WriteStackX86_64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86_64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
#endif
// disallow copy ctor and operator=
@@ -192,13 +207,16 @@ class MinidumpGenerator {
// CPU type of the task being dumped.
cpu_type_t cpu_type_;
-
+
// System information
static char build_string_[16];
static int os_major_version_;
static int os_minor_version_;
static int os_build_number_;
-
+
+ // Context of the task to dump.
+ breakpad_ucontext_t *task_context_;
+
// Information about dynamically loaded code
DynamicImages *dynamic_images_;
diff --git a/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc
new file mode 100644
index 0000000..6142ad1
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// 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.
+//
+// ProtectedMemoryAllocator
+//
+// See the header file for documentation
+
+#include "protected_memory_allocator.h"
+#include <assert.h>
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ProtectedMemoryAllocator::ProtectedMemoryAllocator(vm_size_t pool_size)
+ : pool_size_(pool_size),
+ next_alloc_offset_(0),
+ valid_(false) {
+
+ kern_return_t result = vm_allocate(mach_task_self(),
+ &base_address_,
+ pool_size,
+ TRUE
+ );
+
+ valid_ = (result == KERN_SUCCESS);
+ assert(valid_);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ProtectedMemoryAllocator::~ProtectedMemoryAllocator() {
+ vm_deallocate(mach_task_self(),
+ base_address_,
+ pool_size_
+ );
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+char *ProtectedMemoryAllocator::Allocate(vm_size_t bytes) {
+ if (valid_ && next_alloc_offset_ + bytes <= pool_size_) {
+ char *p = (char*)base_address_ + next_alloc_offset_;
+ next_alloc_offset_ += bytes;
+ return p;
+ }
+
+ return NULL; // ran out of memory in our allocation block
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+kern_return_t ProtectedMemoryAllocator::Protect() {
+ kern_return_t result = vm_protect(mach_task_self(),
+ base_address_,
+ pool_size_,
+ FALSE,
+ VM_PROT_READ);
+
+ return result;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+kern_return_t ProtectedMemoryAllocator::Unprotect() {
+ kern_return_t result = vm_protect(mach_task_self(),
+ base_address_,
+ pool_size_,
+ FALSE,
+ VM_PROT_READ | VM_PROT_WRITE);
+
+ return result;
+}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h
new file mode 100644
index 0000000..7e188db
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// 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.
+//
+// ProtectedMemoryAllocator
+//
+// A very simple allocator class which allows allocation, but not deallocation.
+// The allocations can be made read-only with the Protect() method.
+// This class is NOT useful as a general-purpose memory allocation system,
+// since it does not allow deallocation. It is useful to use for a group
+// of allocations which are created in the same time-frame and destroyed
+// in the same time-frame. It is useful for making allocations of memory
+// which will not need to change often once initialized. This memory can then
+// be protected from memory smashers by calling the Protect() method.
+
+#ifndef PROTECTED_MEMORY_ALLOCATOR_H__
+#define PROTECTED_MEMORY_ALLOCATOR_H__
+
+#include <mach/mach.h>
+
+//
+class ProtectedMemoryAllocator {
+ public:
+ ProtectedMemoryAllocator(vm_size_t pool_size);
+ ~ProtectedMemoryAllocator();
+
+ // Returns a pointer to an allocation of size n within the pool.
+ // Fails by returning NULL is no more space is available.
+ // Please note that the pointers returned from this method should not
+ // be freed in any way (for example by calling free() on them ).
+ char * Allocate(vm_size_t n);
+
+ // Returns the base address of the allocation pool.
+ char * GetBaseAddress() { return (char*)base_address_; }
+
+ // Returns the size of the allocation pool, including allocated
+ // plus free space.
+ vm_size_t GetTotalSize() { return pool_size_; }
+
+ // Returns the number of bytes already allocated in the pool.
+ vm_size_t GetAllocatedSize() { return next_alloc_offset_; }
+
+ // Returns the number of bytes available for allocation.
+ vm_size_t GetFreeSize() { return pool_size_ - next_alloc_offset_; }
+
+ // Makes the entire allocation pool read-only including, of course,
+ // all allocations made from the pool.
+ kern_return_t Protect();
+
+ // Makes the entire allocation pool read/write.
+ kern_return_t Unprotect();
+
+ private:
+ vm_size_t pool_size_;
+ vm_address_t base_address_;
+ vm_size_t next_alloc_offset_;
+ bool valid_;
+};
+
+#endif // PROTECTED_MEMORY_ALLOCATOR_H__
diff --git a/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h b/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h
new file mode 100644
index 0000000..1e4b752
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h
@@ -0,0 +1,47 @@
+// Copyright 2013 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// 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.
+
+#ifndef CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_
+#define CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_
+
+#include <sys/ucontext.h>
+
+// The purpose of this file is to work around the fact that ucontext_t's
+// uc_mcontext member is an mcontext_t rather than an mcontext64_t on ARM64.
+#if defined(__aarch64__)
+// <sys/ucontext.h> doesn't include the below file.
+#include <sys/_types/_ucontext64.h>
+typedef ucontext64_t breakpad_ucontext_t;
+#define breakpad_uc_mcontext uc_mcontext64
+#else
+typedef ucontext_t breakpad_ucontext_t;
+#define breakpad_uc_mcontext uc_mcontext
+#endif // defined(__aarch64__)
+
+#endif // CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_