From 983264848d5372d8e64d62eb67f672c71e4b6470 Mon Sep 17 00:00:00 2001 From: waylonis Date: Wed, 7 Feb 2007 18:57:09 +0000 Subject: Fix bug with mach-o walker not properly walking universal binary (Issue #125) Fix exception handler so that it will properly forward exceptions (Issue #126) r=mmentovai git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@119 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/common/mac/macho_id.cc | 17 +++++++++++++++-- src/common/mac/macho_walker.cc | 39 ++++++++++++++++++++++++++++++++++++--- src/common/mac/macho_walker.h | 12 ++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) (limited to 'src/common') diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc index ca155ed4..59cd1e21 100644 --- a/src/common/mac/macho_id.cc +++ b/src/common/mac/macho_id.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -246,6 +247,12 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, if (swap) swap_segment_command(&seg, NXHostByteOrder()); + struct mach_header_64 header; + off_t header_offset; + + if (!walker->CurrentHeader(&header, &header_offset)) + return false; + // Process segments that have sections: // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) offset += sizeof(struct segment_command); @@ -257,7 +264,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, if (swap) swap_section(&sec, 1, NXHostByteOrder()); - macho_id->Update(walker, sec.offset, sec.size); + macho_id->Update(walker, header_offset + sec.offset, sec.size); offset += sizeof(struct section); } } else if (cmd->cmd == LC_SEGMENT_64) { @@ -269,6 +276,12 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, if (swap) swap_segment_command_64(&seg64, NXHostByteOrder()); + struct mach_header_64 header; + off_t header_offset; + + if (!walker->CurrentHeader(&header, &header_offset)) + return false; + // Process segments that have sections: // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) offset += sizeof(struct segment_command_64); @@ -280,7 +293,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, if (swap) swap_section_64(&sec64, 1, NXHostByteOrder()); - macho_id->Update(walker, sec64.offset, sec64.size); + macho_id->Update(walker, header_offset + sec64.offset, sec64.size); offset += sizeof(struct section_64); } } diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc index 5e9de5f4..81ba3bb5 100644 --- a/src/common/mac/macho_walker.cc +++ b/src/common/mac/macho_walker.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "common/mac/macho_walker.h" @@ -93,6 +94,16 @@ bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { return pread(file_, buffer, size, offset) == (ssize_t)size; } +bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { + if (current_header_) { + memcpy(header, current_header_, sizeof(mach_header_64)); + *offset = current_header_offset_; + return true; + } + + return false; +} + bool MachoWalker::FindHeader(int cpu_type, off_t &offset) { int valid_cpu_type = ValidateCPUType(cpu_type); // Read the magic bytes that's common amongst all mach-o files @@ -165,8 +176,22 @@ bool MachoWalker::WalkHeaderAtOffset(off_t offset) { bool swap = (header.magic == MH_CIGAM); if (swap) swap_mach_header(&header, NXHostByteOrder()); - - return WalkHeaderCore(offset + sizeof(header), header.ncmds, swap); + + // Copy the data into the mach_header_64 structure. Since the 32-bit and + // 64-bit only differ in the last field (reserved), this is safe to do. + struct mach_header_64 header64; + memcpy((void *)&header64, (const void *)&header, sizeof(header)); + header64.reserved = 0; + + current_header_ = &header64; + current_header_size_ = sizeof(header); // 32-bit, not 64-bit + current_header_offset_ = offset; + offset += current_header_size_; + bool result = WalkHeaderCore(offset, header.ncmds, swap); + current_header_ = NULL; + current_header_size_ = 0; + current_header_offset_ = 0; + return result; } bool MachoWalker::WalkHeader64AtOffset(off_t offset) { @@ -178,7 +203,15 @@ bool MachoWalker::WalkHeader64AtOffset(off_t offset) { if (swap) swap_mach_header_64(&header, NXHostByteOrder()); - return WalkHeaderCore(offset + sizeof(header), header.ncmds, swap); + current_header_ = &header; + current_header_size_ = sizeof(header); + current_header_offset_ = offset; + offset += current_header_size_; + bool result = WalkHeaderCore(offset, header.ncmds, swap); + current_header_ = NULL; + current_header_size_ = 0; + current_header_offset_ = 0; + return result; } bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands, diff --git a/src/common/mac/macho_walker.h b/src/common/mac/macho_walker.h index 0d55dd79..eb9575b0 100644 --- a/src/common/mac/macho_walker.h +++ b/src/common/mac/macho_walker.h @@ -68,6 +68,9 @@ class MachoWalker { // Read |size| bytes from the opened file at |offset| into |buffer| bool ReadBytes(void *buffer, size_t size, off_t offset); + + // Return the current header and header offset + bool CurrentHeader(struct mach_header_64 *header, off_t *offset); private: // Validate the |cpu_type| @@ -87,6 +90,15 @@ class MachoWalker { // User specified callback & context LoadCommandCallback callback_; void *callback_context_; + + // Current header, size, and offset. The mach_header_64 is used for both + // 32-bit and 64-bit headers because they only differ in their last field + // (reserved). By adding the |current_header_size_| and the + // |current_header_offset_|, you can determine the offset in the file just + // after the header. + struct mach_header_64 *current_header_; + unsigned long current_header_size_; + off_t current_header_offset_; }; } // namespace MacFileUtilities -- cgit v1.2.1