From 5f57e963d04bf7552d0939725c43c4806a05808f Mon Sep 17 00:00:00 2001 From: "qsr@chromium.org" Date: Mon, 20 Aug 2012 13:42:09 +0000 Subject: [PATCH] Getting context information from the kernel when catching a SIGABRT on iOS. Until now, the context information was the current one when receiving a SIGABRT. This is mainly wrong because the signal handler start in a new context. This instead use the context passed to the signal handler. Review URL: https://breakpad.appspot.com/435002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1015 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/mac/handler/exception_handler.cc | 9 +++++--- src/client/mac/handler/exception_handler.h | 5 +++- src/client/mac/handler/minidump_generator.cc | 24 ++++++++++++++++---- src/client/mac/handler/minidump_generator.h | 10 +++++++- src/common/mac/macho_utilities.h | 8 ------- 5 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/client/mac/handler/exception_handler.cc b/src/client/mac/handler/exception_handler.cc index 40430194..9b401330 100644 --- a/src/client/mac/handler/exception_handler.cc +++ b/src/client/mac/handler/exception_handler.cc @@ -329,6 +329,7 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, bool ExceptionHandler::WriteMinidumpWithException(int exception_type, int exception_code, int exception_subcode, + ucontext_t *task_context, mach_port_t thread_name, bool exit_after_write, bool report_current_thread) { @@ -366,6 +367,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. @@ -509,7 +511,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 +546,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 @@ -590,6 +592,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { EXC_SOFTWARE, MD_EXCEPTION_CODE_MAC_ABORT, 0, + static_cast(uc), mach_thread_self(), true, true); diff --git a/src/client/mac/handler/exception_handler.h b/src/client/mac/handler/exception_handler.h index ec091341..7babcf66 100644 --- a/src/client/mac/handler/exception_handler.h +++ b/src/client/mac/handler/exception_handler.h @@ -182,10 +182,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, + ucontext_t *task_context, mach_port_t thread_name, bool exit_after_write, bool report_current_thread); diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc index b1d429cf..d6326e38 100644 --- a/src/client/mac/handler/minidump_generator.cc +++ b/src/client/mac/handler/minidump_generator.cc @@ -77,6 +77,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 +95,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()) { @@ -168,6 +170,10 @@ void MinidumpGenerator::GatherSystemInformation() { os_build_number_ = IntegerValueAtIndex(product_str, 2); } +void MinidumpGenerator::SetTaskContext(ucontext_t *task_context) { + task_context_ = task_context; +} + string MinidumpGenerator::UniqueNameInDirectory(const string &dir, string *unique_name) { CFUUIDRef uuid = CFUUIDCreate(NULL); @@ -770,6 +776,19 @@ 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(*count), sizeof(arm_thread_state_t)); + memcpy(state, &task_context_->uc_mcontext->__ss, final_size); + *count = final_size; + return true; + } +#endif + } + } thread_state_flavor_t flavor; switch (cpu_type_) { #ifdef HAS_ARM_SUPPORT @@ -878,10 +897,7 @@ bool MinidumpGenerator::WriteMemoryListStream( mach_msg_type_number_t stateCount = static_cast(sizeof(state)); - if (thread_get_state(exception_thread_, - BREAKPAD_MACHINE_THREAD_STATE, - state, - &stateCount) == KERN_SUCCESS) { + if (GetThreadState(exception_thread_, state, &stateCount)) { u_int64_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, diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h index 8394ce6f..ef947841 100644 --- a/src/client/mac/handler/minidump_generator.h +++ b/src/client/mac/handler/minidump_generator.h @@ -102,6 +102,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(ucontext_t *task_context); + // Gather system information. This should be call at least once before using // the MinidumpGenerator class. static void GatherSystemInformation(); @@ -198,7 +203,10 @@ class MinidumpGenerator { static int os_major_version_; static int os_minor_version_; static int os_build_number_; - + + // Context of the task to dump. + ucontext_t *task_context_; + // Information about dynamically loaded code DynamicImages *dynamic_images_; diff --git a/src/common/mac/macho_utilities.h b/src/common/mac/macho_utilities.h index a07945fd..a200c0f7 100644 --- a/src/common/mac/macho_utilities.h +++ b/src/common/mac/macho_utilities.h @@ -54,14 +54,6 @@ # define LC_UUID 0x1b /* the uuid */ #endif -#if TARGET_CPU_X86 -# define BREAKPAD_MACHINE_THREAD_STATE i386_THREAD_STATE -#elif TARGET_CPU_X86_64 -# define BREAKPAD_MACHINE_THREAD_STATE x86_THREAD_STATE64 -#else -# define BREAKPAD_MACHINE_THREAD_STATE MACHINE_THREAD_STATE -#endif - // The uuid_command struct/swap routines were added during the 10.4 series. // Their presence isn't guaranteed. struct breakpad_uuid_command {