1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-15 10:33:59 +02:00

* Updated breakpad to latest version.

This commit is contained in:
Christian Muehlhaeuser
2012-06-24 18:25:34 +02:00
parent 0a3a9a7e97
commit d3eb5c3f88
186 changed files with 9184 additions and 5835 deletions

View File

@@ -28,16 +28,25 @@
// 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 "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 USE_PROTECTED_ALLOCATIONS
#if TARGET_OS_IPHONE
#define USE_PROTECTED_ALLOCATIONS 1
#else
#define USE_PROTECTED_ALLOCATIONS 0
#endif
#endif
// If USE_PROTECTED_ALLOCATIONS is activated then the
// gBreakpadAllocator needs to be setup in other code
@@ -48,9 +57,15 @@
extern ProtectedMemoryAllocator *gBreakpadAllocator;
#endif
namespace google_breakpad {
static union {
#if USE_PROTECTED_ALLOCATIONS
char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
#endif
google_breakpad::ExceptionHandler *handler;
} gProtectedData;
using std::map;
// These structures and techniques are illustrated in
@@ -87,6 +102,7 @@ struct ExceptionReplyMessage {
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"
{
// Forward declarations for functions that need "C" style compilation
@@ -102,128 +118,98 @@ extern "C"
exception_data_t code,
mach_msg_type_number_t code_count)
__attribute__((visibility("default")));
}
#endif
kern_return_t ForwardException(mach_port_t task,
mach_port_t failed_thread,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count);
kern_return_t ForwardException(mach_port_t task,
mach_port_t failed_thread,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count);
kern_return_t exception_raise(mach_port_t target_port,
mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t exception_code,
mach_msg_type_number_t exception_code_count);
#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;
kern_return_t
exception_raise_state(mach_port_t target_port,
mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t exception_code,
mach_msg_type_number_t code_count,
thread_state_flavor_t *target_flavor,
thread_state_t in_thread_state,
mach_msg_type_number_t in_thread_state_count,
thread_state_t out_thread_state,
mach_msg_type_number_t *out_thread_state_count);
if (InHeadP->msgh_id != 2401) {
((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
return FALSE;
}
kern_return_t
exception_raise_state_identity(mach_port_t target_port,
mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t exception_code,
mach_msg_type_number_t exception_code_count,
thread_state_flavor_t *target_flavor,
thread_state_t in_thread_state,
mach_msg_type_number_t in_thread_state_count,
thread_state_t out_thread_state,
mach_msg_type_number_t *out_thread_state_count);
#ifdef __MigPackStructs
#pragma pack(4)
#endif
typedef struct {
mach_msg_header_t Head;
/* start of the kernel processed data */
mach_msg_body_t msgh_body;
mach_msg_port_descriptor_t thread;
mach_msg_port_descriptor_t task;
/* end of the kernel processed data */
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
integer_t code[2];
mach_msg_trailer_t trailer;
} Request;
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
typedef struct {
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
} Reply;
#ifdef __MigPackStructs
#pragma pack()
#endif
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
);
Request *In0P = (Request *)InHeadP;
Reply *OutP = (Reply *)OutHeadP;
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count);
if (In0P->task.name != mach_task_self()) {
return FALSE;
}
OutP->RetCode = ForwardException(In0P->task.name,
In0P->thread.name,
In0P->exception,
In0P->code,
In0P->codeCnt);
OutP->NDR = NDR_record;
return TRUE;
}
#else
boolean_t breakpad_exc_server(mach_msg_header_t *request,
mach_msg_header_t *reply) {
return exc_server(request, reply);
}
kern_return_t breakpad_exception_raise_state(mach_port_t exception_port,
exception_type_t exception,
const exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
const thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
return KERN_SUCCESS;
}
kern_return_t breakpad_exception_raise_state_identity(mach_port_t exception_port,
mach_port_t thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
int *flavor,
thread_state_t old_state,
mach_msg_type_number_t old_stateCnt,
thread_state_t new_state,
mach_msg_type_number_t *new_stateCnt
)
{
return KERN_SUCCESS;
}
kern_return_t breakpad_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count) {
// Callback from exc_server()
kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count) {
if (task != mach_task_self()) {
return KERN_FAILURE;
}
return ForwardException(task, failed_thread, exception, code, code_count);
}
#endif
ExceptionHandler::ExceptionHandler(const string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void *callback_context,
bool install_handler,
const char *port_name)
const char *port_name)
: dump_path_(),
filter_(filter),
callback_(callback),
@@ -239,8 +225,10 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
// This will update to the ID and C-string pointers
set_dump_path(dump_path);
MinidumpGenerator::GatherSystemInformation();
#if !TARGET_OS_IPHONE
if (port_name)
crash_generation_client_.reset(new CrashGenerationClient(port_name));
#endif
Setup(install_handler);
}
@@ -322,6 +310,8 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
EXC_I386_BPT,
#elif defined (__ppc__) || defined (__ppc64__)
EXC_PPC_BREAKPOINT,
#elif defined (__arm__)
EXC_ARM_BREAKPOINT,
#else
#error architecture not supported
#endif
@@ -340,7 +330,8 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
mach_port_t thread_name,
bool exit_after_write) {
bool exit_after_write,
bool report_current_thread) {
bool result = false;
if (directCallback_) {
@@ -352,6 +343,7 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
if (exit_after_write)
_exit(exception_type);
}
#if !TARGET_OS_IPHONE
} else if (IsOutOfProcess()) {
if (exception_type && exception_code) {
// If this is a real exception, give the filter (if any) a chance to
@@ -364,13 +356,16 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
exception_subcode,
thread_name);
}
#endif
} else {
string minidump_id;
// Putting the MinidumpGenerator in its own context will ensure that the
// destructor is executed, closing the newly created minidump file.
if (!dump_path_.empty()) {
MinidumpGenerator md;
MinidumpGenerator md(mach_task_self(),
report_current_thread ? MACH_PORT_NULL :
mach_thread_self());
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.
@@ -411,13 +406,13 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
current.count = EXC_TYPES_COUNT;
mach_port_t current_task = mach_task_self();
kern_return_t result = task_get_exception_ports(current_task,
s_exception_mask,
current.masks,
&current.count,
current.ports,
current.behaviors,
current.flavors);
task_get_exception_ports(current_task,
s_exception_mask,
current.masks,
&current.count,
current.ports,
current.behaviors,
current.flavors);
// Find the first exception handler that matches the exception
unsigned int found;
@@ -435,48 +430,16 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
mach_port_t target_port = current.ports[found];
exception_behavior_t target_behavior = current.behaviors[found];
thread_state_flavor_t target_flavor = current.flavors[found];
mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
breakpad_thread_state_data_t thread_state;
kern_return_t result;
switch (target_behavior) {
case EXCEPTION_DEFAULT:
result = exception_raise(target_port, failed_thread, task, exception,
code, code_count);
break;
case EXCEPTION_STATE:
result = thread_get_state(failed_thread, target_flavor, thread_state,
&thread_state_count);
if (result == KERN_SUCCESS)
result = exception_raise_state(target_port, failed_thread, task,
exception, code,
code_count, &target_flavor,
thread_state, thread_state_count,
thread_state, &thread_state_count);
if (result == KERN_SUCCESS)
result = thread_set_state(failed_thread, target_flavor, thread_state,
thread_state_count);
break;
case EXCEPTION_STATE_IDENTITY:
result = thread_get_state(failed_thread, target_flavor, thread_state,
&thread_state_count);
if (result == KERN_SUCCESS)
result = exception_raise_state_identity(target_port, failed_thread,
task, exception, code,
code_count, &target_flavor,
thread_state,
thread_state_count,
thread_state,
&thread_state_count);
if (result == KERN_SUCCESS)
result = thread_set_state(failed_thread, target_flavor, thread_state,
thread_state_count);
break;
default:
fprintf(stderr, "** Unknown exception behavior\n");
fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior);
result = KERN_FAILURE;
break;
}
@@ -484,18 +447,6 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
return result;
}
// Callback from exc_server()
kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
mach_port_t task,
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t code_count) {
if (task != mach_task_self()) {
return KERN_FAILURE;
}
return ForwardException(task, failed_thread, exception, code, code_count);
}
// static
void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
ExceptionHandler *self =
@@ -534,7 +485,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
self->SuspendThreads();
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
if (gBreakpadAllocator)
gBreakpadAllocator->Unprotect();
#endif
@@ -548,6 +499,8 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
exception_code = EXC_I386_BPT;
#elif defined (__ppc__) || defined (__ppc64__)
exception_code = EXC_PPC_BREAKPOINT;
#elif defined (__arm__)
exception_code = EXC_ARM_BREAKPOINT;
#else
#error architecture not supported
#endif
@@ -557,10 +510,10 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
self->last_minidump_write_result_ =
self->WriteMinidumpWithException(exception_type, exception_code,
0, thread,
false);
false, false);
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
if (gBreakpadAllocator)
gBreakpadAllocator->Protect();
#endif
@@ -575,13 +528,13 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// exceptions that occur in the parent process are caught and
// processed. If the exception was not caused by this task, we
// still need to call into the exception server and have it return
// KERN_FAILURE (see breakpad_exception_raise) in order for the kernel
// KERN_FAILURE (see catch_exception_raise) in order for the kernel
// to move onto the host exception handler for the child task
if (receive.task.name == mach_task_self()) {
self->SuspendThreads();
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
if (gBreakpadAllocator)
gBreakpadAllocator->Unprotect();
#endif
@@ -591,34 +544,35 @@ 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);
subcode, receive.thread.name, true,
false);
#if USE_PROTECTED_ALLOCATIONS
// This may have become protected again within
// WriteMinidumpWithException, but it needs to be unprotected for
// UninstallHandler.
if(gBreakpadAllocator)
if (gBreakpadAllocator)
gBreakpadAllocator->Unprotect();
#endif
self->UninstallHandler(true);
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
if (gBreakpadAllocator)
gBreakpadAllocator->Protect();
#endif
}
// Pass along the exception to the server, which will setup the
// message and call breakpad_exception_raise() and put the return
// message and call catch_exception_raise() and put the return
// code into the reply.
ExceptionReplyMessage reply;
if (!exc_server(&receive.header, &reply.header))
if (!breakpad_exc_server(&receive.header, &reply.header))
exit(1);
// Send a reply and exit
result = mach_msg(&(reply.header), MACH_SEND_MSG,
reply.header.msgh_size, 0, MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
mach_msg(&(reply.header), MACH_SEND_MSG,
reply.header.msgh_size, 0, MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
}
}
}
@@ -626,7 +580,52 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
return NULL;
}
//static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
#if USE_PROTECTED_ALLOCATIONS
if (gBreakpadAllocator)
gBreakpadAllocator->Unprotect();
#endif
gProtectedData.handler->WriteMinidumpWithException(
EXC_SOFTWARE,
MD_EXCEPTION_CODE_MAC_ABORT,
0,
mach_thread_self(),
true,
true);
#if USE_PROTECTED_ALLOCATIONS
if (gBreakpadAllocator)
gBreakpadAllocator->Protect();
#endif
}
bool ExceptionHandler::InstallHandler() {
// If a handler is already installed, something is really wrong.
if (gProtectedData.handler != NULL) {
return false;
}
#if TARGET_OS_IPHONE
if (!IsOutOfProcess()) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGABRT);
sa.sa_sigaction = ExceptionHandler::SignalHandler;
sa.sa_flags = SA_SIGINFO;
scoped_ptr<struct sigaction> old(new struct sigaction);
if (sigaction(SIGABRT, &sa, old.get()) == -1) {
return false;
}
old_handler_.swap(old);
gProtectedData.handler = this;
#if USE_PROTECTED_ALLOCATIONS
assert(((size_t)(gProtectedData.protected_buffer) & PAGE_MASK) == 0);
mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ);
#endif
}
#endif
try {
#if USE_PROTECTED_ALLOCATIONS
previous_ = new (gBreakpadAllocator->Allocate(sizeof(ExceptionParameters)) )
@@ -665,6 +664,16 @@ bool ExceptionHandler::InstallHandler() {
bool ExceptionHandler::UninstallHandler(bool in_exception) {
kern_return_t result = KERN_SUCCESS;
if (old_handler_.get()) {
sigaction(SIGABRT, old_handler_.get(), NULL);
#if USE_PROTECTED_ALLOCATIONS
mprotect(gProtectedData.protected_buffer, PAGE_SIZE,
PROT_READ | PROT_WRITE);
#endif
old_handler_.reset();
gProtectedData.handler = NULL;
}
if (installed_exception_handler_) {
mach_port_t current_task = mach_task_self();
@@ -744,7 +753,7 @@ bool ExceptionHandler::Teardown() {
}
handler_thread_ = NULL;
handler_port_ = NULL;
handler_port_ = MACH_PORT_NULL;
pthread_mutex_destroy(&minidump_write_mutex_);
return result == KERN_SUCCESS;