135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// Copyright (c) 2010, Google Inc.
235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// All rights reserved.
335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek//
435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// Redistribution and use in source and binary forms, with or without
535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// modification, are permitted provided that the following conditions are
635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// met:
735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek//
835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek//     * Redistributions of source code must retain the above copyright
935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// notice, this list of conditions and the following disclaimer.
1035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek//     * Redistributions in binary form must reproduce the above
1135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// copyright notice, this list of conditions and the following disclaimer
1235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// in the documentation and/or other materials provided with the
1335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// distribution.
1435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek//     * Neither the name of Google Inc. nor the names of its
1535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// contributors may be used to endorse or promote products derived from
1635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// this software without specific prior written permission.
1735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek//
1835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
3035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
3135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
3235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and
3335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// google_breakpad::Mach_O::Reader. See macho_reader.h for details.
3435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
3535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include "common/mac/macho_reader.h"
3635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
3735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include <assert.h>
3835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include <stdio.h>
3935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#include <stdlib.h>
4035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
41316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org// Unfortunately, CPU_TYPE_ARM is not define for 10.4.
42316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org#if !defined(CPU_TYPE_ARM)
43316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org#define CPU_TYPE_ARM 12
44316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org#endif
45316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org
46d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org#if !defined(CPU_TYPE_ARM_64)
47d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org#define CPU_TYPE_ARM_64 16777228
48d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org#endif
49d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org
5035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczareknamespace google_breakpad {
5135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczareknamespace mach_o {
5235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
5335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its
5435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// arguments, so you can't place expressions that do necessary work in
5535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// the argument of an assert. Nor can you assign the result of the
5635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// expression to a variable and assert that the variable's value is
5735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// true: you'll get unused variable warnings when NDEBUG is #defined.
5835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek//
5935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that
6035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// the result is true if NDEBUG is not #defined.
6135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#if defined(NDEBUG)
6235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#define ASSERT_ALWAYS_EVAL(x) (x)
6335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#else
6435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#define ASSERT_ALWAYS_EVAL(x) assert(x)
6535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek#endif
6635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
6735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid FatReader::Reporter::BadHeader() {
6835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: file is neither a fat binary file"
6935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " nor a Mach-O object file\n", filename_.c_str());
7035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
7135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
7235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid FatReader::Reporter::TooShort() {
7335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: file too short for the data it claims to contain\n",
7435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str());
7535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
7635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
7735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid FatReader::Reporter::MisplacedObjectFile() {
7835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: file too short for the object files it claims"
7935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " to contain\n", filename_.c_str());
8035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
8135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
8235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool FatReader::Read(const uint8_t *buffer, size_t size) {
8335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  buffer_.start = buffer;
8435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  buffer_.end = buffer + size;
8535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  ByteCursor cursor(&buffer_);
8635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
8735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // Fat binaries always use big-endian, so read the magic number in
8835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // that endianness. To recognize Mach-O magic numbers, which can use
8935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // either endianness, check for both the proper and reversed forms
9035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // of the magic numbers.
9135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  cursor.set_big_endian(true);
9235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (cursor >> magic_) {
9335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (magic_ == FAT_MAGIC) {
9435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // How many object files does this fat binary contain?
9535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      uint32_t object_files_count;
9635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      if (!(cursor >> object_files_count)) {  // nfat_arch
9735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        reporter_->TooShort();
9835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        return false;
9935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      }
10035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
10135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // Read the list of object files.
10235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      object_files_.resize(object_files_count);
10335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      for (size_t i = 0; i < object_files_count; i++) {
10435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        struct fat_arch *objfile = &object_files_[i];
10535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
10635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // Read this object file entry, byte-swapping as appropriate.
10735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        cursor >> objfile->cputype
10835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               >> objfile->cpusubtype
10935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               >> objfile->offset
11035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               >> objfile->size
11135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               >> objfile->align;
11235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (!cursor) {
11335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          reporter_->TooShort();
11435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
11535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        }
11635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // Does the file actually have the bytes this entry refers to?
11735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        size_t fat_size = buffer_.Size();
11835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (objfile->offset > fat_size ||
11935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek            objfile->size > fat_size - objfile->offset) {
12035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          reporter_->MisplacedObjectFile();
12135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
12235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        }
12335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      }
12435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
12535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return true;
12635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    } else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 ||
12735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) {
12835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // If this is a little-endian Mach-O file, fix the cursor's endianness.
12935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64)
13035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        cursor.set_big_endian(false);
13135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // Record the entire file as a single entry in the object file list.
13235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      object_files_.resize(1);
13335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
13435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // Get the cpu type and subtype from the Mach-O header.
13535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      if (!(cursor >> object_files_[0].cputype
13635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                   >> object_files_[0].cpusubtype)) {
13735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        reporter_->TooShort();
13835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        return false;
13935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      }
14035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
14135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      object_files_[0].offset = 0;
1424ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach      object_files_[0].size = static_cast<uint32_t>(buffer_.Size());
14335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // This alignment is correct for 32 and 64-bit x86 and ppc.
14435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // See get_align in the lipo source for other architectures:
14535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
14635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      object_files_[0].align = 12;  // 2^12 == 4096
14735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
14835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return true;
14935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
15035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
15135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
15235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  reporter_->BadHeader();
15335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  return false;
15435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
15535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
15635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::BadHeader() {
15735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str());
15835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
15935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
16035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type,
16135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                       cpu_subtype_t cpu_subtype,
16235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                       cpu_type_t expected_cpu_type,
16335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                       cpu_subtype_t expected_cpu_subtype) {
16435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected"
16535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " type %d, subtype %d\n",
16635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str(), cpu_type, cpu_subtype,
16735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          expected_cpu_type, expected_cpu_subtype);
16835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
16935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
17035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::HeaderTruncated() {
17135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: file does not contain a complete Mach-O header\n",
17235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str());
17335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
17435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
17535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::LoadCommandRegionTruncated() {
17635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: file too short to hold load command region"
17735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " given in Mach-O header\n", filename_.c_str());
17835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
17935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
18035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i,
18135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                           LoadCommandType type) {
18235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: file's header claims there are %ld"
18335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " load commands, but load command #%ld",
18435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str(), claimed, i);
18535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (type) fprintf(stderr, ", of type %d,", type);
18635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, " extends beyond the end of the load command region\n");
18735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
18835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
18935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
19035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: the contents of load command #%ld, of type %d,"
19135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " extend beyond the size given in the load command's header\n",
19235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str(), i, type);
19335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
19435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
19535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::SectionsMissing(const string &name) {
19635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: the load command for segment '%s'"
19735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " is too short to hold the section headers it claims to have\n",
19835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str(), name.c_str());
19935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
20035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
20135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::MisplacedSegmentData(const string &name) {
20235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond"
20335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " the end of the file\n", filename_.c_str(), name.c_str());
20435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
20535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
20635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::MisplacedSectionData(const string &section,
20735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                            const string &segment) {
20835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: the section '%s' in segment '%s'"
20935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " claims its contents lie outside the segment's contents\n",
21035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str(), section.c_str(), segment.c_str());
21135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
21235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
21335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::MisplacedSymbolTable() {
21435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol"
21535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          " table's contents are located beyond the end of the file\n",
21635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str());
21735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
21835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
21935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekvoid Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) {
22035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  fprintf(stderr, "%s: CPU type %d is not supported\n",
22135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          filename_.c_str(), cpu_type);
22235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
22335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
22435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::Read(const uint8_t *buffer,
22535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                  size_t size,
22635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                  cpu_type_t expected_cpu_type,
22735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                  cpu_subtype_t expected_cpu_subtype) {
22835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  assert(!buffer_.start);
22935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  buffer_.start = buffer;
23035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  buffer_.end = buffer + size;
23135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  ByteCursor cursor(&buffer_, true);
23235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  uint32_t magic;
23335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (!(cursor >> magic)) {
23435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    reporter_->HeaderTruncated();
23535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    return false;
23635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
23735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
23835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (expected_cpu_type != CPU_TYPE_ANY) {
23935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    uint32_t expected_magic;
24035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // validate that magic matches the expected cpu type
24135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    switch (expected_cpu_type) {
242316298724f170c77dd7ad67ece3df2d3e434873bqsr@chromium.org      case CPU_TYPE_ARM:
24335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      case CPU_TYPE_I386:
24435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        expected_magic = MH_CIGAM;
24535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        break;
24635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      case CPU_TYPE_POWERPC:
24735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        expected_magic = MH_MAGIC;
24835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        break;
249d1871cfe0951df6cc8dfb06e506002282b54aa67qsr@chromium.org      case CPU_TYPE_ARM_64:
25035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      case CPU_TYPE_X86_64:
25135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        expected_magic = MH_CIGAM_64;
25235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        break;
25335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      case CPU_TYPE_POWERPC64:
25435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        expected_magic = MH_MAGIC_64;
25535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        break;
25635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      default:
25735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        reporter_->UnsupportedCPUType(expected_cpu_type);
25835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        return false;
25935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
26035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
26135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (expected_magic != magic) {
26235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      reporter_->BadHeader();
26335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return false;
26435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
26535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
26635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
26735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // Since the byte cursor is in big-endian mode, a reversed magic number
26835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // always indicates a little-endian file, regardless of our own endianness.
26935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  switch (magic) {
27035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    case MH_MAGIC:    big_endian_ = true;  bits_64_ = false; break;
27135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    case MH_CIGAM:    big_endian_ = false; bits_64_ = false; break;
27235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    case MH_MAGIC_64: big_endian_ = true;  bits_64_ = true;  break;
27335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    case MH_CIGAM_64: big_endian_ = false; bits_64_ = true;  break;
27435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    default:
27535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      reporter_->BadHeader();
27635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return false;
27735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
27835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  cursor.set_big_endian(big_endian_);
27935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  uint32_t commands_size, reserved;
28035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_
28135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek         >> commands_size >> flags_;
28235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (bits_64_)
28335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    cursor >> reserved;
28435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (!cursor) {
28535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    reporter_->HeaderTruncated();
28635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    return false;
28735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
28835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
28935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (expected_cpu_type != CPU_TYPE_ANY &&
29035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      (expected_cpu_type != cpu_type_ ||
29135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek       expected_cpu_subtype != cpu_subtype_)) {
29235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_,
29335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                              expected_cpu_type, expected_cpu_subtype);
29435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    return false;
29535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
29635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
29735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  cursor
29835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      .PointTo(&load_commands_.start, commands_size)
29935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      .PointTo(&load_commands_.end, 0);
30035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  if (!cursor) {
30135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    reporter_->LoadCommandRegionTruncated();
30235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    return false;
30335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
30435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
30535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  return true;
30635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
30735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
30835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
30935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  ByteCursor list_cursor(&load_commands_, big_endian_);
31035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
31135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  for (size_t index = 0; index < load_command_count_; ++index) {
31235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // command refers to this load command alone, so that cursor will
31335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // refuse to read past the load command's end. But since we haven't
31435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // read the size yet, let command initially refer to the entire
31535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // remainder of the load command series.
31635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    ByteBuffer command(list_cursor.here(), list_cursor.Available());
31735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    ByteCursor cursor(&command, big_endian_);
31835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
31935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // Read the command type and size --- fields common to all commands.
32035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    uint32_t type, size;
32135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (!(cursor >> type)) {
32235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      reporter_->LoadCommandsOverrun(load_command_count_, index, 0);
32335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return false;
32435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
32535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (!(cursor >> size) || size > command.Size()) {
32635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      reporter_->LoadCommandsOverrun(load_command_count_, index, type);
32735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return false;
32835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
32935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
33035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // Now that we've read the length, restrict command's range to this
33135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    // load command only.
33235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    command.end = command.start + size;
33335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
33435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    switch (type) {
33535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      case LC_SEGMENT:
33635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      case LC_SEGMENT_64: {
33735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        Segment segment;
33835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        segment.bits_64 = (type == LC_SEGMENT_64);
33935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        size_t word_size = segment.bits_64 ? 8 : 4;
34035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        cursor.CString(&segment.name, 16);
34135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        size_t file_offset, file_size;
34235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        cursor
34335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek            .Read(word_size, false, &segment.vmaddr)
34435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek            .Read(word_size, false, &segment.vmsize)
34535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek            .Read(word_size, false, &file_offset)
34635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek            .Read(word_size, false, &file_size);
34735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        cursor >> segment.maxprot
34835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               >> segment.initprot
34935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               >> segment.nsects
35035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               >> segment.flags;
35135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (!cursor) {
35235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          reporter_->LoadCommandTooShort(index, type);
35335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
35435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        }
35535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (file_offset > buffer_.Size() ||
35635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek            file_size > buffer_.Size() - file_offset) {
35735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          reporter_->MisplacedSegmentData(segment.name);
35835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
35935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        }
36035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // Mach-O files in .dSYM bundles have the contents of the loaded
36135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // segments removed, and their file offsets and file sizes zeroed
36235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // out. To help us handle this special case properly, give such
36335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // segments' contents NULL starting and ending pointers.
36435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (file_offset == 0 && file_size == 0) {
36535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          segment.contents.start = segment.contents.end = NULL;
36635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        } else {
36735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          segment.contents.start = buffer_.start + file_offset;
36835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          segment.contents.end = segment.contents.start + file_size;
36935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        }
37035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // The section list occupies the remainder of this load command's space.
37135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        segment.section_list.start = cursor.here();
37235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        segment.section_list.end = command.end;
37335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
37435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (!handler->SegmentCommand(segment))
37535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
37635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        break;
37735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      }
37835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
37935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      case LC_SYMTAB: {
38035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        uint32_t symoff, nsyms, stroff, strsize;
38135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        cursor >> symoff >> nsyms >> stroff >> strsize;
38235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (!cursor) {
38335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          reporter_->LoadCommandTooShort(index, type);
38435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
38535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        }
38635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // How big are the entries in the symbol table?
38735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // sizeof(struct nlist_64) : sizeof(struct nlist),
38835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // but be paranoid about alignment vs. target architecture.
38935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        size_t symbol_size = bits_64_ ? 16 : 12;
39035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        // How big is the entire symbol array?
39135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        size_t symbols_size = nsyms * symbol_size;
39235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff ||
39335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek            stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) {
39435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          reporter_->MisplacedSymbolTable();
39535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
39635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        }
39735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        ByteBuffer entries(buffer_.start + symoff, symbols_size);
39835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        ByteBuffer names(buffer_.start + stroff, strsize);
39935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (!handler->SymtabCommand(entries, names))
40035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
40135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        break;
40235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      }
40335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
40435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      default: {
40535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        if (!handler->UnknownCommand(type, command))
40635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          return false;
40735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        break;
40835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      }
40935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
41035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
41135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    list_cursor.set_here(command.end);
41235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
41335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
41435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  return true;
41535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
41635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
41735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// A load command handler that looks for a segment of a given name.
41835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekclass Reader::SegmentFinder : public LoadCommandHandler {
41935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek public:
42035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // Create a load command handler that looks for a segment named NAME,
42135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // and sets SEGMENT to describe it if found.
42235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  SegmentFinder(const string &name, Segment *segment)
42335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      : name_(name), segment_(segment), found_() { }
42435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
42535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // Return true if the traversal found the segment, false otherwise.
42635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  bool found() const { return found_; }
42735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
42835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  bool SegmentCommand(const Segment &segment) {
42935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (segment.name == name_) {
43035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      *segment_ = segment;
43135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      found_ = true;
43235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return false;
43335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
43435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    return true;
43535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
43635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
43735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek private:
43835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // The name of the segment our creator is looking for.
43935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  const string &name_;
44035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
44135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // Where we should store the segment if found. (WEAK)
44235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  Segment *segment_;
44335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
44435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // True if we found the segment.
44535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  bool found_;
44635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek};
44735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
44835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::FindSegment(const string &name, Segment *segment) const {
44935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  SegmentFinder finder(name, segment);
45035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  WalkLoadCommands(&finder);
45135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  return finder.found();
45235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
45335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
45435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::WalkSegmentSections(const Segment &segment,
45535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                 SectionHandler *handler) const {
45635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  size_t word_size = segment.bits_64 ? 8 : 4;
45735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  ByteCursor cursor(&segment.section_list, big_endian_);
45835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
45935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  for (size_t i = 0; i < segment.nsects; i++) {
46035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    Section section;
46135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    section.bits_64 = segment.bits_64;
46235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    uint64_t size;
46335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    uint32_t offset, dummy32;
46435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    cursor
46535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        .CString(&section.section_name, 16)
46635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        .CString(&section.segment_name, 16)
46735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        .Read(word_size, false, &section.address)
46835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        .Read(word_size, false, &size)
46935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        >> offset
47035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        >> section.align
47135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        >> dummy32
47235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        >> dummy32
47335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        >> section.flags
47435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        >> dummy32
47535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        >> dummy32;
47635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (section.bits_64)
47735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      cursor >> dummy32;
47835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (!cursor) {
47935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      reporter_->SectionsMissing(segment.name);
48035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return false;
48135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
48235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if ((section.flags & SECTION_TYPE) == S_ZEROFILL) {
48335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // Zero-fill sections have a size, but no contents.
48435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      section.contents.start = section.contents.end = NULL;
48535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    } else if (segment.contents.start == NULL &&
48635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek               segment.contents.end == NULL) {
48735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // Mach-O files in .dSYM bundles have the contents of the loaded
48835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // segments removed, and their file offsets and file sizes zeroed
48935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // out.  However, the sections within those segments still have
49035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // non-zero sizes.  There's no reason to call MisplacedSectionData in
49135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // this case; the caller may just need the section's load
49235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      // address. But do set the contents' limits to NULL, for safety.
49335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      section.contents.start = section.contents.end = NULL;
49435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    } else {
49535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      if (offset < size_t(segment.contents.start - buffer_.start) ||
49635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          offset > size_t(segment.contents.end - buffer_.start) ||
49735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek          size > size_t(segment.contents.end - buffer_.start - offset)) {
49835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        reporter_->MisplacedSectionData(section.section_name,
49935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                        section.segment_name);
50035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek        return false;
50135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      }
50235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      section.contents.start = buffer_.start + offset;
50335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      section.contents.end = section.contents.start + size;
50435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    }
50535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    if (!handler->HandleSection(section))
50635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek      return false;
50735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
50835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  return true;
50935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
51035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
51135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// A SectionHandler that builds a SectionMap for the sections within a
51235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek// given segment.
51335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekclass Reader::SectionMapper: public SectionHandler {
51435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek public:
51535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // Create a SectionHandler that populates MAP with an entry for
51635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // each section it is given.
51735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  SectionMapper(SectionMap *map) : map_(map) { }
51835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  bool HandleSection(const Section &section) {
51935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    (*map_)[section.section_name] = section;
52035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek    return true;
52135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  }
52235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek private:
52335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  // The map under construction. (WEAK)
52435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  SectionMap *map_;
52535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek};
52635c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
52735c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarekbool Reader::MapSegmentSections(const Segment &segment,
52835c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek                                SectionMap *section_map) const {
52935c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  section_map->clear();
53035c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  SectionMapper mapper(section_map);
53135c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek  return WalkSegmentSections(segment, &mapper);
53235c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}
53335c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek
53435c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}  // namespace mach_o
53535c41e00ee2cf9280fe0122c75877ba70b41bb46ted.mielczarek}  // namespace google_breakpad
536