toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc

changeset 0
6474c204b198
     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

mercurial