diff options
Diffstat (limited to '3rdParty/Breakpad/src/client/mac/handler')
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_ |