mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-31 17:42:13 +02:00
* Updated breakpad to latest version.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,258 +0,0 @@
|
||||
#ifndef _exc_user_
|
||||
#define _exc_user_
|
||||
|
||||
/* Module exc */
|
||||
|
||||
#include <string.h>
|
||||
#include <mach/ndr.h>
|
||||
#include <mach/boolean.h>
|
||||
#include <mach/kern_return.h>
|
||||
#include <mach/notify.h>
|
||||
#include <mach/mach_types.h>
|
||||
#include <mach/message.h>
|
||||
#include <mach/mig_errors.h>
|
||||
#include <mach/port.h>
|
||||
|
||||
#ifdef AUTOTEST
|
||||
#ifndef FUNCTION_PTR_T
|
||||
#define FUNCTION_PTR_T
|
||||
typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);
|
||||
typedef struct {
|
||||
char *name;
|
||||
function_ptr_t function;
|
||||
} function_table_entry;
|
||||
typedef function_table_entry *function_table_t;
|
||||
#endif /* FUNCTION_PTR_T */
|
||||
#endif /* AUTOTEST */
|
||||
|
||||
#ifndef exc_MSG_COUNT
|
||||
#define exc_MSG_COUNT 3
|
||||
#endif /* exc_MSG_COUNT */
|
||||
|
||||
#include <mach/std_types.h>
|
||||
#include <mach/mig.h>
|
||||
#include <mach/mig.h>
|
||||
#include <mach/mach_types.h>
|
||||
|
||||
#ifdef __BeforeMigUserHeader
|
||||
__BeforeMigUserHeader
|
||||
#endif /* __BeforeMigUserHeader */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
||||
/* Routine exception_raise */
|
||||
#ifdef mig_external
|
||||
mig_external
|
||||
#else
|
||||
extern
|
||||
#endif /* mig_external */
|
||||
kern_return_t exception_raise
|
||||
(
|
||||
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
|
||||
);
|
||||
|
||||
/* Routine exception_raise_state */
|
||||
#ifdef mig_external
|
||||
mig_external
|
||||
#else
|
||||
extern
|
||||
#endif /* mig_external */
|
||||
kern_return_t 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
|
||||
);
|
||||
|
||||
/* Routine exception_raise_state_identity */
|
||||
#ifdef mig_external
|
||||
mig_external
|
||||
#else
|
||||
extern
|
||||
#endif /* mig_external */
|
||||
kern_return_t 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
|
||||
);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
/********************** Caution **************************/
|
||||
/* The following data types should be used to calculate */
|
||||
/* maximum message sizes only. The actual message may be */
|
||||
/* smaller, and the position of the arguments within the */
|
||||
/* message layout may vary from what is presented here. */
|
||||
/* For example, if any of the arguments are variable- */
|
||||
/* sized, and less than the maximum is sent, the data */
|
||||
/* will be packed tight in the actual message to reduce */
|
||||
/* the presence of holes. */
|
||||
/********************** Caution **************************/
|
||||
|
||||
/* typedefs for all requests */
|
||||
|
||||
#ifndef __Request__exc_subsystem__defined
|
||||
#define __Request__exc_subsystem__defined
|
||||
|
||||
#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];
|
||||
} __Request__exception_raise_t;
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack(4)
|
||||
#endif
|
||||
typedef struct {
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
exception_type_t exception;
|
||||
mach_msg_type_number_t codeCnt;
|
||||
integer_t code[2];
|
||||
int flavor;
|
||||
mach_msg_type_number_t old_stateCnt;
|
||||
natural_t old_state[144];
|
||||
} __Request__exception_raise_state_t;
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#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];
|
||||
int flavor;
|
||||
mach_msg_type_number_t old_stateCnt;
|
||||
natural_t old_state[144];
|
||||
} __Request__exception_raise_state_identity_t;
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif /* !__Request__exc_subsystem__defined */
|
||||
|
||||
/* union of all requests */
|
||||
|
||||
#ifndef __RequestUnion__exc_subsystem__defined
|
||||
#define __RequestUnion__exc_subsystem__defined
|
||||
union __RequestUnion__exc_subsystem {
|
||||
__Request__exception_raise_t Request_exception_raise;
|
||||
__Request__exception_raise_state_t Request_exception_raise_state;
|
||||
__Request__exception_raise_state_identity_t Request_exception_raise_state_identity;
|
||||
};
|
||||
#endif /* !__RequestUnion__exc_subsystem__defined */
|
||||
/* typedefs for all replies */
|
||||
|
||||
#ifndef __Reply__exc_subsystem__defined
|
||||
#define __Reply__exc_subsystem__defined
|
||||
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack(4)
|
||||
#endif
|
||||
typedef struct {
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
kern_return_t RetCode;
|
||||
} __Reply__exception_raise_t;
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack(4)
|
||||
#endif
|
||||
typedef struct {
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
kern_return_t RetCode;
|
||||
int flavor;
|
||||
mach_msg_type_number_t new_stateCnt;
|
||||
natural_t new_state[144];
|
||||
} __Reply__exception_raise_state_t;
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack(4)
|
||||
#endif
|
||||
typedef struct {
|
||||
mach_msg_header_t Head;
|
||||
NDR_record_t NDR;
|
||||
kern_return_t RetCode;
|
||||
int flavor;
|
||||
mach_msg_type_number_t new_stateCnt;
|
||||
natural_t new_state[144];
|
||||
} __Reply__exception_raise_state_identity_t;
|
||||
#ifdef __MigPackStructs
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif /* !__Reply__exc_subsystem__defined */
|
||||
|
||||
/* union of all replies */
|
||||
|
||||
#ifndef __ReplyUnion__exc_subsystem__defined
|
||||
#define __ReplyUnion__exc_subsystem__defined
|
||||
union __ReplyUnion__exc_subsystem {
|
||||
__Reply__exception_raise_t Reply_exception_raise;
|
||||
__Reply__exception_raise_state_t Reply_exception_raise_state;
|
||||
__Reply__exception_raise_state_identity_t Reply_exception_raise_state_identity;
|
||||
};
|
||||
#endif /* !__RequestUnion__exc_subsystem__defined */
|
||||
|
||||
#ifndef subsystem_to_name_map_exc
|
||||
#define subsystem_to_name_map_exc \
|
||||
{ "exception_raise", 2401 },\
|
||||
{ "exception_raise_state", 2402 },\
|
||||
{ "exception_raise_state_identity", 2403 }
|
||||
#endif
|
||||
|
||||
#ifdef __AfterMigUserHeader
|
||||
__AfterMigUserHeader
|
||||
#endif /* __AfterMigUserHeader */
|
||||
|
||||
#endif /* _exc_user_ */
|
@@ -67,6 +67,7 @@
|
||||
|
||||
#include "breakpad_nlist_64.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <fcntl.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <mach-o/loader.h>
|
||||
@@ -189,16 +190,16 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
|
||||
|
||||
struct exec buf;
|
||||
if (read(fd, (char *)&buf, sizeof(buf)) != sizeof(buf) ||
|
||||
(N_BADMAG(buf) && *((long *)&buf) != magic &&
|
||||
NXSwapBigLongToHost(*((long *)&buf)) != FAT_MAGIC) &&
|
||||
/* The following is the big-endian ppc64 check */
|
||||
(*((long*)&buf)) != FAT_MAGIC) {
|
||||
(N_BADMAG(buf) && *((uint32_t *)&buf) != magic &&
|
||||
CFSwapInt32BigToHost(*((uint32_t *)&buf)) != FAT_MAGIC &&
|
||||
/* The following is the big-endian ppc64 check */
|
||||
(*((uint32_t*)&buf)) != FAT_MAGIC)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Deal with fat file if necessary */
|
||||
unsigned arch_offset = 0;
|
||||
if (NXSwapBigLongToHost(*((long *)&buf)) == FAT_MAGIC ||
|
||||
if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC ||
|
||||
/* The following is the big-endian ppc64 check */
|
||||
*((unsigned int *)&buf) == FAT_MAGIC) {
|
||||
/* Get host info */
|
||||
@@ -222,7 +223,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
|
||||
}
|
||||
|
||||
/* Convert fat_narchs to host byte order */
|
||||
fh.nfat_arch = NXSwapBigIntToHost(fh.nfat_arch);
|
||||
fh.nfat_arch = CFSwapInt32BigToHost(fh.nfat_arch);
|
||||
|
||||
/* Read in the fat archs */
|
||||
struct fat_arch *fat_archs =
|
||||
@@ -232,7 +233,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
|
||||
}
|
||||
if (read(fd, (char *)fat_archs,
|
||||
sizeof(struct fat_arch) * fh.nfat_arch) !=
|
||||
(ssize_t)sizeof(struct fat_arch) * fh.nfat_arch) {
|
||||
(ssize_t)(sizeof(struct fat_arch) * fh.nfat_arch)) {
|
||||
free(fat_archs);
|
||||
return -1;
|
||||
}
|
||||
@@ -243,15 +244,15 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
|
||||
*/
|
||||
for (unsigned i = 0; i < fh.nfat_arch; i++) {
|
||||
fat_archs[i].cputype =
|
||||
NXSwapBigIntToHost(fat_archs[i].cputype);
|
||||
CFSwapInt32BigToHost(fat_archs[i].cputype);
|
||||
fat_archs[i].cpusubtype =
|
||||
NXSwapBigIntToHost(fat_archs[i].cpusubtype);
|
||||
CFSwapInt32BigToHost(fat_archs[i].cpusubtype);
|
||||
fat_archs[i].offset =
|
||||
NXSwapBigIntToHost(fat_archs[i].offset);
|
||||
CFSwapInt32BigToHost(fat_archs[i].offset);
|
||||
fat_archs[i].size =
|
||||
NXSwapBigIntToHost(fat_archs[i].size);
|
||||
CFSwapInt32BigToHost(fat_archs[i].size);
|
||||
fat_archs[i].align =
|
||||
NXSwapBigIntToHost(fat_archs[i].align);
|
||||
CFSwapInt32BigToHost(fat_archs[i].align);
|
||||
}
|
||||
|
||||
struct fat_arch *fap = NULL;
|
||||
@@ -296,7 +297,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
|
||||
return -1;
|
||||
}
|
||||
if (read(fd, (char *)load_commands, mh.sizeofcmds) !=
|
||||
mh.sizeofcmds) {
|
||||
(ssize_t)mh.sizeofcmds) {
|
||||
free(load_commands);
|
||||
return -1;
|
||||
}
|
||||
@@ -304,7 +305,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
|
||||
struct load_command *lcp = load_commands;
|
||||
// iterate through all load commands, looking for
|
||||
// LC_SYMTAB load command
|
||||
for (long i = 0; i < mh.ncmds; i++) {
|
||||
for (uint32_t i = 0; i < mh.ncmds; i++) {
|
||||
if (lcp->cmdsize % sizeof(word_type) != 0 ||
|
||||
lcp->cmdsize <= 0 ||
|
||||
(char *)lcp + lcp->cmdsize >
|
||||
|
@@ -35,19 +35,22 @@ extern "C" { // needed to compile on Leopard
|
||||
#include <stdio.h>
|
||||
}
|
||||
|
||||
#include "breakpad_nlist_64.h"
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <assert.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <mach/task_info.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_nlist_64.h"
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_6
|
||||
#define MAC_OS_X_VERSION_10_6 1060
|
||||
#endif
|
||||
@@ -67,6 +70,8 @@ typedef struct task_dyld_info *task_dyld_info_t;
|
||||
|
||||
#endif
|
||||
|
||||
#endif // !TARGET_OS_IPHONE
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
@@ -358,6 +363,11 @@ static uint64_t LookupSymbol(const char* symbol_name,
|
||||
return list.n_value;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
static bool HasTaskDyldInfo() {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static SInt32 GetOSVersionInternal() {
|
||||
SInt32 os_version = 0;
|
||||
Gestalt(gestaltSystemVersion, &os_version);
|
||||
@@ -369,21 +379,22 @@ static SInt32 GetOSVersion() {
|
||||
return os_version;
|
||||
}
|
||||
|
||||
static bool IsSnowLeopardOrLater() {
|
||||
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
|
||||
|
||||
uint64_t DynamicImages::GetDyldAllImageInfosPointer() {
|
||||
if (IsSnowLeopardOrLater()) {
|
||||
if (HasTaskDyldInfo()) {
|
||||
task_dyld_info_data_t task_dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
if (task_info(task_, TASK_DYLD_INFO, (task_info_t)&task_dyld_info,
|
||||
&count) != KERN_SUCCESS) {
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uint64_t)task_dyld_info.all_image_info_addr;
|
||||
|
@@ -45,6 +45,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "mach_vm_compat.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
@@ -281,6 +283,8 @@ class DynamicImages {
|
||||
return CPU_TYPE_POWERPC;
|
||||
#elif defined(__ppc64__)
|
||||
return CPU_TYPE_POWERPC64;
|
||||
#elif defined(__arm__)
|
||||
return CPU_TYPE_ARM;
|
||||
#else
|
||||
#error "GetNativeCPUType not implemented for this architecture"
|
||||
#endif
|
||||
|
@@ -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,
|
||||
¤t.count,
|
||||
current.ports,
|
||||
current.behaviors,
|
||||
current.flavors);
|
||||
task_get_exception_ports(current_task,
|
||||
s_exception_mask,
|
||||
current.masks,
|
||||
¤t.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;
|
||||
|
@@ -37,12 +37,16 @@
|
||||
#define CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "client/mac/crash_generation/crash_generation_client.h"
|
||||
#include "processor/scoped_ptr.h"
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
#include "client/mac/crash_generation/crash_generation_client.h"
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
@@ -152,7 +156,11 @@ class ExceptionHandler {
|
||||
|
||||
// Returns whether out-of-process dump generation is used or not.
|
||||
bool IsOutOfProcess() const {
|
||||
#if TARGET_OS_IPHONE
|
||||
return false;
|
||||
#else
|
||||
return crash_generation_client_.get() != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -179,12 +187,16 @@ class ExceptionHandler {
|
||||
int exception_code,
|
||||
int exception_subcode,
|
||||
mach_port_t thread_name,
|
||||
bool exit_after_write);
|
||||
bool exit_after_write,
|
||||
bool report_current_thread);
|
||||
|
||||
// When installed, this static function will be call from a newly created
|
||||
// pthread with |this| as the argument
|
||||
static void *WaitForMessage(void *exception_handler_class);
|
||||
|
||||
// Signal handler for SIGABRT.
|
||||
static void SignalHandler(int sig, siginfo_t* info, void* uc);
|
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit ExceptionHandler(const ExceptionHandler &);
|
||||
void operator=(const ExceptionHandler &);
|
||||
@@ -250,8 +262,14 @@ class ExceptionHandler {
|
||||
// True, if we're using the mutext to indicate when mindump writing occurs
|
||||
bool use_minidump_write_mutex_;
|
||||
|
||||
// Old signal handler for SIGABRT. Used to be able to restore it when
|
||||
// uninstalling.
|
||||
scoped_ptr<struct sigaction> old_handler_;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
// Client for out-of-process dump generation.
|
||||
scoped_ptr<CrashGenerationClient> crash_generation_client_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
49
thirdparty/breakpad/client/mac/handler/mach_vm_compat.h
vendored
Normal file
49
thirdparty/breakpad/client/mac/handler/mach_vm_compat.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2011, 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_GENERATOR_MACH_VM_COMPAT_H_
|
||||
#define CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_
|
||||
|
||||
#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.
|
||||
#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_size_t vm_size_t
|
||||
#else
|
||||
#include <mach/mach_vm.h>
|
||||
#endif // TARGET_OS_IPHONE
|
||||
|
||||
#endif // CLIENT_MAC_GENERATOR_MACH_VM_COMPAT_H_
|
@@ -31,8 +31,6 @@
|
||||
#include <cstdio>
|
||||
|
||||
#include <mach/host_info.h>
|
||||
#include <mach/i386/thread_status.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <mach/vm_statistics.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/loader.h>
|
||||
@@ -43,12 +41,19 @@
|
||||
|
||||
#include "client/mac/handler/minidump_generator.h"
|
||||
|
||||
#ifdef HAS_ARM_SUPPORT
|
||||
#include <mach/arm/thread_status.h>
|
||||
#endif
|
||||
#ifdef HAS_PPC_SUPPORT
|
||||
#include <mach/ppc/thread_status.h>
|
||||
#endif
|
||||
#ifdef HAS_X86_SUPPORT
|
||||
#include <mach/i386/thread_status.h>
|
||||
#endif
|
||||
|
||||
#include "client/minidump_file_writer-inl.h"
|
||||
#include "common/mac/file_id.h"
|
||||
#include "common/mac/macho_id.h"
|
||||
#include "common/mac/string_utilities.h"
|
||||
|
||||
using MacStringUtils::ConvertToString;
|
||||
@@ -130,14 +135,19 @@ void MinidumpGenerator::GatherSystemInformation() {
|
||||
CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL,
|
||||
&error);
|
||||
|
||||
if (!data)
|
||||
if (!data) {
|
||||
CFRelease(sys_vers);
|
||||
return;
|
||||
}
|
||||
|
||||
CFDictionaryRef list = static_cast<CFDictionaryRef>
|
||||
(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
|
||||
NULL));
|
||||
if (!list)
|
||||
if (!list) {
|
||||
CFRelease(sys_vers);
|
||||
CFRelease(data);
|
||||
return;
|
||||
}
|
||||
|
||||
CFStringRef build_version = static_cast<CFStringRef>
|
||||
(CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
|
||||
@@ -348,16 +358,22 @@ bool MinidumpGenerator::WriteStackFromStartAddress(
|
||||
bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
|
||||
MDMemoryDescriptor *stack_location) {
|
||||
switch (cpu_type_) {
|
||||
#ifdef HAS_ARM_SUPPORT
|
||||
case CPU_TYPE_ARM:
|
||||
return WriteStackARM(state, stack_location);
|
||||
#endif
|
||||
#ifdef HAS_PPC_SUPPORT
|
||||
case CPU_TYPE_POWERPC:
|
||||
return WriteStackPPC(state, stack_location);
|
||||
case CPU_TYPE_POWERPC64:
|
||||
return WriteStackPPC64(state, stack_location);
|
||||
#endif
|
||||
#ifdef HAS_X86_SUPPORT
|
||||
case CPU_TYPE_I386:
|
||||
return WriteStackX86(state, stack_location);
|
||||
case CPU_TYPE_X86_64:
|
||||
return WriteStackX86_64(state, stack_location);
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -366,16 +382,22 @@ bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
|
||||
bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
|
||||
MDLocationDescriptor *register_location) {
|
||||
switch (cpu_type_) {
|
||||
#ifdef HAS_ARM_SUPPORT
|
||||
case CPU_TYPE_ARM:
|
||||
return WriteContextARM(state, register_location);
|
||||
#endif
|
||||
#ifdef HAS_PPC_SUPPORT
|
||||
case CPU_TYPE_POWERPC:
|
||||
return WriteContextPPC(state, register_location);
|
||||
case CPU_TYPE_POWERPC64:
|
||||
return WriteContextPPC64(state, register_location);
|
||||
#endif
|
||||
#ifdef HAS_X86_SUPPORT
|
||||
case CPU_TYPE_I386:
|
||||
return WriteContextX86(state, register_location);
|
||||
case CPU_TYPE_X86_64:
|
||||
return WriteContextX86_64(state, register_location);
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -384,22 +406,86 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
|
||||
u_int64_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_PPC_SUPPORT
|
||||
case CPU_TYPE_POWERPC:
|
||||
return CurrentPCForStackPPC(state);
|
||||
case CPU_TYPE_POWERPC64:
|
||||
return CurrentPCForStackPPC64(state);
|
||||
#endif
|
||||
#ifdef HAS_X86_SUPPORT
|
||||
case CPU_TYPE_I386:
|
||||
return CurrentPCForStackX86(state);
|
||||
case CPU_TYPE_X86_64:
|
||||
return CurrentPCForStackX86_64(state);
|
||||
#endif
|
||||
default:
|
||||
assert("Unknown CPU type!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_ARM_SUPPORT
|
||||
bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state,
|
||||
MDMemoryDescriptor *stack_location) {
|
||||
arm_thread_state_t *machine_state =
|
||||
reinterpret_cast<arm_thread_state_t *>(state);
|
||||
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
|
||||
return WriteStackFromStartAddress(start_addr, stack_location);
|
||||
}
|
||||
|
||||
u_int64_t
|
||||
MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) {
|
||||
arm_thread_state_t *machine_state =
|
||||
reinterpret_cast<arm_thread_state_t *>(state);
|
||||
|
||||
return REGISTER_FROM_THREADSTATE(machine_state, pc);
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,
|
||||
MDLocationDescriptor *register_location)
|
||||
{
|
||||
TypedMDRVA<MDRawContextARM> context(&writer_);
|
||||
arm_thread_state_t *machine_state =
|
||||
reinterpret_cast<arm_thread_state_t *>(state);
|
||||
|
||||
if (!context.Allocate())
|
||||
return false;
|
||||
|
||||
*register_location = context.location();
|
||||
MDRawContextARM *context_ptr = context.get();
|
||||
context_ptr->context_flags = MD_CONTEXT_ARM_FULL;
|
||||
|
||||
#define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a])
|
||||
|
||||
context_ptr->iregs[13] = REGISTER_FROM_THREADSTATE(machine_state, sp);
|
||||
context_ptr->iregs[14] = REGISTER_FROM_THREADSTATE(machine_state, lr);
|
||||
context_ptr->iregs[15] = 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);
|
||||
#undef AddReg
|
||||
#undef AddGPR
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PCC_SUPPORT
|
||||
bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state,
|
||||
MDMemoryDescriptor *stack_location) {
|
||||
@@ -560,6 +646,7 @@ bool MinidumpGenerator::WriteContextPPC64(
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAS_X86_SUPPORT
|
||||
bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state,
|
||||
MDMemoryDescriptor *stack_location) {
|
||||
i386_thread_state_t *machine_state =
|
||||
@@ -678,12 +765,18 @@ bool MinidumpGenerator::WriteContextX86_64(
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
|
||||
thread_state_t state,
|
||||
mach_msg_type_number_t *count) {
|
||||
thread_state_flavor_t flavor;
|
||||
switch (cpu_type_) {
|
||||
#ifdef HAS_ARM_SUPPORT
|
||||
case CPU_TYPE_ARM:
|
||||
flavor = ARM_THREAD_STATE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_PPC_SUPPORT
|
||||
case CPU_TYPE_POWERPC:
|
||||
flavor = PPC_THREAD_STATE;
|
||||
@@ -692,12 +785,14 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
|
||||
flavor = PPC_THREAD_STATE64;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_X86_SUPPORT
|
||||
case CPU_TYPE_I386:
|
||||
flavor = i386_THREAD_STATE;
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
flavor = x86_THREAD_STATE64;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -927,10 +1022,18 @@ bool MinidumpGenerator::WriteSystemInfoStream(
|
||||
MDRawSystemInfo *info_ptr = info.get();
|
||||
|
||||
switch (cpu_type_) {
|
||||
#ifdef HAS_ARM_SUPPORT
|
||||
case CPU_TYPE_ARM:
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_PPC_SUPPORT
|
||||
case CPU_TYPE_POWERPC:
|
||||
case CPU_TYPE_POWERPC64:
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_X86_SUPPORT
|
||||
case CPU_TYPE_I386:
|
||||
case CPU_TYPE_X86_64:
|
||||
if (cpu_type_ == CPU_TYPE_I386)
|
||||
@@ -994,13 +1097,18 @@ bool MinidumpGenerator::WriteSystemInfoStream(
|
||||
|
||||
#endif // __i386__ || __x86_64_
|
||||
break;
|
||||
#endif // HAS_X86_SUPPORT
|
||||
default:
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
info_ptr->number_of_processors = number_of_processors;
|
||||
#if TARGET_OS_IPHONE
|
||||
info_ptr->platform_id = MD_OS_IOS;
|
||||
#else
|
||||
info_ptr->platform_id = MD_OS_MAC_OS_X;
|
||||
#endif // TARGET_OS_IPHONE
|
||||
|
||||
MDLocationDescriptor build_string_loc;
|
||||
|
||||
@@ -1057,7 +1165,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
|
||||
module->version_info.file_version_lo |= (modVersion & 0xff);
|
||||
}
|
||||
|
||||
if (!WriteCVRecord(module, image->GetCPUType(), name.c_str())) {
|
||||
if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -1103,7 +1211,11 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
|
||||
module->size_of_image = static_cast<u_int32_t>(seg->vmsize);
|
||||
module->module_name_rva = string_location.rva;
|
||||
|
||||
if (!WriteCVRecord(module, cpu_type, name))
|
||||
bool in_memory = false;
|
||||
#if TARGET_OS_IPHONE
|
||||
in_memory = true;
|
||||
#endif
|
||||
if (!WriteCVRecord(module, cpu_type, name, in_memory))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -1141,7 +1253,7 @@ int MinidumpGenerator::FindExecutableModule() {
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
|
||||
const char *module_path) {
|
||||
const char *module_path, bool in_memory) {
|
||||
TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
|
||||
|
||||
// Only return the last path component of the full module path
|
||||
@@ -1167,10 +1279,23 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
|
||||
cv_ptr->age = 0;
|
||||
|
||||
// Get the module identifier
|
||||
FileID file_id(module_path);
|
||||
unsigned char identifier[16];
|
||||
bool result = false;
|
||||
if (in_memory) {
|
||||
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);
|
||||
if (!result)
|
||||
result = macho.MD5(cpu_type, identifier);
|
||||
}
|
||||
|
||||
if (file_id.MachoIdentifier(cpu_type, identifier)) {
|
||||
if (!result) {
|
||||
FileID file_id(module_path);
|
||||
result = file_id.MachoIdentifier(cpu_type, 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];
|
||||
@@ -1193,8 +1318,9 @@ bool MinidumpGenerator::WriteModuleListStream(
|
||||
MDRawDirectory *module_list_stream) {
|
||||
TypedMDRVA<MDRawModuleList> list(&writer_);
|
||||
|
||||
int image_count = dynamic_images_ ?
|
||||
dynamic_images_->GetImageCount() : _dyld_image_count();
|
||||
size_t image_count = dynamic_images_ ?
|
||||
static_cast<size_t>(dynamic_images_->GetImageCount()) :
|
||||
_dyld_image_count();
|
||||
|
||||
if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE))
|
||||
return false;
|
||||
@@ -1205,7 +1331,7 @@ bool MinidumpGenerator::WriteModuleListStream(
|
||||
|
||||
// Write out the executable module as the first one
|
||||
MDRawModule module;
|
||||
int executableIndex = FindExecutableModule();
|
||||
size_t executableIndex = FindExecutableModule();
|
||||
|
||||
if (!WriteModuleStream(executableIndex, &module)) {
|
||||
return false;
|
||||
@@ -1214,7 +1340,7 @@ bool MinidumpGenerator::WriteModuleListStream(
|
||||
list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);
|
||||
int destinationIndex = 1; // Write all other modules after this one
|
||||
|
||||
for (int i = 0; i < image_count; ++i) {
|
||||
for (size_t i = 0; i < image_count; ++i) {
|
||||
if (i != executableIndex) {
|
||||
if (!WriteModuleStream(i, &module)) {
|
||||
return false;
|
||||
@@ -1257,19 +1383,11 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
|
||||
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]));
|
||||
size_t size;
|
||||
if (!sysctl(mib, mibsize, NULL, &size, NULL, 0)) {
|
||||
mach_vm_address_t addr;
|
||||
if (mach_vm_allocate(mach_task_self(),
|
||||
&addr,
|
||||
size,
|
||||
true) == KERN_SUCCESS) {
|
||||
struct kinfo_proc *proc = (struct kinfo_proc *)addr;
|
||||
if (!sysctl(mib, mibsize, proc, &size, NULL, 0))
|
||||
info_ptr->process_create_time =
|
||||
static_cast<u_int32_t>(proc->kp_proc.p_starttime.tv_sec);
|
||||
mach_vm_deallocate(mach_task_self(), addr, size);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// Speed
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#define CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -42,10 +43,16 @@
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
#include "dynamic_images.h"
|
||||
#include "mach_vm_compat.h"
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
|
||||
#if !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7)
|
||||
#define HAS_PPC_SUPPORT
|
||||
#endif
|
||||
#if defined(__arm__)
|
||||
#define HAS_ARM_SUPPORT
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#define HAS_X86_SUPPORT
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@@ -53,7 +60,7 @@ using std::string;
|
||||
|
||||
// Use the REGISTER_FROM_THREADSTATE to access a register name from the
|
||||
// breakpad_thread_state_t structure.
|
||||
#if __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64
|
||||
#if __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64 || TARGET_CPU_ARM
|
||||
// In The 10.5 SDK Headers Apple prepended __ to the variable names in the
|
||||
// i386_thread_state_t structure. There's no good way to tell what version of
|
||||
// the SDK we're compiling against so we just toggle on the same preprocessor
|
||||
@@ -75,7 +82,7 @@ class MinidumpGenerator {
|
||||
MinidumpGenerator();
|
||||
MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread);
|
||||
|
||||
~MinidumpGenerator();
|
||||
virtual ~MinidumpGenerator();
|
||||
|
||||
// Return <dir>/<unique_name>.dmp
|
||||
// Sets |unique_name| (if requested) to the unique name for the minidump
|
||||
@@ -99,13 +106,19 @@ class MinidumpGenerator {
|
||||
// the MinidumpGenerator class.
|
||||
static void GatherSystemInformation();
|
||||
|
||||
protected:
|
||||
// Overridable Stream writers
|
||||
virtual bool WriteExceptionStream(MDRawDirectory *exception_stream);
|
||||
|
||||
// Overridable Helper
|
||||
virtual bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
|
||||
|
||||
private:
|
||||
typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *);
|
||||
typedef bool (MinidumpGenerator::*WriteStreamFN)(MDRawDirectory *);
|
||||
|
||||
// Stream writers
|
||||
bool WriteThreadListStream(MDRawDirectory *thread_list_stream);
|
||||
bool WriteMemoryListStream(MDRawDirectory *memory_list_stream);
|
||||
bool WriteExceptionStream(MDRawDirectory *exception_stream);
|
||||
bool WriteSystemInfoStream(MDRawDirectory *system_info_stream);
|
||||
bool WriteModuleListStream(MDRawDirectory *module_list_stream);
|
||||
bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream);
|
||||
@@ -121,14 +134,20 @@ class MinidumpGenerator {
|
||||
MDMemoryDescriptor *stack_location);
|
||||
bool WriteContext(breakpad_thread_state_data_t state,
|
||||
MDLocationDescriptor *register_location);
|
||||
bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
|
||||
bool WriteCVRecord(MDRawModule *module, int cpu_type,
|
||||
const char *module_path);
|
||||
bool WriteCVRecord(MDRawModule *module, int cpu_type,
|
||||
const char *module_path, bool in_memory);
|
||||
bool WriteModuleStream(unsigned int index, MDRawModule *module);
|
||||
size_t CalculateStackSize(mach_vm_address_t start_addr);
|
||||
int FindExecutableModule();
|
||||
|
||||
// Per-CPU implementations of these methods
|
||||
#ifdef HAS_ARM_SUPPORT
|
||||
bool WriteStackARM(breakpad_thread_state_data_t state,
|
||||
MDMemoryDescriptor *stack_location);
|
||||
bool WriteContextARM(breakpad_thread_state_data_t state,
|
||||
MDLocationDescriptor *register_location);
|
||||
u_int64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
|
||||
#endif
|
||||
#ifdef HAS_PPC_SUPPORT
|
||||
bool WriteStackPPC(breakpad_thread_state_data_t state,
|
||||
MDMemoryDescriptor *stack_location);
|
||||
@@ -141,6 +160,7 @@ class MinidumpGenerator {
|
||||
MDLocationDescriptor *register_location);
|
||||
u_int64_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,
|
||||
@@ -151,14 +171,17 @@ class MinidumpGenerator {
|
||||
bool WriteContextX86_64(breakpad_thread_state_data_t state,
|
||||
MDLocationDescriptor *register_location);
|
||||
u_int64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
|
||||
#endif
|
||||
|
||||
// disallow copy ctor and operator=
|
||||
explicit MinidumpGenerator(const MinidumpGenerator &);
|
||||
void operator=(const MinidumpGenerator &);
|
||||
|
||||
protected:
|
||||
// Use this writer to put the data to disk
|
||||
MinidumpFileWriter writer_;
|
||||
|
||||
private:
|
||||
// Exception information
|
||||
int exception_type_;
|
||||
int exception_code_;
|
||||
@@ -183,6 +206,7 @@ class MinidumpGenerator {
|
||||
// directly from the system, even while handling an exception.
|
||||
mutable PageAllocator allocator_;
|
||||
|
||||
protected:
|
||||
// Blocks of memory written to the dump. These are all currently
|
||||
// written while writing the thread list stream, but saved here
|
||||
// so a memory list stream can be written afterwards.
|
||||
|
@@ -72,7 +72,7 @@
|
||||
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F760E8B0DC700D7E813 /* bytereader.cc */; };
|
||||
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */; };
|
||||
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721F780E8B0DC700D7E813 /* functioninfo.cc */; };
|
||||
F93A888B0E8B4C9A0026AF89 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = F9721FA80E8B0E4800D7E813 /* md5.c */; };
|
||||
F93A888B0E8B4C9A0026AF89 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9721FA80E8B0E4800D7E813 /* md5.cc */; };
|
||||
F9721F6C0E8B0D7000D7E813 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721F6B0E8B0D7000D7E813 /* Cocoa.framework */; };
|
||||
F9721FA20E8B0E2300D7E813 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */; };
|
||||
F982089C0DB3280D0017AECA /* breakpad_nlist_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */; };
|
||||
@@ -157,7 +157,7 @@
|
||||
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
|
||||
F9721F780E8B0DC700D7E813 /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; };
|
||||
F9721FA10E8B0E2300D7E813 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
F9721FA80E8B0E4800D7E813 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.c; path = ../../../common/md5.c; sourceTree = SOURCE_ROOT; };
|
||||
F9721FA80E8B0E4800D7E813 /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; };
|
||||
F982089A0DB3280D0017AECA /* breakpad_nlist_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_test.h; sourceTree = "<group>"; };
|
||||
F982089B0DB3280D0017AECA /* breakpad_nlist_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_test.cc; sourceTree = "<group>"; };
|
||||
F98208A10DB32CAE0017AECA /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_64.cc; sourceTree = "<group>"; };
|
||||
@@ -236,7 +236,7 @@
|
||||
8BFC812011FF99D5002CB4DC /* Breakpad.xcconfig */,
|
||||
8BFC812111FF99D5002CB4DC /* BreakpadDebug.xcconfig */,
|
||||
8BFC812211FF99D5002CB4DC /* BreakpadRelease.xcconfig */,
|
||||
F9721FA80E8B0E4800D7E813 /* md5.c */,
|
||||
F9721FA80E8B0E4800D7E813 /* md5.cc */,
|
||||
F9721F760E8B0DC700D7E813 /* bytereader.cc */,
|
||||
F9721F770E8B0DC700D7E813 /* dwarf2reader.cc */,
|
||||
F9721F780E8B0DC700D7E813 /* functioninfo.cc */,
|
||||
@@ -451,7 +451,14 @@
|
||||
isa = PBXProject;
|
||||
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "minidump_test" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
);
|
||||
mainGroup = 08FB7794FE84155DC02AAC07 /* MinidumpWriter */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -594,7 +601,7 @@
|
||||
F93A88880E8B4C9A0026AF89 /* bytereader.cc in Sources */,
|
||||
F93A88890E8B4C9A0026AF89 /* dwarf2reader.cc in Sources */,
|
||||
F93A888A0E8B4C9A0026AF89 /* functioninfo.cc in Sources */,
|
||||
F93A888B0E8B4C9A0026AF89 /* md5.c in Sources */,
|
||||
F93A888B0E8B4C9A0026AF89 /* md5.cc in Sources */,
|
||||
F93A887D0E8B4C8C0026AF89 /* macho_walker.cc in Sources */,
|
||||
F93A887E0E8B4C8C0026AF89 /* macho_id.cc in Sources */,
|
||||
F93A887F0E8B4C8C0026AF89 /* macho_utilities.cc in Sources */,
|
||||
|
@@ -55,21 +55,17 @@ void DynamicImagesTests::ReadTaskMemoryTest() {
|
||||
// pick test2 as a symbol we know to be valid to read
|
||||
// anything will work, really
|
||||
void *addr = reinterpret_cast<void*>(&test2);
|
||||
void *buf;
|
||||
std::vector<uint8_t> buf(getpagesize());
|
||||
|
||||
fprintf(stderr, "reading 0x%p\n", addr);
|
||||
buf = google_breakpad::ReadTaskMemory(mach_task_self(),
|
||||
addr,
|
||||
getpagesize(),
|
||||
&kr);
|
||||
kr = google_breakpad::ReadTaskMemory(mach_task_self(),
|
||||
(uint64_t)addr,
|
||||
getpagesize(),
|
||||
buf);
|
||||
|
||||
CPTAssert(kr == KERN_SUCCESS);
|
||||
|
||||
CPTAssert(buf != NULL);
|
||||
|
||||
CPTAssert(0 == memcmp(buf, (const void*)addr, getpagesize()));
|
||||
|
||||
free(buf);
|
||||
CPTAssert(0 == memcmp(&buf[0], (const void*)addr, getpagesize()));
|
||||
}
|
||||
|
||||
void DynamicImagesTests::ReadLibrariesFromLocalTaskTest() {
|
||||
@@ -79,7 +75,5 @@ void DynamicImagesTests::ReadLibrariesFromLocalTaskTest() {
|
||||
|
||||
fprintf(stderr,"Local task image count: %d\n", d->GetImageCount());
|
||||
|
||||
d->TestPrint();
|
||||
|
||||
CPTAssert(d->GetImageCount() > 0);
|
||||
}
|
||||
|
Reference in New Issue
Block a user