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
This commit is contained in:
qsr@chromium.org 2012-08-20 13:42:09 +00:00
parent e050c46a53
commit 5f57e963d0
5 changed files with 39 additions and 17 deletions

View file

@ -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<ucontext_t*>(uc),
mach_thread_self(),
true,
true);

View file

@ -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);

View file

@ -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<size_t>(*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<mach_msg_type_number_t>(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,

View file

@ -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();
@ -199,6 +204,9 @@ class MinidumpGenerator {
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_;

View file

@ -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 {