aboutsummaryrefslogtreecommitdiff
path: root/src/client/mac/handler/minidump_generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/mac/handler/minidump_generator.cc')
-rw-r--r--src/client/mac/handler/minidump_generator.cc346
1 files changed, 253 insertions, 93 deletions
diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc
index 8e3faf27..2e9765ad 100644
--- a/src/client/mac/handler/minidump_generator.cc
+++ b/src/client/mac/handler/minidump_generator.cc
@@ -31,7 +31,9 @@
#include <cstdio>
#include <mach/host_info.h>
+#include <mach/i386/thread_status.h>
#include <mach/mach_vm.h>
+#include <mach/ppc/thread_status.h>
#include <mach/vm_statistics.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
@@ -65,6 +67,7 @@ MinidumpGenerator::MinidumpGenerator()
exception_thread_(0),
crashing_task_(mach_task_self()),
handler_thread_(mach_thread_self()),
+ cpu_type_(DynamicImages::GetNativeCPUType()),
dynamic_images_(NULL),
memory_blocks_(&allocator_) {
GatherSystemInformation();
@@ -81,12 +84,15 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,
exception_thread_(0),
crashing_task_(crashing_task),
handler_thread_(handler_thread),
+ cpu_type_(DynamicImages::GetNativeCPUType()),
dynamic_images_(NULL),
memory_blocks_(&allocator_) {
if (crashing_task != mach_task_self()) {
dynamic_images_ = new DynamicImages(crashing_task_);
+ cpu_type_ = dynamic_images_->GetCPUType();
} else {
dynamic_images_ = NULL;
+ cpu_type_ = DynamicImages::GetNativeCPUType();
}
GatherSystemInformation();
@@ -254,8 +260,10 @@ size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {
return 0;
}
-
- if ((stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK) {
+ if (((cpu_type_ & CPU_ARCH_ABI64) &&
+ (stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK_64BIT) ||
+ (!(cpu_type_ & CPU_ARCH_ABI64) &&
+ (stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK_32BIT)) {
// The stack for thread 0 needs to extend all the way to
// 0xc0000000 on 32 bit and 00007fff5fc00000 on 64bit. HOWEVER,
// for many processes, the stack is first created in one page
@@ -305,20 +313,15 @@ bool MinidumpGenerator::WriteStackFromStartAddress(
return false;
if (dynamic_images_) {
-
- kern_return_t kr;
-
- void *stack_memory = ReadTaskMemory(crashing_task_,
- (void*)start_addr,
- size,
- &kr);
-
- if (stack_memory == NULL) {
+ vector<uint8_t> stack_memory;
+ if (ReadTaskMemory(crashing_task_,
+ start_addr,
+ size,
+ stack_memory) != KERN_SUCCESS) {
return false;
}
- result = memory.Copy(stack_memory, size);
- free(stack_memory);
+ result = memory.Copy(&stack_memory[0], size);
} else {
result = memory.Copy(reinterpret_cast<const void *>(start_addr), size);
}
@@ -330,34 +333,99 @@ bool MinidumpGenerator::WriteStackFromStartAddress(
return result;
}
-#if TARGET_CPU_PPC || TARGET_CPU_PPC64
bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location) {
- breakpad_thread_state_t *machine_state =
- reinterpret_cast<breakpad_thread_state_t *>(state);
+ switch (cpu_type_) {
+ case CPU_TYPE_POWERPC:
+ return WriteStackPPC(state, stack_location);
+ case CPU_TYPE_POWERPC64:
+ return WriteStackPPC64(state, stack_location);
+ case CPU_TYPE_I386:
+ return WriteStackX86(state, stack_location);
+ case CPU_TYPE_X86_64:
+ return WriteStackX86_64(state, stack_location);
+ default:
+ return false;
+ }
+}
+
+bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location) {
+ switch (cpu_type_) {
+ case CPU_TYPE_POWERPC:
+ return WriteContextPPC(state, register_location);
+ case CPU_TYPE_POWERPC64:
+ return WriteContextPPC64(state, register_location);
+ case CPU_TYPE_I386:
+ return WriteContextX86(state, register_location);
+ case CPU_TYPE_X86_64:
+ return WriteContextX86_64(state, register_location);
+ default:
+ return false;
+ }
+}
+
+u_int64_t MinidumpGenerator::CurrentPCForStack(
+ breakpad_thread_state_data_t state) {
+ switch (cpu_type_) {
+ case CPU_TYPE_POWERPC:
+ return CurrentPCForStackPPC(state);
+ case CPU_TYPE_POWERPC64:
+ return CurrentPCForStackPPC64(state);
+ case CPU_TYPE_I386:
+ return CurrentPCForStackX86(state);
+ case CPU_TYPE_X86_64:
+ return CurrentPCForStackX86_64(state);
+ default:
+ assert("Unknown CPU type!");
+ return 0;
+ }
+}
+
+bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state,
+ MDMemoryDescriptor *stack_location) {
+ ppc_thread_state_t *machine_state =
+ reinterpret_cast<ppc_thread_state_t *>(state);
+ mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
+ return WriteStackFromStartAddress(start_addr, stack_location);
+}
+
+bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state,
+ MDMemoryDescriptor *stack_location) {
+ ppc_thread_state64_t *machine_state =
+ reinterpret_cast<ppc_thread_state64_t *>(state);
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
return WriteStackFromStartAddress(start_addr, stack_location);
}
u_int64_t
-MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
- breakpad_thread_state_t *machine_state =
- reinterpret_cast<breakpad_thread_state_t *>(state);
+MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
+ ppc_thread_state_t *machine_state =
+ reinterpret_cast<ppc_thread_state_t *>(state);
return REGISTER_FROM_THREADSTATE(machine_state, srr0);
}
-bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
- TypedMDRVA<MinidumpContext> context(&writer_);
- breakpad_thread_state_t *machine_state =
- reinterpret_cast<breakpad_thread_state_t *>(state);
+u_int64_t
+MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) {
+ ppc_thread_state64_t *machine_state =
+ reinterpret_cast<ppc_thread_state64_t *>(state);
+
+ return REGISTER_FROM_THREADSTATE(machine_state, srr0);
+}
+
+bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location)
+{
+ TypedMDRVA<MDRawContextPPC> context(&writer_);
+ ppc_thread_state_t *machine_state =
+ reinterpret_cast<ppc_thread_state_t *>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MinidumpContext *context_ptr = context.get();
+ MDRawContextPPC *context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
@@ -402,57 +470,124 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
AddGPR(29);
AddGPR(30);
AddGPR(31);
-
-#if TARGET_CPU_PPC
- /* The mq register is only for PPC */
AddReg(mq);
-#endif
-
+#undef AddReg
+#undef AddGPR
return true;
}
-#elif TARGET_CPU_X86 || TARGET_CPU_X86_64
+bool MinidumpGenerator::WriteContextPPC64(
+ breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location) {
+ TypedMDRVA<MDRawContextPPC64> context(&writer_);
+ ppc_thread_state64_t *machine_state =
+ reinterpret_cast<ppc_thread_state64_t *>(state);
-bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
+ if (!context.Allocate())
+ return false;
+
+ *register_location = context.location();
+ MDRawContextPPC64 *context_ptr = context.get();
+ context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
+
+#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
+#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a)
+
+ AddReg(srr0);
+ AddReg(cr);
+ AddReg(xer);
+ AddReg(ctr);
+ AddReg(lr);
+ AddReg(vrsave);
+
+ AddGPR(0);
+ AddGPR(1);
+ AddGPR(2);
+ AddGPR(3);
+ AddGPR(4);
+ AddGPR(5);
+ AddGPR(6);
+ AddGPR(7);
+ AddGPR(8);
+ AddGPR(9);
+ AddGPR(10);
+ AddGPR(11);
+ AddGPR(12);
+ AddGPR(13);
+ AddGPR(14);
+ AddGPR(15);
+ AddGPR(16);
+ AddGPR(17);
+ AddGPR(18);
+ AddGPR(19);
+ AddGPR(20);
+ AddGPR(21);
+ AddGPR(22);
+ AddGPR(23);
+ AddGPR(24);
+ AddGPR(25);
+ AddGPR(26);
+ AddGPR(27);
+ AddGPR(28);
+ AddGPR(29);
+ AddGPR(30);
+ AddGPR(31);
+#undef AddReg
+#undef AddGPR
+
+ return true;
+}
+
+bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location) {
- breakpad_thread_state_t *machine_state =
- reinterpret_cast<breakpad_thread_state_t *>(state);
+ i386_thread_state_t *machine_state =
+ reinterpret_cast<i386_thread_state_t *>(state);
-#if TARGET_CPU_X86_64
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp);
-#else
mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp);
-#endif
+ return WriteStackFromStartAddress(start_addr, stack_location);
+}
+
+bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,
+ MDMemoryDescriptor *stack_location) {
+ x86_thread_state64_t *machine_state =
+ reinterpret_cast<x86_thread_state64_t *>(state);
+
+ mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp);
return WriteStackFromStartAddress(start_addr, stack_location);
}
u_int64_t
-MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
- breakpad_thread_state_t *machine_state =
- reinterpret_cast<breakpad_thread_state_t *>(state);
+MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
+ i386_thread_state_t *machine_state =
+ reinterpret_cast<i386_thread_state_t *>(state);
-#if TARGET_CPU_X86_64
- return REGISTER_FROM_THREADSTATE(machine_state, rip);
-#else
return REGISTER_FROM_THREADSTATE(machine_state, eip);
-#endif
}
-bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
- TypedMDRVA<MinidumpContext> context(&writer_);
- breakpad_thread_state_t *machine_state =
- reinterpret_cast<breakpad_thread_state_t *>(state);
+u_int64_t
+MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) {
+ x86_thread_state64_t *machine_state =
+ reinterpret_cast<x86_thread_state64_t *>(state);
+
+ return REGISTER_FROM_THREADSTATE(machine_state, rip);
+}
+
+bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location)
+{
+ TypedMDRVA<MDRawContextX86> context(&writer_);
+ i386_thread_state_t *machine_state =
+ reinterpret_cast<i386_thread_state_t *>(state);
if (!context.Allocate())
return false;
*register_location = context.location();
- MinidumpContext *context_ptr = context.get();
+ MDRawContextX86 *context_ptr = context.get();
#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
-#if TARGET_CPU_X86
+
context_ptr->context_flags = MD_CONTEXT_X86;
AddReg(eax);
AddReg(ebx);
@@ -472,7 +607,26 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
AddReg(eflags);
AddReg(eip);
-#else
+#undef AddReg(a)
+
+ return true;
+}
+
+bool MinidumpGenerator::WriteContextX86_64(
+ breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location) {
+ TypedMDRVA<MDRawContextAMD64> context(&writer_);
+ x86_thread_state64_t *machine_state =
+ reinterpret_cast<x86_thread_state64_t *>(state);
+
+ if (!context.Allocate())
+ return false;
+
+ *register_location = context.location();
+ MDRawContextAMD64 *context_ptr = context.get();
+
+#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
+
context_ptr->context_flags = MD_CONTEXT_AMD64;
AddReg(rax);
AddReg(rbx);
@@ -495,16 +649,38 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
// not used in the flags register. Since the minidump format
// specifies 32 bits for the flags register, we can truncate safely
// with no loss.
- context_ptr->eflags = static_cast<u_int32_t>(machine_state->__rflags);
+ context_ptr->eflags = static_cast<u_int32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));
AddReg(cs);
AddReg(fs);
AddReg(gs);
-#endif
#undef AddReg(a)
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_) {
+ case CPU_TYPE_POWERPC:
+ flavor = PPC_THREAD_STATE;
+ break;
+ case CPU_TYPE_POWERPC64:
+ flavor = PPC_THREAD_STATE64;
+ break;
+ case CPU_TYPE_I386:
+ flavor = i386_THREAD_STATE;
+ break;
+ case CPU_TYPE_X86_64:
+ flavor = x86_THREAD_STATE64;
+ break;
+ default:
+ return false;
+ }
+ return thread_get_state(target_thread, flavor,
+ state, count) == KERN_SUCCESS;
+}
bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
MDRawThread *thread) {
@@ -512,9 +688,7 @@ bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
mach_msg_type_number_t state_count
= static_cast<mach_msg_type_number_t>(sizeof(state));
- if (thread_get_state(thread_id, BREAKPAD_MACHINE_THREAD_STATE,
- state, &state_count) ==
- KERN_SUCCESS) {
+ if (GetThreadState(thread_id, state, &state_count)) {
if (!WriteStack(state, &thread->stack))
return false;
@@ -653,21 +827,15 @@ bool MinidumpGenerator::WriteMemoryListStream(
if (dynamic_images_) {
// Out-of-process.
- kern_return_t kr;
-
- void *memory =
- ReadTaskMemory(
- crashing_task_,
- reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range),
- ip_memory_d.memory.data_size,
- &kr);
-
- if (memory == NULL) {
+ vector<uint8_t> memory;
+ if (ReadTaskMemory(crashing_task_,
+ ip_memory_d.start_of_memory_range,
+ ip_memory_d.memory.data_size,
+ memory) != KERN_SUCCESS) {
return false;
}
- ip_memory.Copy(memory, ip_memory_d.memory.data_size);
- free(memory);
+ ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size);
} else {
// In-process, just copy from local memory.
ip_memory.Copy(
@@ -733,23 +901,23 @@ bool MinidumpGenerator::WriteSystemInfoStream(
system_info_stream->location = info.location();
// CPU Information
- uint32_t cpu_type;
- size_t len = sizeof(cpu_type);
- sysctlbyname("hw.cputype", &cpu_type, &len, NULL, 0);
uint32_t number_of_processors;
- len = sizeof(number_of_processors);
+ size_t len = sizeof(number_of_processors);
sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0);
MDRawSystemInfo *info_ptr = info.get();
- switch (cpu_type) {
+ switch (cpu_type_) {
case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC;
break;
case CPU_TYPE_I386:
case CPU_TYPE_X86_64:
- // hw.cputype is currently always I386 even on an x86-64 system
+ if (cpu_type_ == CPU_TYPE_I386)
+ info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86;
+ else
+ info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64;
#ifdef __i386__
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86;
// ebx is used for PIC code, so we need
// to preserve it.
#define cpuid(op,eax,ebx,ecx,edx) \
@@ -763,7 +931,7 @@ bool MinidumpGenerator::WriteSystemInfoStream(
"=d" (edx) \
: "0" (op))
#elif defined(__x86_64__)
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64;
+
#define cpuid(op,eax,ebx,ecx,edx) \
asm ("cpuid \n\t" \
: "=a" (eax), \
@@ -837,19 +1005,12 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
if (!image)
return false;
- const breakpad_mach_header *header = image->GetMachHeader();
-
- if (!header)
- return false;
-
- int cpu_type = header->cputype;
-
memset(module, 0, sizeof(MDRawModule));
MDLocationDescriptor string_location;
- const char* name = image->GetFilePath();
- if (!writer_.WriteString(name, 0, &string_location))
+ string name = image->GetFilePath();
+ if (!writer_.WriteString(name.c_str(), 0, &string_location))
return false;
module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide();
@@ -876,12 +1037,11 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
module->version_info.file_version_lo |= (modVersion & 0xff);
}
- if (!WriteCVRecord(module, cpu_type, name)) {
+ if (!WriteCVRecord(module, image->GetCPUType(), name.c_str())) {
return false;
}
} else {
- // we're getting module info in the crashed process
-
+ // Getting module info in the crashed process
const breakpad_mach_header *header;
header = (breakpad_mach_header*)_dyld_get_image_header(index);
if (!header)
@@ -903,7 +1063,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
unsigned long slide = _dyld_get_image_vmaddr_slide(index);
const char* name = _dyld_get_image_name(index);
const struct load_command *cmd =
- reinterpret_cast<const struct load_command *>(header + 1);
+ reinterpret_cast<const struct load_command *>(header + 1);
memset(module, 0, sizeof(MDRawModule));
@@ -911,7 +1071,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
if (cmd->cmd == LC_SEGMENT_ARCH) {
const breakpad_mach_segment_command *seg =
- reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
+ reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
MDLocationDescriptor string_location;