diff --git a/src/client/mac/handler/dynamic_images.cc b/src/client/mac/handler/dynamic_images.cc index da1b7353..0fff084a 100644 --- a/src/client/mac/handler/dynamic_images.cc +++ b/src/client/mac/handler/dynamic_images.cc @@ -33,11 +33,13 @@ extern "C" { // needed to compile on Leopard #include } +#include +#include #include #include "client/mac/handler/dynamic_images.h" namespace google_breakpad { - + //============================================================================== // Returns the size of the memory region containing |address| and the // number of bytes from |address| to the end of the region. @@ -46,27 +48,30 @@ namespace google_breakpad { // first in order to handle cases when we're reading strings and they // straddle two vm regions. // -static vm_size_t GetMemoryRegionSize(task_port_t target_task, - const void* address, - vm_size_t *size_to_end) { - vm_address_t region_base = (vm_address_t)address; - vm_size_t region_size; +static mach_vm_size_t GetMemoryRegionSize(task_port_t target_task, + const void* address, + mach_vm_size_t *size_to_end) { + mach_vm_address_t region_base = (mach_vm_address_t)address; + mach_vm_size_t region_size; natural_t nesting_level = 0; vm_region_submap_info submap_info; mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT; - + // Get information about the vm region containing |address| - kern_return_t result = - vm_region_recurse(target_task, - ®ion_base, - ®ion_size, - &nesting_level, - reinterpret_cast(&submap_info), - &info_count); - + vm_region_recurse_info_t region_info; + region_info = reinterpret_cast(&submap_info); + + kern_return_t result = + mach_vm_region_recurse(target_task, + ®ion_base, + ®ion_size, + &nesting_level, + region_info, + &info_count); + if (result == KERN_SUCCESS) { // Get distance from |address| to the end of this region - *size_to_end = region_base + region_size -(vm_address_t)address; + *size_to_end = region_base + region_size -(mach_vm_address_t)address; // If we want to handle strings as long as 4096 characters we may need // to check if there's a vm region immediately following the first one. @@ -74,20 +79,19 @@ static vm_size_t GetMemoryRegionSize(task_port_t target_task, // of the second region. if (*size_to_end < 4096) { // Second region starts where the first one ends - vm_address_t region_base2 = - (vm_address_t)(region_base + region_size); - vm_size_t region_size2; + mach_vm_address_t region_base2 = + (mach_vm_address_t)(region_base + region_size); + mach_vm_size_t region_size2; // Get information about the following vm region - result = - vm_region_recurse( - target_task, - ®ion_base2, - ®ion_size2, - &nesting_level, - reinterpret_cast(&submap_info), - &info_count); - + result = + mach_vm_region_recurse(target_task, + ®ion_base2, + ®ion_size2, + &nesting_level, + region_info, + &info_count); + // Extend region_size to go all the way to the end of the 2nd region if (result == KERN_SUCCESS && region_base2 == region_base + region_size) { @@ -95,13 +99,13 @@ static vm_size_t GetMemoryRegionSize(task_port_t target_task, } } - *size_to_end = region_base + region_size -(vm_address_t)address; + *size_to_end = region_base + region_size -(mach_vm_address_t)address; } else { region_size = 0; *size_to_end = 0; } - - return region_size; + + return region_size; } #define kMaxStringLength 8192 @@ -115,17 +119,17 @@ static void* ReadTaskString(task_port_t target_task, // The problem is we don't know how much to read until we know how long // the string is. And we don't know how long the string is, until we've read // the memory! So, we'll try to read kMaxStringLength bytes - // (or as many bytes as we can until we reach the end of the vm region). - vm_size_t size_to_end; + // (or as many bytes as we can until we reach the end of the vm region). + mach_vm_size_t size_to_end; GetMemoryRegionSize(target_task, address, &size_to_end); - + if (size_to_end > 0) { - vm_size_t size_to_read = + mach_vm_size_t size_to_read = size_to_end > kMaxStringLength ? kMaxStringLength : size_to_end; return ReadTaskMemory(target_task, address, size_to_read); } - + return NULL; } @@ -136,27 +140,36 @@ void* ReadTaskMemory(task_port_t target_task, const void* address, size_t length) { void* result = NULL; - vm_address_t page_address = reinterpret_cast(address) & (-4096); - vm_address_t last_page_address = - (reinterpret_cast(address) + length + 4095) & (-4096); - vm_size_t page_size = last_page_address - page_address; + int systemPageSize = getpagesize(); + + // use the negative of the page size for the mask to find the page address + mach_vm_address_t page_address = + reinterpret_cast(address) && (-systemPageSize); + + mach_vm_address_t last_page_address = + (reinterpret_cast(address) + length + + (systemPageSize - 1)) & (-systemPageSize); + + mach_vm_size_t page_size = last_page_address - page_address; uint8_t* local_start; uint32_t local_length; - kern_return_t r = vm_read(target_task, - page_address, - page_size, - reinterpret_cast(&local_start), - &local_length); + kern_return_t r = mach_vm_read(target_task, + page_address, + page_size, + reinterpret_cast(&local_start), + &local_length); if (r == KERN_SUCCESS) { result = malloc(length); if (result != NULL) { - memcpy(result, &local_start[(uint32_t)address - page_address], length); + memcpy(result, + &local_start[(mach_vm_address_t)address - page_address], + length); } - vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length); + mach_vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length); } - + return result; } @@ -165,21 +178,37 @@ void* ReadTaskMemory(task_port_t target_task, //============================================================================== // Initializes vmaddr_, vmsize_, and slide_ void DynamicImage::CalculateMemoryInfo() { - mach_header *header = GetMachHeader(); + breakpad_mach_header *header = GetMachHeader(); + + // unless we can process the header, ensure that calls to + // IsValid() will return false + vmaddr_ = 0; + vmsize_ = 0; + slide_ = 0; + +#if __LP64__ + if(header->magic != MH_MAGIC_64) { + return; + } +#else + if(header->magic != MH_MAGIC) { + return; + } +#endif const struct load_command *cmd = reinterpret_cast(header + 1); for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) { if (cmd->cmd == LC_SEGMENT) { - const struct segment_command *seg = - reinterpret_cast(cmd); + const breakpad_mach_segment_command *seg = + reinterpret_cast(cmd); if (!strcmp(seg->segname, "__TEXT")) { vmaddr_ = seg->vmaddr; vmsize_ = seg->vmsize; slide_ = 0; - + if (seg->fileoff == 0 && seg->filesize != 0) { slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr; } @@ -190,11 +219,7 @@ void DynamicImage::CalculateMemoryInfo() { cmd = reinterpret_cast (reinterpret_cast(cmd) + cmd->cmdsize); } - - // we failed - a call to IsValid() will return false - vmaddr_ = 0; - vmsize_ = 0; - slide_ = 0; + } void DynamicImage::Print() { @@ -203,11 +228,11 @@ void DynamicImage::Print() { path = "(unknown)"; } printf("%p: %s\n", GetLoadAddress(), path); - mach_header *header = GetMachHeader(); + breakpad_mach_header *header = GetMachHeader(); MachHeader(*header).Print(); printf("vmaddr\t\t: %p\n", reinterpret_cast(GetVMAddr())); - printf("vmsize\t\t: %d\n", GetVMSize()); - printf("slide\t\t: %d\n", GetVMAddrSlide()); + printf("vmsize\t\t: %llu\n", GetVMSize()); + printf("slide\t\t: %td\n", GetVMAddrSlide()); } #pragma mark - @@ -231,7 +256,7 @@ void DynamicImages::ReadImageInfoForTask() { struct nlist &list = l[0]; list.n_un.n_name = const_cast("_dyld_all_image_infos"); nlist("/usr/lib/dyld", &list); - + if (list.n_value) { // Read the structure inside of dyld that contains information about // loaded images. We're reading from the desired task's address space. @@ -261,19 +286,23 @@ void DynamicImages::ReadImageInfoForTask() { dyld_image_info &info = infoArray[i]; // First read just the mach_header from the image in the task. - mach_header *header = reinterpret_cast - (ReadTaskMemory(task_, info.load_address_, sizeof(mach_header))); + breakpad_mach_header *header = reinterpret_cast + (ReadTaskMemory(task_, + info.load_address_, + sizeof(breakpad_mach_header))); if (!header) break; // bail on this dynamic image - + // Now determine the total amount we really want to read based on the - // size of the load commands. We need the header plus all of the + // size of the load commands. We need the header plus all of the // load commands. - unsigned int header_size = sizeof(mach_header) + header->sizeofcmds; + unsigned int header_size = + sizeof(breakpad_mach_header) + header->sizeofcmds; + free(header); - header = reinterpret_cast + header = reinterpret_cast (ReadTaskMemory(task_, info.load_address_, header_size)); // Read the file name from the task's memory space. @@ -285,43 +314,44 @@ void DynamicImages::ReadImageInfoForTask() { file_path = reinterpret_cast (ReadTaskString(task_, info.file_path_)); } - + // Create an object representing this image and add it to our list. - DynamicImage *new_image = new DynamicImage(header, - header_size, - info.load_address_, - file_path, - info.file_mod_date_, - task_); + DynamicImage *new_image; + new_image = new DynamicImage(header, + header_size, + (breakpad_mach_header*)info.load_address_, + file_path, + info.file_mod_date_, + task_); if (new_image->IsValid()) { image_list_.push_back(DynamicImageRef(new_image)); } else { delete new_image; } - + if (file_path) { free(file_path); } } - + free(dyldInfo); free(infoArray); - + // sorts based on loading address sort(image_list_.begin(), image_list_.end() ); } - } + } } //============================================================================== DynamicImage *DynamicImages::GetExecutableImage() { int executable_index = GetExecutableImageIndex(); - + if (executable_index >= 0) { return GetImage(executable_index); } - + return NULL; } diff --git a/src/client/mac/handler/dynamic_images.h b/src/client/mac/handler/dynamic_images.h index d6762c77..e780eeb1 100644 --- a/src/client/mac/handler/dynamic_images.h +++ b/src/client/mac/handler/dynamic_images.h @@ -68,13 +68,23 @@ typedef struct dyld_all_image_infos { bool processDetachedFromSharedRegion; } dyld_all_image_infos; +// some typedefs to isolate 64/32 bit differences +#ifdef __LP64__ +typedef mach_header_64 breakpad_mach_header; +typedef segment_command_64 breakpad_mach_segment_command; +#else +typedef mach_header breakpad_mach_header; +typedef segment_command breakpad_mach_segment_command; +#endif + + //============================================================================== // A simple wrapper for a mach_header // // This could be fleshed out with some more interesting methods. class MachHeader { public: - explicit MachHeader(const mach_header &header) : header_(header) {} + explicit MachHeader(const breakpad_mach_header &header) : header_(header) {} void Print() { printf("magic\t\t: %4x\n", header_.magic); @@ -86,16 +96,16 @@ class MachHeader { printf("flags\t\t: %d\n", header_.flags); } - mach_header header_; + breakpad_mach_header header_; }; //============================================================================== // Represents a single dynamically loaded mach-o image class DynamicImage { public: - DynamicImage(mach_header *header, // we take ownership - int header_size, // includes load commands - mach_header *load_address, + DynamicImage(breakpad_mach_header *header, // we take ownership + int header_size, // includes load commands + breakpad_mach_header *load_address, char *inFilePath, uintptr_t image_mod_date, mach_port_t task) @@ -116,7 +126,7 @@ class DynamicImage { } // Returns pointer to a local copy of the mach_header plus load commands - mach_header *GetMachHeader() {return header_;} + breakpad_mach_header *GetMachHeader() {return header_;} // Size of mach_header plus load commands int GetHeaderSize() const {return header_size_;} @@ -127,16 +137,16 @@ class DynamicImage { uintptr_t GetModDate() const {return file_mod_date_;} // Actual address where the image was loaded - mach_header *GetLoadAddress() const {return load_address_;} + breakpad_mach_header *GetLoadAddress() const {return load_address_;} // Address where the image should be loaded - uint32_t GetVMAddr() const {return vmaddr_;} + mach_vm_address_t GetVMAddr() const {return vmaddr_;} // Difference between GetLoadAddress() and GetVMAddr() ptrdiff_t GetVMAddrSlide() const {return slide_;} // Size of the image - uint32_t GetVMSize() const {return vmsize_;} + mach_vm_size_t GetVMSize() const {return vmsize_;} // Task owning this loaded image mach_port_t GetTask() {return task_;} @@ -183,23 +193,25 @@ class DynamicImage { InitializeFilePath(inInfo.GetFilePath()); // copy mach_header and load commands - header_ = reinterpret_cast(malloc(inInfo.header_size_)); + void *headerBuffer = malloc(inInfo.header_size_); + header_ = reinterpret_cast(headerBuffer); + memcpy(header_, inInfo.header_, inInfo.header_size_); header_size_ = inInfo.header_size_; } #endif - mach_header *header_; // our local copy of the header - int header_size_; // mach_header plus load commands - mach_header *load_address_; // base address image is mapped into - uint32_t vmaddr_; - uint32_t vmsize_; - ptrdiff_t slide_; + breakpad_mach_header *header_; // our local copy of the header + int header_size_; // mach_header plus load commands + breakpad_mach_header *load_address_; // base address image is mapped into + mach_vm_address_t vmaddr_; + mach_vm_size_t vmsize_; + ptrdiff_t slide_; - char *file_path_; // path dyld used to load the image - uintptr_t file_mod_date_; // time_t of image file + char *file_path_; // path dyld used to load the image + uintptr_t file_mod_date_; // time_t of image file - mach_port_t task_; + mach_port_t task_; }; //============================================================================== @@ -211,7 +223,8 @@ class DynamicImage { class DynamicImageRef { public: explicit DynamicImageRef(DynamicImage *inP) : p(inP) {} - DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} // STL required + // The copy constructor is required by STL + DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {} bool operator<(const DynamicImageRef &inRef) const { return (*const_cast(this)->p) @@ -266,10 +279,14 @@ class DynamicImages { } void TestPrint() { + const breakpad_mach_header *header; for (int i = 0; i < (int)image_list_.size(); ++i) { printf("dyld: %p: name = %s\n", _dyld_get_image_header(i), - _dyld_get_image_name(i) ); - const mach_header *header = _dyld_get_image_header(i); + _dyld_get_image_name(i) ); + + const void *imageHeader = _dyld_get_image_header(i); + header = reinterpret_cast(imageHeader); + MachHeader(*header).Print(); } } diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc index f6d1811d..75812929 100644 --- a/src/client/mac/handler/minidump_generator.cc +++ b/src/client/mac/handler/minidump_generator.cc @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,7 @@ using MacStringUtils::IntegerValueAtIndex; namespace google_breakpad { -// constructor when generating from within the crashed process +// constructor when generating from within the crashed process MinidumpGenerator::MinidumpGenerator() : exception_type_(0), exception_code_(0), @@ -59,8 +60,10 @@ MinidumpGenerator::MinidumpGenerator() GatherSystemInformation(); } -// constructor when generating from a different process than the crashed process -MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread) +// constructor when generating from a different process than the +// crashed process +MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, + mach_port_t handler_thread) : exception_type_(0), exception_code_(0), exception_thread_(0), @@ -71,7 +74,7 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, mach_port_t hand } else { dynamic_images_ = NULL; } - + GatherSystemInformation(); } @@ -89,26 +92,29 @@ void MinidumpGenerator::GatherSystemInformation() { // If this is non-zero, then we've already gathered the information if (os_major_version_) return; - + // This code extracts the version and build information from the OS CFStringRef vers_path = CFSTR("/System/Library/CoreServices/SystemVersion.plist"); CFURLRef sys_vers = - CFURLCreateWithFileSystemPath(NULL, vers_path, kCFURLPOSIXPathStyle, false); + CFURLCreateWithFileSystemPath(NULL, + vers_path, + kCFURLPOSIXPathStyle, + false); CFDataRef data; SInt32 error; CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL, &error); - + if (!data) return; - + CFDictionaryRef list = static_cast (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL)); if (!list) return; - + CFStringRef build_version = static_cast (CFDictionaryGetValue(list, CFSTR("ProductBuildVersion"))); CFStringRef product_version = static_cast @@ -207,35 +213,45 @@ bool MinidumpGenerator::Write(const char *path) { return result; } -size_t MinidumpGenerator::CalculateStackSize(vm_address_t start_addr) { - vm_address_t stack_region_base = start_addr; - vm_size_t stack_region_size; +size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) { + mach_vm_address_t stack_region_base = start_addr; + mach_vm_size_t stack_region_size; natural_t nesting_level = 0; vm_region_submap_info submap_info; mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT; - kern_return_t result = - vm_region_recurse(crashing_task_, &stack_region_base, &stack_region_size, - &nesting_level, - reinterpret_cast(&submap_info), - &info_count); - if ((stack_region_base + stack_region_size) == 0xbffff000) { - // The stack for thread 0 needs to extend all the way to 0xc0000000 - // For many processes the stack is first created in one page - // from 0xbffff000 - 0xc0000000 and is then later extended to - // a much larger size by creating a new VM region immediately below - // the initial page + vm_region_recurse_info_t region_info; + region_info = reinterpret_cast(&submap_info); - // include the original stack frame page (0xbffff000 - 0xc0000000) - stack_region_size += 0x1000; + kern_return_t result = + mach_vm_region_recurse(crashing_task_, &stack_region_base, + &stack_region_size, &nesting_level, + region_info, + &info_count); + + if ((stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK) { + // 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 + // below this, and is then later extended to a much larger size by + // creating a new VM region immediately below the initial page. + + // You can see this for yourself by running vmmap on a "hello, + // world" program + + // Because of the above, we'll add 4k to include the original + // stack frame page. + // This method of finding the stack region needs to be done in + // a better way; the breakpad issue 247 is tracking this. + stack_region_size += 0x1000; } - return result == KERN_SUCCESS ? + return result == KERN_SUCCESS ? stack_region_base + stack_region_size - start_addr : 0; } bool MinidumpGenerator::WriteStackFromStartAddress( - vm_address_t start_addr, + mach_vm_address_t start_addr, MDMemoryDescriptor *stack_location) { UntypedMDRVA memory(&writer_); size_t size = CalculateStackSize(start_addr); @@ -250,55 +266,73 @@ bool MinidumpGenerator::WriteStackFromStartAddress( bool result; if (dynamic_images_) { - void *stack_memory = ReadTaskMemory(crashing_task_, (void*)start_addr, size); + + void *stack_memory = ReadTaskMemory(crashing_task_, + (void*)start_addr, + size); + result = memory.Copy(stack_memory, size); free(stack_memory); } else { result = memory.Copy(reinterpret_cast(start_addr), size); } - + stack_location->start_of_memory_range = start_addr; stack_location->memory = memory.location(); return result; } -#if TARGET_CPU_PPC +#if TARGET_CPU_PPC || TARGET_CPU_PPC64 bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, MDMemoryDescriptor *stack_location) { - ppc_thread_state_t *machine_state = - reinterpret_cast(state); - vm_address_t start_addr = machine_state->r1; + breakpad_thread_state_t *machine_state = + reinterpret_cast(state); +#if TARGET_CPU_PPC + mach_vm_address_t start_addr = machine_state->r1; +#else + mach_vm_address_t start_addr = machine_state->__r1; +#endif return WriteStackFromStartAddress(start_addr, stack_location); } -u_int64_t MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { - ppc_thread_state_t *machine_state = - reinterpret_cast(state); +u_int64_t +MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { + breakpad_thread_state_t *machine_state = + reinterpret_cast(state); +#if TARGET_CPU_PPC return machine_state->srr0; +#else + return machine_state->__srr0; +#endif } bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, MDLocationDescriptor *register_location) { - TypedMDRVA context(&writer_); - ppc_thread_state_t *machine_state = - reinterpret_cast(state); + TypedMDRVA context(&writer_); + breakpad_thread_state_t *machine_state = + reinterpret_cast(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextPPC *context_ptr = context.get(); + MinidumpContext *context_ptr = context.get(); context_ptr->context_flags = MD_CONTEXT_PPC_BASE; +#if TARGET_CPU_PPC64 +#define AddReg(a) context_ptr->a = machine_state->__ ## a +#define AddGPR(a) context_ptr->gpr[a] = machine_state->__r ## a +#else #define AddReg(a) context_ptr->a = machine_state->a #define AddGPR(a) context_ptr->gpr[a] = machine_state->r ## a +#endif + AddReg(srr0); AddReg(cr); AddReg(xer); AddReg(ctr); - AddReg(mq); AddReg(lr); AddReg(vrsave); @@ -334,38 +368,68 @@ 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 + + return true; } -#elif TARGET_CPU_X86 +#elif TARGET_CPU_X86 || TARGET_CPU_X86_64 + bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, MDMemoryDescriptor *stack_location) { - i386_thread_state_t *machine_state = - reinterpret_cast(state); - vm_address_t start_addr = machine_state->esp; + breakpad_thread_state_t *machine_state = + reinterpret_cast(state); + +#if TARGET_CPU_X86_64 + mach_vm_address_t start_addr = machine_state->__rsp; +#else + mach_vm_address_t start_addr = machine_state->esp; +#endif return WriteStackFromStartAddress(start_addr, stack_location); } -u_int64_t MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { - i386_thread_state_t *machine_state = - reinterpret_cast(state); +u_int64_t +MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { + breakpad_thread_state_t *machine_state = + reinterpret_cast(state); +#if TARGET_CPU_X86_64 + return machine_state->__rip; +#else return machine_state->eip; +#endif } bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, MDLocationDescriptor *register_location) { - TypedMDRVA context(&writer_); - i386_thread_state_t *machine_state = - reinterpret_cast(state); + TypedMDRVA context(&writer_); + breakpad_thread_state_t *machine_state = + reinterpret_cast(state); if (!context.Allocate()) return false; *register_location = context.location(); - MDRawContextX86 *context_ptr = context.get(); + MinidumpContext *context_ptr = context.get(); + +#if TARGET_CPU_X86 context_ptr->context_flags = MD_CONTEXT_X86; + #define AddReg(a) context_ptr->a = machine_state->a + AddReg(eax); + AddReg(ebx); + AddReg(ecx); + AddReg(edx); + AddReg(esi); + AddReg(edi); + AddReg(ebp); + AddReg(esp); + AddReg(cs); AddReg(ds); AddReg(ss); @@ -375,16 +439,40 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, AddReg(eflags); AddReg(eip); - AddReg(eax); - AddReg(ebx); - AddReg(ecx); - AddReg(edx); - AddReg(esi); - AddReg(edi); - AddReg(ebp); - AddReg(esp); +#else + +#define AddReg(a) context_ptr->a = machine_state->__ ## a + context_ptr->context_flags = MD_CONTEXT_AMD64; + AddReg(rax); + AddReg(rbx); + AddReg(rcx); + AddReg(rdx); + AddReg(rdi); + AddReg(rsi); + AddReg(rbp); + AddReg(rsp); + AddReg(r8); + AddReg(r9); + AddReg(r10); + AddReg(r11); + AddReg(r12); + AddReg(r13); + AddReg(r14); + AddReg(r15); + AddReg(rip); + // according to AMD's software developer guide, bits above 18 are + // 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 = machine_state->__rflags; + AddReg(cs); + AddReg(fs); + AddReg(gs); +#endif + return true; } + #endif bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, @@ -447,7 +535,8 @@ bool MinidumpGenerator::WriteThreadListStream( return true; } -bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { +bool +MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { TypedMDRVA exception(&writer_); if (!exception.Allocate()) @@ -466,7 +555,9 @@ bool MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { breakpad_thread_state_data_t state; mach_msg_type_number_t stateCount = sizeof(state); - if (thread_get_state(exception_thread_, BREAKPAD_MACHINE_THREAD_STATE, state, + if (thread_get_state(exception_thread_, + BREAKPAD_MACHINE_THREAD_STATE, + state, &stateCount) != KERN_SUCCESS) return false; @@ -508,13 +599,13 @@ bool MinidumpGenerator::WriteSystemInfoStream( // to preserve it. #define cpuid(op,eax,ebx,ecx,edx) \ asm ("pushl %%ebx \n\t" \ - "cpuid \n\t" \ - "movl %%ebx,%1 \n\t" \ - "popl %%ebx" \ - : "=a" (eax), \ - "=g" (ebx), \ - "=c" (ecx), \ - "=d" (edx) \ + "cpuid \n\t" \ + "movl %%ebx,%1 \n\t" \ + "popl %%ebx" \ + : "=a" (eax), \ + "=g" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ : "0" (op)) int unused, unused2; // get vendor id @@ -564,7 +655,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, if (!image) return false; - const mach_header *header = image->GetMachHeader(); + const breakpad_mach_header *header = image->GetMachHeader(); if (!header) return false; @@ -588,11 +679,24 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, } } else { // we're getting module info in the crashed process - const struct mach_header *header = _dyld_get_image_header(index); + const breakpad_mach_header *header; + header = (breakpad_mach_header*)_dyld_get_image_header(index); if (!header) return false; +#ifdef __LP64__ + assert(header->magic == MH_MAGIC_64); + + if(header->magic != MH_MAGIC_64) + return false; +#else + assert(header->magic == MH_MAGIC); + + if(header->magic != MH_MAGIC) + return false; +#endif + int cpu_type = header->cputype; unsigned long slide = _dyld_get_image_vmaddr_slide(index); const char* name = _dyld_get_image_name(index); @@ -603,8 +707,10 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, for (unsigned int i = 0; cmd && (i < header->ncmds); i++) { if (cmd->cmd == LC_SEGMENT) { - const struct segment_command *seg = - reinterpret_cast(cmd); + + const breakpad_mach_segment_command *seg = + reinterpret_cast(cmd); + if (!strcmp(seg->segname, "__TEXT")) { MDLocationDescriptor string_location; @@ -622,10 +728,10 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, } } - cmd = reinterpret_cast((char *)cmd + cmd->cmdsize); + cmd = reinterpret_cast((char *)cmd + cmd->cmdsize); } } - + return true; } @@ -647,7 +753,7 @@ int MinidumpGenerator::FindExecutableModule() { return index; } } - + // failed - just use the first image return 0; } @@ -681,9 +787,9 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, // Get the module identifier FileID file_id(module_path); unsigned char identifier[16]; - + if (file_id.MachoIdentifier(cpu_type, identifier)) { - cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 | + cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 | (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 | (uint32_t)identifier[3]; cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5]; @@ -705,9 +811,6 @@ bool MinidumpGenerator::WriteModuleListStream( MDRawDirectory *module_list_stream) { TypedMDRVA list(&writer_); - if (!_dyld_present()) - return false; - int image_count = dynamic_images_ ? dynamic_images_->GetImageCount() : _dyld_image_count(); @@ -770,12 +873,15 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, info_ptr->process_id }; size_t size; if (!sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &size, NULL, 0)) { - vm_address_t addr; - if (vm_allocate(mach_task_self(), &addr, size, true) == KERN_SUCCESS) { + 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, sizeof(mib) / sizeof(mib[0]), proc, &size, NULL, 0)) info_ptr->process_create_time = proc->kp_proc.p_starttime.tv_sec; - vm_deallocate(mach_task_self(), addr, size); + mach_vm_deallocate(mach_task_self(), addr, size); } } diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h index 33d84c1c..0d3424c3 100644 --- a/src/client/mac/handler/minidump_generator.h +++ b/src/client/mac/handler/minidump_generator.h @@ -46,6 +46,26 @@ namespace google_breakpad { using std::string; +#if TARGET_CPU_X86_64 || TARGET_CPU_PPC64 +#define TOP_OF_THREAD0_STACK 0x00007fff5fbff000 +#else +#define TOP_OF_THREAD0_STACK 0xbffff000 +#endif + +#if TARGET_CPU_X86_64 +typedef x86_thread_state64_t breakpad_thread_state_t; +typedef MDRawContextAMD64 MinidumpContext; +#elif TARGET_CPU_X86 +typedef i386_thread_state_t breakpad_thread_state_t; +typedef MDRawContextX86 MinidumpContext; +#elif TARGET_CPU_PPC64 +typedef ppc_thread_state64_t breakpad_thread_state_t; +typedef MDRawContextPPC64 MinidumpContext; +#elif TARGET_CPU_PPC +typedef ppc_thread_state_t breakpad_thread_state_t; +typedef MDRawContextPPC MinidumpContext; +#endif + // Creates a minidump file of the current process. If there is exception data, // use SetExceptionInformation() to add this to the minidump. The minidump // file is generated by the Write() function. @@ -93,7 +113,7 @@ class MinidumpGenerator { // Helpers u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state); - bool WriteStackFromStartAddress(vm_address_t start_addr, + bool WriteStackFromStartAddress(mach_vm_address_t start_addr, MDMemoryDescriptor *stack_location); bool WriteStack(breakpad_thread_state_data_t state, MDMemoryDescriptor *stack_location); @@ -103,7 +123,9 @@ class MinidumpGenerator { bool WriteCVRecord(MDRawModule *module, int cpu_type, const char *module_path); bool WriteModuleStream(unsigned int index, MDRawModule *module); - size_t CalculateStackSize(vm_address_t start_addr); + + size_t CalculateStackSize(mach_vm_address_t start_addr); + int FindExecutableModule(); // disallow copy ctor and operator= diff --git a/src/client/mac/handler/minidump_generator_test.cc b/src/client/mac/handler/minidump_generator_test.cc index c5f01ae9..62530832 100644 --- a/src/client/mac/handler/minidump_generator_test.cc +++ b/src/client/mac/handler/minidump_generator_test.cc @@ -48,9 +48,13 @@ static void *Reporter(void *) { struct passwd *user = getpwuid(getuid()); // Write it to the desktop - snprintf(buffer, sizeof(buffer), "/Users/%s/Desktop/test.dmp", user->pw_name); + snprintf(buffer, + sizeof(buffer), + "/Users/%s/Desktop/test.dmp", + user->pw_name); + fprintf(stdout, "Writing %s\n", buffer); - + unlink(buffer); md.Write(buffer); doneWritingReport = true;