1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,270 @@ 1.4 +// Copyright (c) 2006, Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// macho_walker.cc: Iterate over the load commands in a mach-o file 1.34 +// 1.35 +// See macho_walker.h for documentation 1.36 +// 1.37 +// Author: Dan Waylonis 1.38 + 1.39 +extern "C" { // necessary for Leopard 1.40 + #include <assert.h> 1.41 + #include <fcntl.h> 1.42 + #include <mach-o/arch.h> 1.43 + #include <mach-o/loader.h> 1.44 + #include <mach-o/swap.h> 1.45 + #include <string.h> 1.46 + #include <unistd.h> 1.47 +} 1.48 + 1.49 +#include "common/mac/byteswap.h" 1.50 +#include "common/mac/macho_walker.h" 1.51 +#include "common/mac/macho_utilities.h" 1.52 + 1.53 +namespace MacFileUtilities { 1.54 + 1.55 +MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, 1.56 + void *context) 1.57 + : file_(0), 1.58 + memory_(NULL), 1.59 + memory_size_(0), 1.60 + callback_(callback), 1.61 + callback_context_(context), 1.62 + current_header_(NULL), 1.63 + current_header_size_(0), 1.64 + current_header_offset_(0) { 1.65 + file_ = open(path, O_RDONLY); 1.66 +} 1.67 + 1.68 +MachoWalker::MachoWalker(void *memory, size_t size, 1.69 + LoadCommandCallback callback, void *context) 1.70 + : file_(0), 1.71 + memory_(memory), 1.72 + memory_size_(size), 1.73 + callback_(callback), 1.74 + callback_context_(context), 1.75 + current_header_(NULL), 1.76 + current_header_size_(0), 1.77 + current_header_offset_(0) { 1.78 +} 1.79 + 1.80 +MachoWalker::~MachoWalker() { 1.81 + if (file_ != -1) 1.82 + close(file_); 1.83 +} 1.84 + 1.85 +bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { 1.86 + cpu_type_t valid_cpu_type = cpu_type; 1.87 + cpu_subtype_t valid_cpu_subtype = cpu_subtype; 1.88 + // if |cpu_type| is 0, use the native cpu type. 1.89 + if (cpu_type == 0) { 1.90 + const NXArchInfo *arch = NXGetLocalArchInfo(); 1.91 + assert(arch); 1.92 + valid_cpu_type = arch->cputype; 1.93 + valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE; 1.94 + } 1.95 + off_t offset; 1.96 + if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) { 1.97 + if (cpu_type & CPU_ARCH_ABI64) 1.98 + return WalkHeader64AtOffset(offset); 1.99 + 1.100 + return WalkHeaderAtOffset(offset); 1.101 + } 1.102 + 1.103 + return false; 1.104 +} 1.105 + 1.106 +bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { 1.107 + if (memory_) { 1.108 + if (offset < 0) 1.109 + return false; 1.110 + bool result = true; 1.111 + if (offset + size > memory_size_) { 1.112 + if (static_cast<size_t>(offset) >= memory_size_) 1.113 + return false; 1.114 + size = memory_size_ - static_cast<size_t>(offset); 1.115 + result = false; 1.116 + } 1.117 + memcpy(buffer, static_cast<char *>(memory_) + offset, size); 1.118 + return result; 1.119 + } else { 1.120 + return pread(file_, buffer, size, offset) == (ssize_t)size; 1.121 + } 1.122 +} 1.123 + 1.124 +bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { 1.125 + if (current_header_) { 1.126 + memcpy(header, current_header_, sizeof(mach_header_64)); 1.127 + *offset = current_header_offset_; 1.128 + return true; 1.129 + } 1.130 + 1.131 + return false; 1.132 +} 1.133 + 1.134 +bool MachoWalker::FindHeader(cpu_type_t cpu_type, 1.135 + cpu_subtype_t cpu_subtype, 1.136 + off_t &offset) { 1.137 + // Read the magic bytes that's common amongst all mach-o files 1.138 + uint32_t magic; 1.139 + if (!ReadBytes(&magic, sizeof(magic), 0)) 1.140 + return false; 1.141 + 1.142 + offset = sizeof(magic); 1.143 + 1.144 + // Figure out what type of file we've got 1.145 + bool is_fat = false; 1.146 + if (magic == FAT_MAGIC || magic == FAT_CIGAM) { 1.147 + is_fat = true; 1.148 + } 1.149 + else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 && 1.150 + magic != MH_CIGAM_64) { 1.151 + return false; 1.152 + } 1.153 + 1.154 + if (!is_fat) { 1.155 + // If we don't have a fat header, check if the cpu type matches the single 1.156 + // header 1.157 + struct mach_header header; 1.158 + if (!ReadBytes(&header, sizeof(header), 0)) 1.159 + return false; 1.160 + 1.161 + if (magic == MH_CIGAM || magic == MH_CIGAM_64) 1.162 + swap_mach_header(&header, NXHostByteOrder()); 1.163 + 1.164 + if (cpu_type != header.cputype || 1.165 + (cpu_subtype != CPU_SUBTYPE_MULTIPLE && 1.166 + cpu_subtype != header.cpusubtype)) { 1.167 + return false; 1.168 + } 1.169 + 1.170 + offset = 0; 1.171 + return true; 1.172 + } else { 1.173 + // Read the fat header and find an appropriate architecture 1.174 + offset = 0; 1.175 + struct fat_header fat; 1.176 + if (!ReadBytes(&fat, sizeof(fat), offset)) 1.177 + return false; 1.178 + 1.179 + if (NXHostByteOrder() != NX_BigEndian) 1.180 + swap_fat_header(&fat, NXHostByteOrder()); 1.181 + 1.182 + offset += sizeof(fat); 1.183 + 1.184 + // Search each architecture for the desired one 1.185 + struct fat_arch arch; 1.186 + for (uint32_t i = 0; i < fat.nfat_arch; ++i) { 1.187 + if (!ReadBytes(&arch, sizeof(arch), offset)) 1.188 + return false; 1.189 + 1.190 + if (NXHostByteOrder() != NX_BigEndian) 1.191 + swap_fat_arch(&arch, 1, NXHostByteOrder()); 1.192 + 1.193 + if (arch.cputype == cpu_type && 1.194 + (cpu_subtype == CPU_SUBTYPE_MULTIPLE || 1.195 + arch.cpusubtype == cpu_subtype)) { 1.196 + offset = arch.offset; 1.197 + return true; 1.198 + } 1.199 + 1.200 + offset += sizeof(arch); 1.201 + } 1.202 + } 1.203 + 1.204 + return false; 1.205 +} 1.206 + 1.207 +bool MachoWalker::WalkHeaderAtOffset(off_t offset) { 1.208 + struct mach_header header; 1.209 + if (!ReadBytes(&header, sizeof(header), offset)) 1.210 + return false; 1.211 + 1.212 + bool swap = (header.magic == MH_CIGAM); 1.213 + if (swap) 1.214 + swap_mach_header(&header, NXHostByteOrder()); 1.215 + 1.216 + // Copy the data into the mach_header_64 structure. Since the 32-bit and 1.217 + // 64-bit only differ in the last field (reserved), this is safe to do. 1.218 + struct mach_header_64 header64; 1.219 + memcpy((void *)&header64, (const void *)&header, sizeof(header)); 1.220 + header64.reserved = 0; 1.221 + 1.222 + current_header_ = &header64; 1.223 + current_header_size_ = sizeof(header); // 32-bit, not 64-bit 1.224 + current_header_offset_ = offset; 1.225 + offset += current_header_size_; 1.226 + bool result = WalkHeaderCore(offset, header.ncmds, swap); 1.227 + current_header_ = NULL; 1.228 + current_header_size_ = 0; 1.229 + current_header_offset_ = 0; 1.230 + return result; 1.231 +} 1.232 + 1.233 +bool MachoWalker::WalkHeader64AtOffset(off_t offset) { 1.234 + struct mach_header_64 header; 1.235 + if (!ReadBytes(&header, sizeof(header), offset)) 1.236 + return false; 1.237 + 1.238 + bool swap = (header.magic == MH_CIGAM_64); 1.239 + if (swap) 1.240 + breakpad_swap_mach_header_64(&header, NXHostByteOrder()); 1.241 + 1.242 + current_header_ = &header; 1.243 + current_header_size_ = sizeof(header); 1.244 + current_header_offset_ = offset; 1.245 + offset += current_header_size_; 1.246 + bool result = WalkHeaderCore(offset, header.ncmds, swap); 1.247 + current_header_ = NULL; 1.248 + current_header_size_ = 0; 1.249 + current_header_offset_ = 0; 1.250 + return result; 1.251 +} 1.252 + 1.253 +bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands, 1.254 + bool swap) { 1.255 + for (uint32_t i = 0; i < number_of_commands; ++i) { 1.256 + struct load_command cmd; 1.257 + if (!ReadBytes(&cmd, sizeof(cmd), offset)) 1.258 + return false; 1.259 + 1.260 + if (swap) 1.261 + swap_load_command(&cmd, NXHostByteOrder()); 1.262 + 1.263 + // Call the user callback 1.264 + if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_)) 1.265 + break; 1.266 + 1.267 + offset += cmd.cmdsize; 1.268 + } 1.269 + 1.270 + return true; 1.271 +} 1.272 + 1.273 +} // namespace MacFileUtilities