toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.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_reader_unittest.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1898 @@
     1.4 +// Copyright (c) 2010 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 +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
    1.34 +
    1.35 +// macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader
    1.36 +// and google_breakpad::Mach_O::Reader.
    1.37 +
    1.38 +#include <map>
    1.39 +#include <string>
    1.40 +#include <vector>
    1.41 +
    1.42 +#include "breakpad_googletest_includes.h"
    1.43 +#include "common/mac/macho_reader.h"
    1.44 +#include "common/test_assembler.h"
    1.45 +
    1.46 +namespace mach_o = google_breakpad::mach_o;
    1.47 +namespace test_assembler = google_breakpad::test_assembler;
    1.48 +
    1.49 +using mach_o::FatReader;
    1.50 +using mach_o::FileFlags;
    1.51 +using mach_o::FileType;
    1.52 +using mach_o::LoadCommandType;
    1.53 +using mach_o::Reader;
    1.54 +using mach_o::Section;
    1.55 +using mach_o::SectionMap;
    1.56 +using mach_o::Segment;
    1.57 +using test_assembler::Endianness;
    1.58 +using test_assembler::Label;
    1.59 +using test_assembler::kBigEndian;
    1.60 +using test_assembler::kLittleEndian;
    1.61 +using test_assembler::kUnsetEndian;
    1.62 +using google_breakpad::ByteBuffer;
    1.63 +using std::map;
    1.64 +using std::string;
    1.65 +using std::vector;
    1.66 +using testing::AllOf;
    1.67 +using testing::DoAll;
    1.68 +using testing::Field;
    1.69 +using testing::InSequence;
    1.70 +using testing::Matcher;
    1.71 +using testing::Return;
    1.72 +using testing::SaveArg;
    1.73 +using testing::Test;
    1.74 +using testing::_;
    1.75 +
    1.76 +
    1.77 +// Mock classes for the reader's various reporters and handlers.
    1.78 +
    1.79 +class MockFatReaderReporter: public FatReader::Reporter {
    1.80 + public:
    1.81 +  MockFatReaderReporter(const string &filename)
    1.82 +      : FatReader::Reporter(filename) { }
    1.83 +  MOCK_METHOD0(BadHeader, void());
    1.84 +  MOCK_METHOD0(MisplacedObjectFile, void());
    1.85 +  MOCK_METHOD0(TooShort, void());
    1.86 +};
    1.87 +
    1.88 +class MockReaderReporter: public Reader::Reporter {
    1.89 + public:
    1.90 +  MockReaderReporter(const string &filename) : Reader::Reporter(filename) { }
    1.91 +  MOCK_METHOD0(BadHeader, void());
    1.92 +  MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type,
    1.93 +                                     cpu_subtype_t cpu_subtype,
    1.94 +                                     cpu_type_t expected_cpu_type,
    1.95 +                                     cpu_subtype_t expected_cpu_subtype));
    1.96 +  MOCK_METHOD0(HeaderTruncated, void());
    1.97 +  MOCK_METHOD0(LoadCommandRegionTruncated, void());
    1.98 +  MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i,
    1.99 +                                         LoadCommandType type));
   1.100 +  MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type));
   1.101 +  MOCK_METHOD1(SectionsMissing, void(const string &name));
   1.102 +  MOCK_METHOD1(MisplacedSegmentData, void(const string &name));
   1.103 +  MOCK_METHOD2(MisplacedSectionData, void(const string &section,
   1.104 +                                          const string &segment));
   1.105 +  MOCK_METHOD0(MisplacedSymbolTable, void());
   1.106 +  MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type));
   1.107 +};
   1.108 +
   1.109 +class MockLoadCommandHandler: public Reader::LoadCommandHandler {
   1.110 + public:
   1.111 +  MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &));
   1.112 +  MOCK_METHOD1(SegmentCommand, bool(const Segment &));
   1.113 +  MOCK_METHOD2(SymtabCommand,  bool(const ByteBuffer &, const ByteBuffer &));
   1.114 +};
   1.115 +
   1.116 +class MockSectionHandler: public Reader::SectionHandler {
   1.117 + public:
   1.118 +  MOCK_METHOD1(HandleSection, bool(const Section &section));
   1.119 +};
   1.120 +
   1.121 +
   1.122 +// Tests for mach_o::FatReader.
   1.123 +
   1.124 +// Since the effect of these functions is to write to stderr, the
   1.125 +// results of these tests must be inspected by hand.
   1.126 +TEST(FatReaderReporter, BadHeader) {
   1.127 +  FatReader::Reporter reporter("filename");
   1.128 +  reporter.BadHeader();
   1.129 +}
   1.130 +
   1.131 +TEST(FatReaderReporter, MisplacedObjectFile) {
   1.132 +  FatReader::Reporter reporter("filename");
   1.133 +  reporter.MisplacedObjectFile();
   1.134 +}
   1.135 +
   1.136 +TEST(FatReaderReporter, TooShort) {
   1.137 +  FatReader::Reporter reporter("filename");
   1.138 +  reporter.TooShort();
   1.139 +}
   1.140 +
   1.141 +TEST(MachOReaderReporter, BadHeader) {
   1.142 +  Reader::Reporter reporter("filename");
   1.143 +  reporter.BadHeader();
   1.144 +}
   1.145 +
   1.146 +TEST(MachOReaderReporter, CPUTypeMismatch) {
   1.147 +  Reader::Reporter reporter("filename");
   1.148 +  reporter.CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
   1.149 +                           CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
   1.150 +}
   1.151 +
   1.152 +TEST(MachOReaderReporter, HeaderTruncated) {
   1.153 +  Reader::Reporter reporter("filename");
   1.154 +  reporter.HeaderTruncated();
   1.155 +}
   1.156 +
   1.157 +TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
   1.158 +  Reader::Reporter reporter("filename");
   1.159 +  reporter.LoadCommandRegionTruncated();
   1.160 +}
   1.161 +
   1.162 +TEST(MachOReaderReporter, LoadCommandsOverrun) {
   1.163 +  Reader::Reporter reporter("filename");
   1.164 +  reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
   1.165 +  reporter.LoadCommandsOverrun(10, 9, 0);
   1.166 +}
   1.167 +
   1.168 +TEST(MachOReaderReporter, LoadCommandTooShort) {
   1.169 +  Reader::Reporter reporter("filename");
   1.170 +  reporter.LoadCommandTooShort(11, LC_SYMTAB);
   1.171 +}
   1.172 +
   1.173 +TEST(MachOReaderReporter, SectionsMissing) {
   1.174 +  Reader::Reporter reporter("filename");
   1.175 +  reporter.SectionsMissing("segment name");
   1.176 +}
   1.177 +
   1.178 +TEST(MachOReaderReporter, MisplacedSegmentData) {
   1.179 +  Reader::Reporter reporter("filename");
   1.180 +  reporter.MisplacedSegmentData("segment name");
   1.181 +}
   1.182 +
   1.183 +TEST(MachOReaderReporter, MisplacedSectionData) {
   1.184 +  Reader::Reporter reporter("filename");
   1.185 +  reporter.MisplacedSectionData("section name", "segment name");
   1.186 +}
   1.187 +
   1.188 +TEST(MachOReaderReporter, MisplacedSymbolTable) {
   1.189 +  Reader::Reporter reporter("filename");
   1.190 +  reporter.MisplacedSymbolTable();
   1.191 +}
   1.192 +
   1.193 +TEST(MachOReaderReporter, UnsupportedCPUType) {
   1.194 +  Reader::Reporter reporter("filename");
   1.195 +  reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
   1.196 +}
   1.197 +
   1.198 +struct FatReaderFixture {
   1.199 +  FatReaderFixture()
   1.200 +      : fat(kBigEndian),
   1.201 +        reporter("reporter filename"),
   1.202 +        reader(&reporter), object_files(), object_files_size() { 
   1.203 +    EXPECT_CALL(reporter, BadHeader()).Times(0);
   1.204 +    EXPECT_CALL(reporter, TooShort()).Times(0);
   1.205 +
   1.206 +    // here, start, and Mark are file offsets in 'fat'.
   1.207 +    fat.start() = 0;
   1.208 +  }
   1.209 +  // Append a 'fat_arch' entry to 'fat', with the given field values.
   1.210 +  void AppendFatArch(cpu_type_t type, cpu_subtype_t subtype,
   1.211 +                     Label offset, Label size, uint32_t align) {
   1.212 +    fat
   1.213 +        .B32(type)
   1.214 +        .B32(subtype)
   1.215 +        .B32(offset)
   1.216 +        .B32(size)
   1.217 +        .B32(align);
   1.218 +  }
   1.219 +  // Append |n| dummy 'fat_arch' entries to 'fat'. The cpu type and
   1.220 +  // subtype have unrealistic values.
   1.221 +  void AppendDummyArchEntries(int n) {
   1.222 +    for (int i = 0; i < n; i++)
   1.223 +      AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1);
   1.224 +  }
   1.225 +  void ReadFat(bool expect_parse_success = true) {
   1.226 +    ASSERT_TRUE(fat.GetContents(&contents));
   1.227 +    fat_bytes = reinterpret_cast<const uint8_t *>(contents.data());
   1.228 +    if (expect_parse_success) {
   1.229 +      EXPECT_TRUE(reader.Read(fat_bytes, contents.size()));
   1.230 +      object_files = reader.object_files(&object_files_size);
   1.231 +    }
   1.232 +    else
   1.233 +      EXPECT_FALSE(reader.Read(fat_bytes, contents.size()));
   1.234 +  }
   1.235 +  test_assembler::Section fat;
   1.236 +  MockFatReaderReporter reporter;
   1.237 +  FatReader reader;
   1.238 +  string contents;
   1.239 +  const uint8_t *fat_bytes;
   1.240 +  const struct fat_arch *object_files;
   1.241 +  size_t object_files_size;
   1.242 +};
   1.243 +
   1.244 +class FatReaderTest: public FatReaderFixture, public Test { };
   1.245 +
   1.246 +TEST_F(FatReaderTest, BadMagic) {
   1.247 +  EXPECT_CALL(reporter, BadHeader()).Times(1);
   1.248 +  fat
   1.249 +      .B32(0xcafed00d)           // magic number (incorrect)
   1.250 +      .B32(10);                  // number of architectures
   1.251 +  AppendDummyArchEntries(10);
   1.252 +  ReadFat(false);
   1.253 +}
   1.254 +
   1.255 +TEST_F(FatReaderTest, HeaderTooShort) {
   1.256 +  EXPECT_CALL(reporter, TooShort()).Times(1);
   1.257 +  fat
   1.258 +      .B32(0xcafebabe);             // magic number
   1.259 +  ReadFat(false);
   1.260 +}
   1.261 +
   1.262 +TEST_F(FatReaderTest, ObjectListTooShort) {
   1.263 +  EXPECT_CALL(reporter, TooShort()).Times(1);
   1.264 +  fat
   1.265 +      .B32(0xcafebabe)              // magic number
   1.266 +      .B32(10);                     // number of architectures
   1.267 +  AppendDummyArchEntries(9);        // nine dummy architecture entries...
   1.268 +  fat                               // and a tenth, missing a byte at the end
   1.269 +      .B32(0x3d46c8fc)              // cpu type
   1.270 +      .B32(0x8a7bfb01)              // cpu subtype
   1.271 +      .B32(0)                       // offset
   1.272 +      .B32(0)                       // size
   1.273 +      .Append(3, '*');              // one byte short of a four-byte alignment
   1.274 +  ReadFat(false);
   1.275 +}
   1.276 +
   1.277 +TEST_F(FatReaderTest, DataTooShort) {
   1.278 +  EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1);
   1.279 +  Label arch_data;
   1.280 +  fat
   1.281 +      .B32(0xcafebabe)              // magic number
   1.282 +      .B32(1);                      // number of architectures
   1.283 +  AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0);
   1.284 +  fat
   1.285 +      .Mark(&arch_data)             // file data begins here
   1.286 +      .Append(30, '*');             // only 30 bytes, not 40 as header claims
   1.287 +  ReadFat(false);
   1.288 +}
   1.289 +
   1.290 +TEST_F(FatReaderTest, NoObjectFiles) {
   1.291 +  fat
   1.292 +      .B32(0xcafebabe)              // magic number
   1.293 +      .B32(0);                      // number of architectures
   1.294 +  ReadFat();
   1.295 +  EXPECT_EQ(0U, object_files_size);
   1.296 +}
   1.297 +
   1.298 +TEST_F(FatReaderTest, OneObjectFile) {
   1.299 +  Label obj1_offset;
   1.300 +  fat
   1.301 +      .B32(0xcafebabe)              // magic number
   1.302 +      .B32(1);                      // number of architectures
   1.303 +  // First object file list entry
   1.304 +  AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2);
   1.305 +  // First object file data
   1.306 +  fat
   1.307 +      .Mark(&obj1_offset)           
   1.308 +      .Append(0x42, '*');           // dummy contents
   1.309 +  ReadFat();
   1.310 +  ASSERT_EQ(1U, object_files_size);
   1.311 +  EXPECT_EQ(0x5e3a6e91, object_files[0].cputype);
   1.312 +  EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype);
   1.313 +  EXPECT_EQ(obj1_offset.Value(), object_files[0].offset);
   1.314 +  EXPECT_EQ(0x42U, object_files[0].size);
   1.315 +  EXPECT_EQ(0x355b15b2U, object_files[0].align);
   1.316 +}
   1.317 +
   1.318 +TEST_F(FatReaderTest, ThreeObjectFiles) {
   1.319 +  Label obj1, obj2, obj3;
   1.320 +  fat
   1.321 +      .B32(0xcafebabe)              // magic number
   1.322 +      .B32(3);                      // number of architectures
   1.323 +  // Three object file list entries.
   1.324 +  AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8);
   1.325 +  AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd);
   1.326 +  AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7);
   1.327 +  fat
   1.328 +      // First object file data
   1.329 +      .Mark(&obj1)           
   1.330 +      .Append(0xfb4, '*')           // dummy contents
   1.331 +      // Second object file data
   1.332 +      .Mark(&obj2)           
   1.333 +      .Append(0xc31, '%')           // dummy contents
   1.334 +      // Third object file data
   1.335 +      .Mark(&obj3)           
   1.336 +      .Append(0x4b3, '^');          // dummy contents
   1.337 +  
   1.338 +  ReadFat();
   1.339 +
   1.340 +  ASSERT_EQ(3U, object_files_size);
   1.341 +
   1.342 +  // First object file.
   1.343 +  EXPECT_EQ(0x0cb92c30, object_files[0].cputype);
   1.344 +  EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype);
   1.345 +  EXPECT_EQ(obj1.Value(), object_files[0].offset);
   1.346 +  EXPECT_EQ(0xfb4U, object_files[0].size);
   1.347 +  EXPECT_EQ(0x2615dbe8U, object_files[0].align);
   1.348 +
   1.349 +  // Second object file.
   1.350 +  EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype);
   1.351 +  EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype);
   1.352 +  EXPECT_EQ(obj2.Value(), object_files[1].offset);
   1.353 +  EXPECT_EQ(0xc31U, object_files[1].size);
   1.354 +  EXPECT_EQ(0x83af6ffdU, object_files[1].align);
   1.355 +
   1.356 +  // Third object file.
   1.357 +  EXPECT_EQ(0x3717276d, object_files[2].cputype);
   1.358 +  EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype);
   1.359 +  EXPECT_EQ(obj3.Value(), object_files[2].offset);
   1.360 +  EXPECT_EQ(0x4b3U, object_files[2].size);
   1.361 +  EXPECT_EQ(0x035267d7U, object_files[2].align);
   1.362 +}
   1.363 +
   1.364 +TEST_F(FatReaderTest, BigEndianMachO32) {
   1.365 +  fat.set_endianness(kBigEndian);
   1.366 +  fat
   1.367 +      .D32(0xfeedface)                  // Mach-O file magic number
   1.368 +      .D32(0x1a9d0518)                  // cpu type
   1.369 +      .D32(0x1b779357)                  // cpu subtype
   1.370 +      .D32(0x009df67e)                  // file type
   1.371 +      .D32(0)                           // no load commands
   1.372 +      .D32(0)                           // the load commands occupy no bytes
   1.373 +      .D32(0x21987a99);                 // flags
   1.374 +
   1.375 +  ReadFat();
   1.376 +
   1.377 +  // FatReader should treat a Mach-O file as if it were a fat binary file
   1.378 +  // containing one object file --- the whole thing.
   1.379 +  ASSERT_EQ(1U, object_files_size);
   1.380 +  EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
   1.381 +  EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
   1.382 +  EXPECT_EQ(0U, object_files[0].offset);
   1.383 +  EXPECT_EQ(contents.size(), object_files[0].size);
   1.384 +}
   1.385 +
   1.386 +TEST_F(FatReaderTest, BigEndianMachO64) {
   1.387 +  fat.set_endianness(kBigEndian);
   1.388 +  fat
   1.389 +      .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
   1.390 +      .D32(0x5aff8487)                  // cpu type
   1.391 +      .D32(0x4c6a57f7)                  // cpu subtype
   1.392 +      .D32(0x4392d2c8)                  // file type
   1.393 +      .D32(0)                           // no load commands
   1.394 +      .D32(0)                           // the load commands occupy no bytes
   1.395 +      .D32(0x1b033eea);                 // flags
   1.396 +
   1.397 +  ReadFat();
   1.398 +
   1.399 +  // FatReader should treat a Mach-O file as if it were a fat binary file
   1.400 +  // containing one object file --- the whole thing.
   1.401 +  ASSERT_EQ(1U, object_files_size);
   1.402 +  EXPECT_EQ(0x5aff8487, object_files[0].cputype);
   1.403 +  EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
   1.404 +  EXPECT_EQ(0U, object_files[0].offset);
   1.405 +  EXPECT_EQ(contents.size(), object_files[0].size);
   1.406 +}
   1.407 +
   1.408 +TEST_F(FatReaderTest, LittleEndianMachO32) {
   1.409 +  fat.set_endianness(kLittleEndian);
   1.410 +  fat
   1.411 +      .D32(0xfeedface)                  // Mach-O file magic number
   1.412 +      .D32(0x1a9d0518)                  // cpu type
   1.413 +      .D32(0x1b779357)                  // cpu subtype
   1.414 +      .D32(0x009df67e)                  // file type
   1.415 +      .D32(0)                           // no load commands
   1.416 +      .D32(0)                           // the load commands occupy no bytes
   1.417 +      .D32(0x21987a99);                 // flags
   1.418 +
   1.419 +  ReadFat();
   1.420 +
   1.421 +  // FatReader should treat a Mach-O file as if it were a fat binary file
   1.422 +  // containing one object file --- the whole thing.
   1.423 +  ASSERT_EQ(1U, object_files_size);
   1.424 +  EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
   1.425 +  EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
   1.426 +  EXPECT_EQ(0U, object_files[0].offset);
   1.427 +  EXPECT_EQ(contents.size(), object_files[0].size);
   1.428 +}
   1.429 +
   1.430 +TEST_F(FatReaderTest, LittleEndianMachO64) {
   1.431 +  fat.set_endianness(kLittleEndian);
   1.432 +  fat
   1.433 +      .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
   1.434 +      .D32(0x5aff8487)                  // cpu type
   1.435 +      .D32(0x4c6a57f7)                  // cpu subtype
   1.436 +      .D32(0x4392d2c8)                  // file type
   1.437 +      .D32(0)                           // no load commands
   1.438 +      .D32(0)                           // the load commands occupy no bytes
   1.439 +      .D32(0x1b033eea);                 // flags
   1.440 +
   1.441 +  ReadFat();
   1.442 +
   1.443 +  // FatReader should treat a Mach-O file as if it were a fat binary file
   1.444 +  // containing one object file --- the whole thing.
   1.445 +  ASSERT_EQ(1U, object_files_size);
   1.446 +  EXPECT_EQ(0x5aff8487, object_files[0].cputype);
   1.447 +  EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
   1.448 +  EXPECT_EQ(0U, object_files[0].offset);
   1.449 +  EXPECT_EQ(contents.size(), object_files[0].size);
   1.450 +}
   1.451 +
   1.452 +TEST_F(FatReaderTest, IncompleteMach) {
   1.453 +  fat.set_endianness(kLittleEndian);
   1.454 +  fat
   1.455 +      .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
   1.456 +      .D32(0x5aff8487);                 // cpu type
   1.457 +      // Truncated!
   1.458 +
   1.459 +  EXPECT_CALL(reporter, TooShort()).WillOnce(Return());
   1.460 +
   1.461 +  ReadFat(false);
   1.462 +}
   1.463 +
   1.464 +
   1.465 +// General mach_o::Reader tests.
   1.466 +
   1.467 +// Dynamically scoped configuration data.
   1.468 +class WithConfiguration {
   1.469 + public:
   1.470 +  // Establish the given parameters as the default for SizedSections
   1.471 +  // created within the dynamic scope of this instance.
   1.472 +  WithConfiguration(Endianness endianness, size_t word_size)
   1.473 +      : endianness_(endianness), word_size_(word_size), saved_(current_) {
   1.474 +    current_ = this;
   1.475 +  }
   1.476 +  ~WithConfiguration() { current_ = saved_; }
   1.477 +  static Endianness endianness() { 
   1.478 +    assert(current_);
   1.479 +    return current_->endianness_;
   1.480 +  }
   1.481 +  static size_t word_size() { 
   1.482 +    assert(current_);
   1.483 +    return current_->word_size_;
   1.484 +  }
   1.485 +
   1.486 + private:
   1.487 +  // The innermost WithConfiguration in whose dynamic scope we are
   1.488 +  // currently executing.
   1.489 +  static WithConfiguration *current_;
   1.490 +
   1.491 +  // The innermost WithConfiguration whose dynamic scope encloses this
   1.492 +  // WithConfiguration.
   1.493 +  Endianness endianness_;
   1.494 +  size_t word_size_;
   1.495 +  WithConfiguration *saved_;
   1.496 +};
   1.497 +
   1.498 +WithConfiguration *WithConfiguration::current_ = NULL;
   1.499 +
   1.500 +// A test_assembler::Section with a size that we can cite. The start(),
   1.501 +// Here() and Mark() member functions of a SizedSection always represent
   1.502 +// offsets within the overall file.
   1.503 +class SizedSection: public test_assembler::Section {
   1.504 + public:
   1.505 +  // Construct a section of the given endianness and word size.
   1.506 +  explicit SizedSection(Endianness endianness, size_t word_size)
   1.507 +      : test_assembler::Section(endianness), word_size_(word_size) {
   1.508 +    assert(word_size_ == 32 || word_size_ == 64);
   1.509 +  }
   1.510 +  SizedSection()
   1.511 +      : test_assembler::Section(WithConfiguration::endianness()),
   1.512 +        word_size_(WithConfiguration::word_size()) {
   1.513 +    assert(word_size_ == 32 || word_size_ == 64);
   1.514 +  }
   1.515 +
   1.516 +  // Access/set this section's word size.
   1.517 +  size_t word_size() const { return word_size_; }
   1.518 +  void set_word_size(size_t word_size) { 
   1.519 +    assert(word_size_ == 32 || word_size_ == 64);
   1.520 +    word_size_ = word_size;
   1.521 +  }
   1.522 +
   1.523 +  // Return a label representing the size this section will have when it
   1.524 +  // is Placed in some containing section.
   1.525 +  Label final_size() const { return final_size_; }
   1.526 +
   1.527 +  // Append SECTION to the end of this section, and call its Finish member.
   1.528 +  // Return a reference to this section.
   1.529 +  SizedSection &Place(SizedSection *section) {
   1.530 +    assert(section->endianness() == endianness());
   1.531 +    section->Finish();
   1.532 +    section->start() = Here();
   1.533 +    test_assembler::Section::Append(*section);
   1.534 +    return *this;
   1.535 +  }
   1.536 +
   1.537 + protected:
   1.538 +  // Mark this section's contents as complete. For plain SizedSections, we
   1.539 +  // set SECTION's start to its position in this section, and its final_size
   1.540 +  // label to its current size. Derived classes can extend this as needed
   1.541 +  // for their additional semantics.
   1.542 +  virtual void Finish() {
   1.543 +    final_size_ = Size();
   1.544 +  }
   1.545 +
   1.546 +  // The word size for this data: either 32 or 64.
   1.547 +  size_t word_size_;
   1.548 +
   1.549 + private:
   1.550 +  // This section's final size, set when we are placed in some other
   1.551 +  // SizedSection.
   1.552 +  Label final_size_;
   1.553 +};
   1.554 +
   1.555 +// A SizedSection that is loaded into memory at a particular address.
   1.556 +class LoadedSection: public SizedSection {
   1.557 + public:
   1.558 +  explicit LoadedSection(Label address = Label()) : address_(address) { }
   1.559 +
   1.560 +  // Return a label representing this section's address.
   1.561 +  Label address() const { return address_; }
   1.562 +
   1.563 +  // Placing a loaded section within a loaded section sets the relationship
   1.564 +  // between their addresses.
   1.565 +  LoadedSection &Place(LoadedSection *section) {
   1.566 +    section->address() = address() + Size();
   1.567 +    SizedSection::Place(section);
   1.568 +    return *this;
   1.569 +  }
   1.570 +
   1.571 + protected:
   1.572 +  // The address at which this section's contents will be loaded.
   1.573 +  Label address_;
   1.574 +};
   1.575 +  
   1.576 +// A SizedSection representing a segment load command.
   1.577 +class SegmentLoadCommand: public SizedSection {
   1.578 + public:
   1.579 +  SegmentLoadCommand() : section_count_(0) { }
   1.580 +
   1.581 +  // Append a segment load command header with the given characteristics.
   1.582 +  // The load command will refer to CONTENTS, which must be Placed in the
   1.583 +  // file separately, at the desired position. Return a reference to this
   1.584 +  // section.
   1.585 +  SegmentLoadCommand &Header(const string &name, const LoadedSection &contents,
   1.586 +                             uint32_t maxprot, uint32_t initprot,
   1.587 +                             uint32_t flags) {
   1.588 +    assert(contents.word_size() == word_size());
   1.589 +    D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64);
   1.590 +    D32(final_size());
   1.591 +    AppendCString(name, 16);
   1.592 +    Append(endianness(), word_size() / 8, contents.address());
   1.593 +    Append(endianness(), word_size() / 8, vmsize_);
   1.594 +    Append(endianness(), word_size() / 8, contents.start());
   1.595 +    Append(endianness(), word_size() / 8, contents.final_size());
   1.596 +    D32(maxprot);
   1.597 +    D32(initprot);
   1.598 +    D32(final_section_count_);
   1.599 +    D32(flags);
   1.600 +
   1.601 +    content_final_size_ = contents.final_size();
   1.602 +
   1.603 +    return *this;
   1.604 +  }
   1.605 +
   1.606 +  // Return a label representing the size of this segment when loaded into
   1.607 +  // memory. If this label is still undefined by the time we place this
   1.608 +  // segment, it defaults to the final size of the segment's in-file
   1.609 +  // contents. Return a reference to this load command.
   1.610 +  Label &vmsize() { return vmsize_; }
   1.611 +
   1.612 +  // Add a section entry with the given characteristics to this segment
   1.613 +  // load command. Return a reference to this. The section entry will refer
   1.614 +  // to CONTENTS, which must be Placed in the segment's contents
   1.615 +  // separately, at the desired position.
   1.616 +  SegmentLoadCommand &AppendSectionEntry(const string &section_name,
   1.617 +                                         const string &segment_name,
   1.618 +                                         uint32_t alignment, uint32_t flags,
   1.619 +                                         const LoadedSection &contents) {
   1.620 +    AppendCString(section_name, 16);
   1.621 +    AppendCString(segment_name, 16);
   1.622 +    Append(endianness(), word_size() / 8, contents.address());
   1.623 +    Append(endianness(), word_size() / 8, contents.final_size());
   1.624 +    D32(contents.start());
   1.625 +    D32(alignment);
   1.626 +    D32(0);                  // relocations start
   1.627 +    D32(0);                  // relocations size
   1.628 +    D32(flags);
   1.629 +    D32(0x93656b95);         // reserved1
   1.630 +    D32(0xc35a2473);         // reserved2
   1.631 +    if (word_size() == 64)
   1.632 +      D32(0x70284b95);       // reserved3
   1.633 +
   1.634 +    section_count_++;
   1.635 +
   1.636 +    return *this;
   1.637 +  }
   1.638 +
   1.639 + protected:
   1.640 +  void Finish() {
   1.641 +    final_section_count_ = section_count_;
   1.642 +    if (!vmsize_.IsKnownConstant())
   1.643 +      vmsize_ = content_final_size_;
   1.644 +    SizedSection::Finish();
   1.645 +  }
   1.646 +
   1.647 + private:
   1.648 +  // The number of sections that have been added to this segment so far.
   1.649 +  size_t section_count_;
   1.650 +
   1.651 +  // A label representing the final number of sections this segment will hold.
   1.652 +  Label final_section_count_;
   1.653 +
   1.654 +  // The size of the contents for this segment present in the file.
   1.655 +  Label content_final_size_;
   1.656 +
   1.657 +  // A label representing the size of this segment when loaded; this can be
   1.658 +  // larger than the size of its file contents, the difference being
   1.659 +  // zero-filled. If not set explicitly by calling set_vmsize, this is set
   1.660 +  // equal to the size of the contents.
   1.661 +  Label vmsize_;
   1.662 +};
   1.663 +
   1.664 +// A SizedSection holding a list of Mach-O load commands.
   1.665 +class LoadCommands: public SizedSection {
   1.666 + public:
   1.667 +  LoadCommands() : command_count_(0) { }
   1.668 +
   1.669 +  // Return a label representing the final load command count.
   1.670 +  Label final_command_count() const { return final_command_count_; }
   1.671 +
   1.672 +  // Increment the command count; return a reference to this section.
   1.673 +  LoadCommands &CountCommand() {
   1.674 +    command_count_++;
   1.675 +    return *this;
   1.676 +  }
   1.677 +
   1.678 +  // Place COMMAND, containing a load command, at the end of this section.
   1.679 +  // Return a reference to this section.
   1.680 +  LoadCommands &Place(SizedSection *section) {
   1.681 +    SizedSection::Place(section);
   1.682 +    CountCommand();
   1.683 +    return *this;
   1.684 +  }
   1.685 +
   1.686 + protected:
   1.687 +  // Mark this load command list as complete.
   1.688 +  void Finish() {
   1.689 +    SizedSection::Finish();
   1.690 +    final_command_count_ = command_count_;
   1.691 +  }
   1.692 +
   1.693 + private:
   1.694 +  // The number of load commands we have added to this file so far.
   1.695 +  size_t command_count_;
   1.696 +
   1.697 +  // A label representing the final command count.
   1.698 +  Label final_command_count_;
   1.699 +};
   1.700 +
   1.701 +// A SizedSection holding the contents of a Mach-O file. Within a
   1.702 +// MachOFile, the start, Here, and Mark members refer to file offsets.
   1.703 +class MachOFile: public SizedSection {
   1.704 + public:
   1.705 +  MachOFile() { 
   1.706 +    start() = 0;
   1.707 +  }
   1.708 +
   1.709 +  // Create a Mach-O file header using the given characteristics and load
   1.710 +  // command list. This Places COMMANDS immediately after the header.
   1.711 +  // Return a reference to this section.
   1.712 +  MachOFile &Header(LoadCommands *commands,
   1.713 +                    cpu_type_t cpu_type = CPU_TYPE_X86,
   1.714 +                    cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL,
   1.715 +                    FileType file_type = MH_EXECUTE,
   1.716 +                    uint32_t file_flags = (MH_TWOLEVEL |
   1.717 +                                           MH_DYLDLINK |
   1.718 +                                           MH_NOUNDEFS)) {
   1.719 +    D32(word_size() == 32 ? 0xfeedface : 0xfeedfacf);  // magic number
   1.720 +    D32(cpu_type);                              // cpu type
   1.721 +    D32(cpu_subtype);                           // cpu subtype
   1.722 +    D32(file_type);                             // file type
   1.723 +    D32(commands->final_command_count());       // number of load commands
   1.724 +    D32(commands->final_size());                // their size in bytes
   1.725 +    D32(file_flags);                            // flags
   1.726 +    if (word_size() == 64)
   1.727 +      D32(0x55638b90);                          // reserved
   1.728 +    Place(commands);
   1.729 +    return *this;
   1.730 +  }
   1.731 +};
   1.732 +
   1.733 +
   1.734 +struct ReaderFixture {
   1.735 +  ReaderFixture()
   1.736 +      : reporter("reporter filename"),
   1.737 +        reader(&reporter) { 
   1.738 +    EXPECT_CALL(reporter, BadHeader()).Times(0);
   1.739 +    EXPECT_CALL(reporter, CPUTypeMismatch(_, _, _, _)).Times(0);
   1.740 +    EXPECT_CALL(reporter, HeaderTruncated()).Times(0);
   1.741 +    EXPECT_CALL(reporter, LoadCommandRegionTruncated()).Times(0);
   1.742 +    EXPECT_CALL(reporter, LoadCommandsOverrun(_, _, _)).Times(0);
   1.743 +    EXPECT_CALL(reporter, LoadCommandTooShort(_, _)).Times(0);
   1.744 +    EXPECT_CALL(reporter, SectionsMissing(_)).Times(0);
   1.745 +    EXPECT_CALL(reporter, MisplacedSegmentData(_)).Times(0);
   1.746 +    EXPECT_CALL(reporter, MisplacedSectionData(_, _)).Times(0);
   1.747 +    EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(0);
   1.748 +    EXPECT_CALL(reporter, UnsupportedCPUType(_)).Times(0);
   1.749 +
   1.750 +    EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0);
   1.751 +    EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
   1.752 +  }
   1.753 +
   1.754 +  void ReadFile(MachOFile *file,
   1.755 +                bool expect_parse_success,
   1.756 +                cpu_type_t expected_cpu_type,
   1.757 +                cpu_subtype_t expected_cpu_subtype) {
   1.758 +    ASSERT_TRUE(file->GetContents(&file_contents));
   1.759 +    file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data());
   1.760 +    if (expect_parse_success) {
   1.761 +      EXPECT_TRUE(reader.Read(file_bytes,
   1.762 +                              file_contents.size(),
   1.763 +                              expected_cpu_type,
   1.764 +                              expected_cpu_subtype));
   1.765 +    } else {
   1.766 +      EXPECT_FALSE(reader.Read(file_bytes,
   1.767 +                               file_contents.size(),
   1.768 +                               expected_cpu_type,
   1.769 +                               expected_cpu_subtype));
   1.770 +    }
   1.771 +  }
   1.772 +
   1.773 +  string file_contents;
   1.774 +  const uint8_t *file_bytes;
   1.775 +  MockReaderReporter reporter;
   1.776 +  Reader reader;
   1.777 +  MockLoadCommandHandler load_command_handler;
   1.778 +  MockSectionHandler section_handler;
   1.779 +};
   1.780 +
   1.781 +class ReaderTest: public ReaderFixture, public Test { };
   1.782 +
   1.783 +TEST_F(ReaderTest, BadMagic) {
   1.784 +  WithConfiguration config(kLittleEndian, 32);
   1.785 +  const cpu_type_t kCPUType = 0x46b760df;
   1.786 +  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
   1.787 +  MachOFile file;
   1.788 +  file
   1.789 +      .D32(0x67bdebe1)                  // Not a proper magic number.
   1.790 +      .D32(kCPUType)                    // cpu type
   1.791 +      .D32(kCPUSubType)                 // cpu subtype
   1.792 +      .D32(0x149fc717)                  // file type
   1.793 +      .D32(0)                           // no load commands
   1.794 +      .D32(0)                           // they occupy no bytes
   1.795 +      .D32(0x80e71d64)                  // flags
   1.796 +      .D32(0);                          // reserved
   1.797 +  EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
   1.798 +  ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
   1.799 +}
   1.800 +
   1.801 +TEST_F(ReaderTest, MismatchedMagic) {
   1.802 +  WithConfiguration config(kLittleEndian, 32);
   1.803 +  const cpu_type_t kCPUType = CPU_TYPE_I386;
   1.804 +  const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
   1.805 +  MachOFile file;
   1.806 +  file
   1.807 +      .D32(MH_CIGAM)                    // Right magic, but winds up wrong
   1.808 +                                        // due to bitswapping
   1.809 +      .D32(kCPUType)                    // cpu type
   1.810 +      .D32(kCPUSubType)                 // cpu subtype
   1.811 +      .D32(0x149fc717)                  // file type
   1.812 +      .D32(0)                           // no load commands
   1.813 +      .D32(0)                           // they occupy no bytes
   1.814 +      .D32(0x80e71d64)                  // flags
   1.815 +      .D32(0);                          // reserved
   1.816 +  EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
   1.817 +  ReadFile(&file, false, kCPUType, kCPUSubType);
   1.818 +}
   1.819 +
   1.820 +TEST_F(ReaderTest, ShortMagic) {
   1.821 +  WithConfiguration config(kBigEndian, 32);
   1.822 +  MachOFile file;
   1.823 +  file
   1.824 +      .D16(0xfeed);                     // magic number
   1.825 +                                        // truncated!
   1.826 +  EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
   1.827 +  ReadFile(&file, false, CPU_TYPE_ANY, 0);
   1.828 +}
   1.829 +
   1.830 +TEST_F(ReaderTest, ShortHeader) {
   1.831 +  WithConfiguration config(kBigEndian, 32);
   1.832 +  const cpu_type_t kCPUType = CPU_TYPE_ANY;
   1.833 +  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
   1.834 +  MachOFile file;
   1.835 +  file
   1.836 +      .D32(0xfeedface)                  // magic number
   1.837 +      .D32(kCPUType)                    // cpu type
   1.838 +      .D32(kCPUSubType)                 // cpu subtype
   1.839 +      .D32(0x149fc717)                  // file type
   1.840 +      .D32(0)                           // no load commands
   1.841 +      .D32(0);                          // they occupy no bytes
   1.842 +  EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
   1.843 +  ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
   1.844 +}
   1.845 +
   1.846 +TEST_F(ReaderTest, MismatchedCPU) {
   1.847 +  WithConfiguration config(kBigEndian, 32);
   1.848 +  const cpu_type_t kCPUType = CPU_TYPE_I386;
   1.849 +  const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
   1.850 +  MachOFile file;
   1.851 +  file
   1.852 +      .D32(MH_MAGIC)                    // Right magic for PPC (once bitswapped)
   1.853 +      .D32(kCPUType)                    // cpu type
   1.854 +      .D32(kCPUSubType)                 // cpu subtype
   1.855 +      .D32(0x149fc717)                  // file type
   1.856 +      .D32(0)                           // no load commands
   1.857 +      .D32(0)                           // they occupy no bytes
   1.858 +      .D32(0x80e71d64)                  // flags
   1.859 +      .D32(0);                          // reserved
   1.860 +  EXPECT_CALL(reporter,
   1.861 +              CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
   1.862 +                              CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL))
   1.863 +    .WillOnce(Return());
   1.864 +  ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
   1.865 +}
   1.866 +
   1.867 +TEST_F(ReaderTest, LittleEndian32Bit) {
   1.868 +  WithConfiguration config(kLittleEndian, 32);
   1.869 +  const cpu_type_t kCPUType = 0x46b760df;
   1.870 +  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
   1.871 +  MachOFile file;
   1.872 +  file
   1.873 +      .D32(0xfeedface)                  // magic number
   1.874 +      .D32(kCPUType)                    // cpu type
   1.875 +      .D32(kCPUSubType)                 // cpu subtype
   1.876 +      .D32(0x149fc717)                  // file type
   1.877 +      .D32(0)                           // no load commands
   1.878 +      .D32(0)                           // they occupy no bytes
   1.879 +      .D32(0x80e71d64)                  // flags
   1.880 +      .D32(0);                          // reserved
   1.881 +           ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
   1.882 +  EXPECT_FALSE(reader.bits_64());
   1.883 +  EXPECT_FALSE(reader.big_endian());
   1.884 +  EXPECT_EQ(kCPUType,               reader.cpu_type());
   1.885 +  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
   1.886 +  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
   1.887 +  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
   1.888 +}
   1.889 +
   1.890 +TEST_F(ReaderTest, LittleEndian64Bit) {
   1.891 +  WithConfiguration config(kLittleEndian, 64);
   1.892 +  const cpu_type_t kCPUType = 0x46b760df;
   1.893 +  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
   1.894 +  MachOFile file;
   1.895 +  file
   1.896 +      .D32(0xfeedfacf)                  // magic number
   1.897 +      .D32(kCPUType)                    // cpu type
   1.898 +      .D32(kCPUSubType)                 // cpu subtype
   1.899 +      .D32(0x149fc717)                  // file type
   1.900 +      .D32(0)                           // no load commands
   1.901 +      .D32(0)                           // they occupy no bytes
   1.902 +      .D32(0x80e71d64)                  // flags
   1.903 +      .D32(0);                          // reserved
   1.904 +  ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
   1.905 +  EXPECT_TRUE(reader.bits_64());
   1.906 +  EXPECT_FALSE(reader.big_endian());
   1.907 +  EXPECT_EQ(kCPUType,               reader.cpu_type());
   1.908 +  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
   1.909 +  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
   1.910 +  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
   1.911 +}
   1.912 +
   1.913 +TEST_F(ReaderTest, BigEndian32Bit) {
   1.914 +  WithConfiguration config(kBigEndian, 32);
   1.915 +  const cpu_type_t kCPUType = 0x46b760df;
   1.916 +  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
   1.917 +  MachOFile file;
   1.918 +  file
   1.919 +      .D32(0xfeedface)                  // magic number
   1.920 +      .D32(kCPUType)                    // cpu type
   1.921 +      .D32(kCPUSubType)                 // cpu subtype
   1.922 +      .D32(0x149fc717)                  // file type
   1.923 +      .D32(0)                           // no load commands
   1.924 +      .D32(0)                           // they occupy no bytes
   1.925 +      .D32(0x80e71d64)                  // flags
   1.926 +      .D32(0);                          // reserved
   1.927 +  ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
   1.928 +  EXPECT_FALSE(reader.bits_64());
   1.929 +  EXPECT_TRUE(reader.big_endian());
   1.930 +  EXPECT_EQ(kCPUType,               reader.cpu_type());
   1.931 +  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
   1.932 +  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
   1.933 +  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
   1.934 +}
   1.935 +
   1.936 +TEST_F(ReaderTest, BigEndian64Bit) {
   1.937 +  WithConfiguration config(kBigEndian, 64);
   1.938 +  const cpu_type_t kCPUType = 0x46b760df;
   1.939 +  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
   1.940 +  MachOFile file;
   1.941 +  file
   1.942 +      .D32(0xfeedfacf)                  // magic number
   1.943 +      .D32(kCPUType)                    // cpu type
   1.944 +      .D32(kCPUSubType)                 // cpu subtype
   1.945 +      .D32(0x149fc717)                  // file type
   1.946 +      .D32(0)                           // no load commands
   1.947 +      .D32(0)                           // they occupy no bytes
   1.948 +      .D32(0x80e71d64)                  // flags
   1.949 +      .D32(0);                          // reserved
   1.950 +  ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
   1.951 +  EXPECT_TRUE(reader.bits_64());
   1.952 +  EXPECT_TRUE(reader.big_endian());
   1.953 +  EXPECT_EQ(kCPUType,               reader.cpu_type());
   1.954 +  EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
   1.955 +  EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
   1.956 +  EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
   1.957 +}
   1.958 +
   1.959 +
   1.960 +// Load command tests.
   1.961 +
   1.962 +class LoadCommand: public ReaderFixture, public Test { };
   1.963 +
   1.964 +TEST_F(LoadCommand, RegionTruncated) {
   1.965 +  WithConfiguration config(kBigEndian, 64);
   1.966 +  const cpu_type_t kCPUType = 0x46b760df;
   1.967 +  const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
   1.968 +  MachOFile file;
   1.969 +  file
   1.970 +      .D32(0xfeedfacf)                  // magic number
   1.971 +      .D32(kCPUType)                    // cpu type
   1.972 +      .D32(kCPUSubType)                 // cpu subtype
   1.973 +      .D32(0x149fc717)                  // file type
   1.974 +      .D32(1)                           // one load command
   1.975 +      .D32(40)                          // occupying 40 bytes
   1.976 +      .D32(0x80e71d64)                  // flags
   1.977 +      .D32(0)                           // reserved
   1.978 +      .Append(20, 0);                   // load command region, not as long as
   1.979 +                                        // Mach-O header promised
   1.980 +
   1.981 +  EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return());
   1.982 +
   1.983 +  ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
   1.984 +}
   1.985 +
   1.986 +TEST_F(LoadCommand, None) {
   1.987 +  WithConfiguration config(kLittleEndian, 32);
   1.988 +  LoadCommands load_commands;
   1.989 +  MachOFile file;
   1.990 +  file.Header(&load_commands);
   1.991 +
   1.992 +  ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL);
   1.993 +
   1.994 +  EXPECT_FALSE(reader.bits_64());
   1.995 +  EXPECT_FALSE(reader.big_endian());
   1.996 +  EXPECT_EQ(CPU_TYPE_X86,         reader.cpu_type());
   1.997 +  EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
   1.998 +  EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
   1.999 +  EXPECT_EQ(FileFlags(MH_TWOLEVEL |
  1.1000 +                      MH_DYLDLINK |
  1.1001 +                      MH_NOUNDEFS),
  1.1002 +            FileFlags(reader.flags()));
  1.1003 +  
  1.1004 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1005 +}
  1.1006 +
  1.1007 +TEST_F(LoadCommand, Unknown) {
  1.1008 +  WithConfiguration config(kBigEndian, 32);
  1.1009 +  LoadCommands load_commands;
  1.1010 +  load_commands
  1.1011 +      .CountCommand()
  1.1012 +      .D32(0x33293d4a)                  // unknown load command
  1.1013 +      .D32(40)                          // total size in bytes
  1.1014 +      .Append(32, '*');                 // dummy data
  1.1015 +  MachOFile file;
  1.1016 +  file.Header(&load_commands);
  1.1017 +
  1.1018 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1019 +
  1.1020 +  EXPECT_FALSE(reader.bits_64());
  1.1021 +  EXPECT_TRUE(reader.big_endian());
  1.1022 +  EXPECT_EQ(CPU_TYPE_X86,         reader.cpu_type());
  1.1023 +  EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
  1.1024 +  EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
  1.1025 +  EXPECT_EQ(FileFlags(MH_TWOLEVEL |
  1.1026 +                      MH_DYLDLINK |
  1.1027 +                      MH_NOUNDEFS),
  1.1028 +            reader.flags());
  1.1029 +
  1.1030 +  ByteBuffer expected;
  1.1031 +  expected.start = file_bytes + load_commands.start().Value();
  1.1032 +  expected.end = expected.start + load_commands.final_size().Value();
  1.1033 +  EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a,
  1.1034 +                                                   expected))
  1.1035 +      .WillOnce(Return(true));
  1.1036 +
  1.1037 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1038 +}
  1.1039 +
  1.1040 +TEST_F(LoadCommand, TypeIncomplete) {
  1.1041 +  WithConfiguration config(kLittleEndian, 32);
  1.1042 +  LoadCommands load_commands;
  1.1043 +  load_commands
  1.1044 +      .CountCommand()
  1.1045 +      .Append(3, 0);                    // load command type, incomplete
  1.1046 +
  1.1047 +  MachOFile file;
  1.1048 +  file.Header(&load_commands);
  1.1049 +
  1.1050 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1051 +
  1.1052 +  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0))
  1.1053 +      .WillOnce(Return());
  1.1054 +  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1.1055 +}
  1.1056 +
  1.1057 +TEST_F(LoadCommand, LengthIncomplete) {
  1.1058 +  WithConfiguration config(kBigEndian, 64);
  1.1059 +  LoadCommands load_commands;
  1.1060 +  load_commands
  1.1061 +      .CountCommand()
  1.1062 +      .D32(LC_SEGMENT);                 // load command
  1.1063 +                                                // no length
  1.1064 +  MachOFile file;
  1.1065 +  file.Header(&load_commands);
  1.1066 +
  1.1067 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1068 +
  1.1069 +  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
  1.1070 +      .WillOnce(Return());
  1.1071 +  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1.1072 +}
  1.1073 +
  1.1074 +TEST_F(LoadCommand, ContentIncomplete) {
  1.1075 +  WithConfiguration config(kLittleEndian, 64);
  1.1076 +  LoadCommands load_commands;
  1.1077 +  load_commands
  1.1078 +      .CountCommand()
  1.1079 +      .D32(LC_SEGMENT)          // load command
  1.1080 +      .D32(40)                          // total size in bytes
  1.1081 +      .Append(28, '*');                 // not enough dummy data
  1.1082 +  MachOFile file;
  1.1083 +  file.Header(&load_commands);
  1.1084 +
  1.1085 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1086 +
  1.1087 +  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
  1.1088 +      .WillOnce(Return());
  1.1089 +  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1.1090 +}
  1.1091 +
  1.1092 +TEST_F(LoadCommand, SegmentBE32) {
  1.1093 +  WithConfiguration config(kBigEndian, 32);
  1.1094 +  LoadedSection segment;
  1.1095 +  segment.address() = 0x1891139c;
  1.1096 +  segment.Append(42, '*');              // segment contents
  1.1097 +  SegmentLoadCommand segment_command;
  1.1098 +  segment_command
  1.1099 +      .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd);
  1.1100 +  segment_command.vmsize() = 0xcb76584fU;
  1.1101 +  LoadCommands load_commands;
  1.1102 +  load_commands.Place(&segment_command);
  1.1103 +  MachOFile file;
  1.1104 +  file
  1.1105 +      .Header(&load_commands)
  1.1106 +      .Place(&segment);
  1.1107 +
  1.1108 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1109 +
  1.1110 +  Segment actual_segment;
  1.1111 +  EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1.1112 +    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1.1113 +                    Return(true)));
  1.1114 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1115 +
  1.1116 +  EXPECT_EQ(false,                        actual_segment.bits_64);
  1.1117 +  EXPECT_EQ("froon",                      actual_segment.name);
  1.1118 +  EXPECT_EQ(0x1891139cU,                  actual_segment.vmaddr);
  1.1119 +  EXPECT_EQ(0xcb76584fU,                  actual_segment.vmsize);
  1.1120 +  EXPECT_EQ(0x94d6dd22U,                  actual_segment.maxprot);
  1.1121 +  EXPECT_EQ(0x8bdbc319U,                  actual_segment.initprot);
  1.1122 +  EXPECT_EQ(0x990a16ddU,                  actual_segment.flags);
  1.1123 +  EXPECT_EQ(0U,                           actual_segment.nsects);
  1.1124 +  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
  1.1125 +  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  1.1126 +}
  1.1127 +
  1.1128 +TEST_F(LoadCommand, SegmentLE32) {
  1.1129 +  WithConfiguration config(kLittleEndian, 32);
  1.1130 +  LoadedSection segment;
  1.1131 +  segment.address() = 0x4b877866;
  1.1132 +  segment.Append(42, '*');              // segment contents
  1.1133 +  SegmentLoadCommand segment_command;
  1.1134 +  segment_command
  1.1135 +      .Header("sixteenprecisely", segment,
  1.1136 +              0x350759ed, 0x6cf5a62e, 0x990a16dd);
  1.1137 +  segment_command.vmsize() = 0xcb76584fU;
  1.1138 +  LoadCommands load_commands;
  1.1139 +  load_commands.Place(&segment_command);
  1.1140 +  MachOFile file;
  1.1141 +  file
  1.1142 +      .Header(&load_commands)
  1.1143 +      .Place(&segment);
  1.1144 +
  1.1145 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1146 +
  1.1147 +  Segment actual_segment;
  1.1148 +  EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1.1149 +    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1.1150 +                    Return(true)));
  1.1151 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1152 +
  1.1153 +  EXPECT_EQ(false,                        actual_segment.bits_64);
  1.1154 +  EXPECT_EQ("sixteenprecisely",           actual_segment.name);
  1.1155 +  EXPECT_EQ(0x4b877866U,                  actual_segment.vmaddr);
  1.1156 +  EXPECT_EQ(0xcb76584fU,                  actual_segment.vmsize);
  1.1157 +  EXPECT_EQ(0x350759edU,                  actual_segment.maxprot);
  1.1158 +  EXPECT_EQ(0x6cf5a62eU,                  actual_segment.initprot);
  1.1159 +  EXPECT_EQ(0x990a16ddU,                  actual_segment.flags);
  1.1160 +  EXPECT_EQ(0U,                           actual_segment.nsects);
  1.1161 +  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
  1.1162 +  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  1.1163 +}
  1.1164 +
  1.1165 +TEST_F(LoadCommand, SegmentBE64) {
  1.1166 +  WithConfiguration config(kBigEndian, 64);
  1.1167 +  LoadedSection segment;
  1.1168 +  segment.address() = 0x79f484f77009e511ULL;
  1.1169 +  segment.Append(42, '*');              // segment contents
  1.1170 +  SegmentLoadCommand segment_command;
  1.1171 +  segment_command
  1.1172 +      .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220);
  1.1173 +  segment_command.vmsize() = 0x8d92397ce6248abaULL;
  1.1174 +  LoadCommands load_commands;
  1.1175 +  load_commands.Place(&segment_command);
  1.1176 +  MachOFile file;
  1.1177 +  file
  1.1178 +      .Header(&load_commands)
  1.1179 +      .Place(&segment);
  1.1180 +
  1.1181 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1182 +
  1.1183 +  Segment actual_segment;
  1.1184 +  EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1.1185 +    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1.1186 +                    Return(true)));
  1.1187 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1188 +
  1.1189 +  EXPECT_EQ(true,                         actual_segment.bits_64);
  1.1190 +  EXPECT_EQ("froon",                      actual_segment.name);
  1.1191 +  EXPECT_EQ(0x79f484f77009e511ULL,        actual_segment.vmaddr);
  1.1192 +  EXPECT_EQ(0x8d92397ce6248abaULL,        actual_segment.vmsize);
  1.1193 +  EXPECT_EQ(0x42b45da5U,                  actual_segment.maxprot);
  1.1194 +  EXPECT_EQ(0x8bdbc319U,                  actual_segment.initprot);
  1.1195 +  EXPECT_EQ(0xb2335220U,                  actual_segment.flags);
  1.1196 +  EXPECT_EQ(0U,                           actual_segment.nsects);
  1.1197 +  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
  1.1198 +  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  1.1199 +}
  1.1200 +
  1.1201 +TEST_F(LoadCommand, SegmentLE64) {
  1.1202 +  WithConfiguration config(kLittleEndian, 64);
  1.1203 +  LoadedSection segment;
  1.1204 +  segment.address() = 0x50c0501dc5922d35ULL;
  1.1205 +  segment.Append(42, '*');              // segment contents
  1.1206 +  SegmentLoadCommand segment_command;
  1.1207 +  segment_command
  1.1208 +      .Header("sixteenprecisely", segment,
  1.1209 +              0x917c339d, 0xdbc446fa, 0xb650b563);
  1.1210 +  segment_command.vmsize() = 0x84ae73e7c75469bfULL;
  1.1211 +  LoadCommands load_commands;
  1.1212 +  load_commands.Place(&segment_command);
  1.1213 +  MachOFile file;
  1.1214 +  file
  1.1215 +      .Header(&load_commands)
  1.1216 +      .Place(&segment);
  1.1217 +
  1.1218 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1219 +
  1.1220 +  Segment actual_segment;
  1.1221 +  EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1.1222 +    .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1.1223 +                    Return(true)));
  1.1224 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1225 +
  1.1226 +  EXPECT_EQ(true,                         actual_segment.bits_64);
  1.1227 +  EXPECT_EQ("sixteenprecisely",           actual_segment.name);
  1.1228 +  EXPECT_EQ(0x50c0501dc5922d35ULL,        actual_segment.vmaddr);
  1.1229 +  EXPECT_EQ(0x84ae73e7c75469bfULL,        actual_segment.vmsize);
  1.1230 +  EXPECT_EQ(0x917c339dU,                  actual_segment.maxprot);
  1.1231 +  EXPECT_EQ(0xdbc446faU,                  actual_segment.initprot);
  1.1232 +  EXPECT_EQ(0xb650b563U,                  actual_segment.flags);
  1.1233 +  EXPECT_EQ(0U,                           actual_segment.nsects);
  1.1234 +  EXPECT_EQ(0U,                           actual_segment.section_list.Size());
  1.1235 +  EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
  1.1236 +}
  1.1237 +
  1.1238 +TEST_F(LoadCommand, SegmentCommandTruncated) {
  1.1239 +  WithConfiguration config(kBigEndian, 32);
  1.1240 +  LoadedSection segment_contents;
  1.1241 +  segment_contents.Append(20, '*');     	// lah di dah
  1.1242 +  SizedSection command;
  1.1243 +  command
  1.1244 +      .D32(LC_SEGMENT)          	// command type
  1.1245 +      .D32(command.final_size())                // command size
  1.1246 +      .AppendCString("too-short", 16)           // segment name
  1.1247 +      .D32(0x9c759211)                          // vmaddr
  1.1248 +      .D32(segment_contents.final_size())       // vmsize
  1.1249 +      .D32(segment_contents.start())            // file offset
  1.1250 +      .D32(segment_contents.final_size())       // file size
  1.1251 +      .D32(0x56f28446)                          // max protection
  1.1252 +      .D32(0xe7910dcb)                          // initial protection
  1.1253 +      .D32(0)                                   // no sections
  1.1254 +      .Append(3, 0);                            // flags (one byte short!)
  1.1255 +  LoadCommands load_commands;
  1.1256 +  load_commands.Place(&command);
  1.1257 +  MachOFile file;
  1.1258 +  file
  1.1259 +      .Header(&load_commands)
  1.1260 +      .Place(&segment_contents);
  1.1261 +  
  1.1262 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1263 +
  1.1264 +  EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT))
  1.1265 +      .WillOnce(Return());
  1.1266 +
  1.1267 +  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1.1268 +}
  1.1269 +
  1.1270 +TEST_F(LoadCommand, SegmentBadContentOffset) {
  1.1271 +  WithConfiguration config(kLittleEndian, 32);
  1.1272 +  // Instead of letting a Place call set the segment's file offset and size,
  1.1273 +  // set them ourselves, to check that the parser catches invalid offsets
  1.1274 +  // instead of handing us bogus pointers.
  1.1275 +  LoadedSection segment;
  1.1276 +  segment.address() = 0x4db5489c;
  1.1277 +  segment.start() = 0x7e189e76;         // beyond end of file
  1.1278 +  segment.final_size() = 0x98b9c3ab;
  1.1279 +  SegmentLoadCommand segment_command;
  1.1280 +  segment_command
  1.1281 +      .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f);
  1.1282 +  LoadCommands load_commands;
  1.1283 +  load_commands.Place(&segment_command);
  1.1284 +  MachOFile file;
  1.1285 +  file.Header(&load_commands);
  1.1286 +
  1.1287 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1288 +
  1.1289 +  EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen"))
  1.1290 +      .WillOnce(Return());
  1.1291 +
  1.1292 +  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1.1293 +}
  1.1294 +
  1.1295 +TEST_F(LoadCommand, ThreeLoadCommands) {
  1.1296 +  WithConfiguration config(kBigEndian, 32);
  1.1297 +  LoadedSection seg1, seg2, seg3;
  1.1298 +  SegmentLoadCommand cmd1, cmd2, cmd3;
  1.1299 +
  1.1300 +  seg1.Append(128, '@');
  1.1301 +  seg1.address() = 0xa7f61ef6;
  1.1302 +  cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87);
  1.1303 +  // Include some dummy data at the end of the load command. Since we
  1.1304 +  // didn't claim to have any sections, the reader should ignore this. But
  1.1305 +  // making sure the commands have different lengths ensures that we're
  1.1306 +  // using the right command's length to advance the LoadCommandIterator.
  1.1307 +  cmd1.Append(128, '!');
  1.1308 +
  1.1309 +  seg2.Append(42, '*');
  1.1310 +  seg2.address() = 0xc70fc909;
  1.1311 +  cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30);
  1.1312 +  // More dummy data at the end of the load command. 
  1.1313 +  cmd2.Append(32, '^');
  1.1314 +
  1.1315 +  seg3.Append(42, '%');
  1.1316 +  seg3.address() = 0x46b3ab05;
  1.1317 +  cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b);
  1.1318 +  // More dummy data at the end of the load command. 
  1.1319 +  cmd3.Append(64, '&');
  1.1320 +
  1.1321 +  LoadCommands load_commands;
  1.1322 +  load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
  1.1323 +
  1.1324 +  MachOFile file;
  1.1325 +  file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3);
  1.1326 +
  1.1327 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1328 +
  1.1329 +  {
  1.1330 +    InSequence s;
  1.1331 +    EXPECT_CALL(load_command_handler,
  1.1332 +                SegmentCommand(Field(&Segment::name, "head")))
  1.1333 +      .WillOnce(Return(true));
  1.1334 +    EXPECT_CALL(load_command_handler,
  1.1335 +                SegmentCommand(Field(&Segment::name, "thorax")))
  1.1336 +      .WillOnce(Return(true));
  1.1337 +    EXPECT_CALL(load_command_handler,
  1.1338 +                SegmentCommand(Field(&Segment::name, "abdomen")))
  1.1339 +      .WillOnce(Return(true));
  1.1340 +  }
  1.1341 +
  1.1342 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1343 +}
  1.1344 +
  1.1345 +static inline Matcher<const Section &> MatchSection(
  1.1346 +    Matcher<bool> bits_64,
  1.1347 +    Matcher<const string &> section_name,
  1.1348 +    Matcher<const string &> segment_name,
  1.1349 +    Matcher<uint64_t> address,
  1.1350 +    Matcher<uint32_t> alignment,
  1.1351 +    Matcher<uint32_t> flags,
  1.1352 +    Matcher<const ByteBuffer &> contents) {
  1.1353 +  return AllOf(AllOf(Field(&Section::bits_64, bits_64),
  1.1354 +                     Field(&Section::section_name, section_name),
  1.1355 +                     Field(&Section::segment_name, segment_name),
  1.1356 +                     Field(&Section::address, address)),
  1.1357 +               AllOf(Field(&Section::align, alignment),
  1.1358 +                     Field(&Section::flags, flags),
  1.1359 +                     Field(&Section::contents, contents)));
  1.1360 +}
  1.1361 +
  1.1362 +static inline Matcher<const Section &> MatchSection(
  1.1363 +    Matcher<bool> bits_64,
  1.1364 +    Matcher<const string &> section_name,
  1.1365 +    Matcher<const string &> segment_name,
  1.1366 +    Matcher<uint64_t> address) {
  1.1367 +  return AllOf(Field(&Section::bits_64, bits_64),
  1.1368 +               Field(&Section::section_name, section_name),
  1.1369 +               Field(&Section::segment_name, segment_name),
  1.1370 +               Field(&Section::address, address));
  1.1371 +}
  1.1372 +
  1.1373 +TEST_F(LoadCommand, OneSegmentTwoSections) {
  1.1374 +  WithConfiguration config(kBigEndian, 64);
  1.1375 +
  1.1376 +  // Create some sections with some data.
  1.1377 +  LoadedSection section1, section2;
  1.1378 +  section1.Append("buddha's hand");
  1.1379 +  section2.Append("kumquat");
  1.1380 +
  1.1381 +  // Create a segment to hold them.
  1.1382 +  LoadedSection segment;
  1.1383 +  segment.address() = 0xe1d0eeec;
  1.1384 +  segment.Place(&section2).Place(&section1);
  1.1385 +
  1.1386 +  SegmentLoadCommand segment_command;
  1.1387 +  segment_command
  1.1388 +      .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2)
  1.1389 +      .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1)
  1.1390 +      .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2);
  1.1391 +
  1.1392 +  LoadCommands commands;
  1.1393 +  commands.Place(&segment_command);
  1.1394 +
  1.1395 +  MachOFile file;
  1.1396 +  file.Header(&commands).Place(&segment);
  1.1397 +
  1.1398 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1399 +  
  1.1400 +  Segment actual_segment;
  1.1401 +  EXPECT_CALL(load_command_handler, SegmentCommand(_))
  1.1402 +      .WillOnce(DoAll(SaveArg<0>(&actual_segment),
  1.1403 +                      Return(true)));
  1.1404 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1405 +
  1.1406 +  {
  1.1407 +    InSequence s;
  1.1408 +    ByteBuffer contents1;
  1.1409 +    contents1.start = file_bytes + section1.start().Value();
  1.1410 +    contents1.end = contents1.start + section1.final_size().Value();
  1.1411 +    EXPECT_EQ("buddha's hand",
  1.1412 +              string(reinterpret_cast<const char *>(contents1.start),
  1.1413 +                     contents1.Size()));
  1.1414 +    EXPECT_CALL(section_handler,
  1.1415 +                HandleSection(MatchSection(true, "mandarin", "kishu",
  1.1416 +                                           section1.address().Value(), 12,
  1.1417 +                                           0x8cd4604bU, contents1)))
  1.1418 +      .WillOnce(Return(true));
  1.1419 +    
  1.1420 +    ByteBuffer contents2;
  1.1421 +    contents2.start = file_bytes + section2.start().Value();
  1.1422 +    contents2.end = contents2.start + section2.final_size().Value();
  1.1423 +    EXPECT_EQ("kumquat",
  1.1424 +              string(reinterpret_cast<const char *>(contents2.start),
  1.1425 +                     contents2.Size()));
  1.1426 +    EXPECT_CALL(section_handler,
  1.1427 +                HandleSection(MatchSection(true, "bergamot", "cara cara",
  1.1428 +                                           section2.address().Value(), 12,
  1.1429 +                                           0x98746efaU, contents2)))
  1.1430 +      .WillOnce(Return(true));
  1.1431 +  }
  1.1432 +
  1.1433 +  EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1.1434 +}
  1.1435 +
  1.1436 +TEST_F(LoadCommand, MisplacedSectionBefore) {
  1.1437 +  WithConfiguration config(kLittleEndian, 64);
  1.1438 +
  1.1439 +  // The segment.
  1.1440 +  LoadedSection segment;
  1.1441 +  segment.address() = 0x696d83cc;
  1.1442 +  segment.Append(10, '0');
  1.1443 +
  1.1444 +  // The contents of the following sections don't matter, because
  1.1445 +  // we're not really going to Place them in segment; we're just going
  1.1446 +  // to set all their labels by hand to get the (impossible)
  1.1447 +  // configurations we want.
  1.1448 +
  1.1449 +  // A section whose starting offset is before that of its section.
  1.1450 +  LoadedSection before;
  1.1451 +  before.Append(10, '1');
  1.1452 +  before.start()   = segment.start() - 1;
  1.1453 +  before.address() = segment.address() - 1;
  1.1454 +  before.final_size() = before.Size();
  1.1455 +  
  1.1456 +  SegmentLoadCommand command;
  1.1457 +  command
  1.1458 +    .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
  1.1459 +    .AppendSectionEntry("before",     "segment", 0, 0x686c6921, before);
  1.1460 +
  1.1461 +  LoadCommands commands;
  1.1462 +  commands.Place(&command);
  1.1463 +
  1.1464 +  MachOFile file;
  1.1465 +  file.Header(&commands).Place(&segment);
  1.1466 +
  1.1467 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1468 +
  1.1469 +  Segment actual_segment;
  1.1470 +  EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
  1.1471 +
  1.1472 +  EXPECT_CALL(reporter, MisplacedSectionData("before", "segment"))
  1.1473 +    .WillOnce(Return());
  1.1474 +  EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1.1475 +}
  1.1476 +
  1.1477 +TEST_F(LoadCommand, MisplacedSectionAfter) {
  1.1478 +  WithConfiguration config(kLittleEndian, 64);
  1.1479 +
  1.1480 +  // The segment.
  1.1481 +  LoadedSection segment;
  1.1482 +  segment.address() = 0x696d83cc;
  1.1483 +  segment.Append(10, '0');
  1.1484 +
  1.1485 +  // The contents of the following sections don't matter, because
  1.1486 +  // we're not really going to Place them in segment; we're just going
  1.1487 +  // to set all their labels by hand to get the (impossible)
  1.1488 +  // configurations we want.
  1.1489 +
  1.1490 +  // A section whose starting offset is after the end of its section.
  1.1491 +  LoadedSection after;
  1.1492 +  after.Append(10, '2');
  1.1493 +  after.start()    = segment.start() + 11;
  1.1494 +  after.address()   = segment.address() + 11;
  1.1495 +  after.final_size() = after.Size();
  1.1496 +
  1.1497 +  SegmentLoadCommand command;
  1.1498 +  command
  1.1499 +    .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
  1.1500 +    .AppendSectionEntry("after",      "segment", 0, 0x2ee50124, after);
  1.1501 +
  1.1502 +  LoadCommands commands;
  1.1503 +  commands.Place(&command);
  1.1504 +
  1.1505 +  MachOFile file;
  1.1506 +  file.Header(&commands).Place(&segment);
  1.1507 +
  1.1508 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1509 +
  1.1510 +  Segment actual_segment;
  1.1511 +  EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
  1.1512 +
  1.1513 +  EXPECT_CALL(reporter, MisplacedSectionData("after", "segment"))
  1.1514 +    .WillOnce(Return());
  1.1515 +  EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1.1516 +}
  1.1517 +
  1.1518 +TEST_F(LoadCommand, MisplacedSectionTooBig) {
  1.1519 +  WithConfiguration config(kLittleEndian, 64);
  1.1520 +
  1.1521 +  // The segment.
  1.1522 +  LoadedSection segment;
  1.1523 +  segment.address() = 0x696d83cc;
  1.1524 +  segment.Append(10, '0');
  1.1525 +
  1.1526 +  // The contents of the following sections don't matter, because
  1.1527 +  // we're not really going to Place them in segment; we're just going
  1.1528 +  // to set all their labels by hand to get the (impossible)
  1.1529 +  // configurations we want.
  1.1530 +
  1.1531 +  // A section that extends beyond the end of its section.
  1.1532 +  LoadedSection too_big;
  1.1533 +  too_big.Append(10, '3');
  1.1534 +  too_big.start()   = segment.start() + 1;
  1.1535 +  too_big.address() = segment.address() + 1;
  1.1536 +  too_big.final_size() = too_big.Size();
  1.1537 +
  1.1538 +  SegmentLoadCommand command;
  1.1539 +  command
  1.1540 +    .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
  1.1541 +    .AppendSectionEntry("too big",    "segment", 0, 0x8b53ae5c, too_big);
  1.1542 +
  1.1543 +  LoadCommands commands;
  1.1544 +  commands.Place(&command);
  1.1545 +
  1.1546 +  MachOFile file;
  1.1547 +  file.Header(&commands).Place(&segment);
  1.1548 +
  1.1549 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1550 +
  1.1551 +  Segment actual_segment;
  1.1552 +  EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
  1.1553 +
  1.1554 +  EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment"))
  1.1555 +    .WillOnce(Return());
  1.1556 +  EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1.1557 +}
  1.1558 +
  1.1559 +
  1.1560 +// The segments in a .dSYM bundle's Mach-O file have their file offset
  1.1561 +// and size set to zero, but the sections don't.  The reader shouldn't
  1.1562 +// report an error in this case.
  1.1563 +TEST_F(LoadCommand, ZappedSegment) {
  1.1564 +  WithConfiguration config(kBigEndian, 32);
  1.1565 +
  1.1566 +  // The segment.
  1.1567 +  LoadedSection segment;
  1.1568 +  segment.address() = 0x696d83cc;
  1.1569 +  segment.start() = 0;
  1.1570 +  segment.final_size() = 0;
  1.1571 +
  1.1572 +  // The section.
  1.1573 +  LoadedSection section;
  1.1574 +  section.address() = segment.address();
  1.1575 +  section.start() = 0;
  1.1576 +  section.final_size() = 1000;          // extends beyond its segment
  1.1577 +  
  1.1578 +  SegmentLoadCommand command;
  1.1579 +  command
  1.1580 +    .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c)
  1.1581 +    .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section);
  1.1582 +
  1.1583 +  LoadCommands commands;
  1.1584 +  commands.Place(&command);
  1.1585 +
  1.1586 +  MachOFile file;
  1.1587 +  file.Header(&commands);
  1.1588 +
  1.1589 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1590 +
  1.1591 +  Segment actual_segment;
  1.1592 +  EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment));
  1.1593 +
  1.1594 +  ByteBuffer zapped_extent(NULL, 0);
  1.1595 +  EXPECT_CALL(section_handler,
  1.1596 +              HandleSection(MatchSection(false, "twitching", "zapped",
  1.1597 +                                         0x696d83cc, 0, 0x93b3bd42,
  1.1598 +                                         zapped_extent)))
  1.1599 +    .WillOnce(Return(true));
  1.1600 +
  1.1601 +  EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
  1.1602 +}
  1.1603 +
  1.1604 +TEST_F(LoadCommand, MapSegmentSections) {
  1.1605 +  WithConfiguration config(kLittleEndian, 32);
  1.1606 +
  1.1607 +  // Create some sections with some data.
  1.1608 +  LoadedSection section1, section2, section3, section4;
  1.1609 +  section1.Append("buddha's hand");
  1.1610 +  section2.start() = 0;                 // Section 2 is an S_ZEROFILL section.
  1.1611 +  section2.final_size() = 0;
  1.1612 +  section3.Append("shasta gold");
  1.1613 +  section4.Append("satsuma");
  1.1614 +
  1.1615 +  // Create two segments to hold them.
  1.1616 +  LoadedSection segment1, segment2;
  1.1617 +  segment1.address() = 0x13e6c8a9;
  1.1618 +  segment1.Place(&section3).Place(&section1);
  1.1619 +  segment2.set_word_size(64);
  1.1620 +  segment2.address() = 0x04d462e2;
  1.1621 +  segment2.Place(&section4);
  1.1622 +  section2.address() = segment2.address() + segment2.Size();
  1.1623 +
  1.1624 +  SegmentLoadCommand segment_command1, segment_command2;
  1.1625 +  segment_command1
  1.1626 +      .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64)
  1.1627 +      .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1)
  1.1628 +      .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3);
  1.1629 +  segment_command2.set_word_size(64);
  1.1630 +  segment_command2
  1.1631 +      .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33)
  1.1632 +      .AppendSectionEntry("sixteenprecisely", "thorax",
  1.1633 +                          12, S_ZEROFILL, section2)
  1.1634 +      .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4);
  1.1635 +
  1.1636 +  LoadCommands commands;
  1.1637 +  commands.Place(&segment_command1).Place(&segment_command2);
  1.1638 +
  1.1639 +  MachOFile file;
  1.1640 +  file.Header(&commands).Place(&segment1).Place(&segment2);
  1.1641 +
  1.1642 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1643 +
  1.1644 +  Segment segment;
  1.1645 +  SectionMap section_map;
  1.1646 +
  1.1647 +  EXPECT_FALSE(reader.FindSegment("smoot", &segment));
  1.1648 +
  1.1649 +  ASSERT_TRUE(reader.FindSegment("thorax", &segment));
  1.1650 +  ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
  1.1651 +
  1.1652 +  EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome")
  1.1653 +               != section_map.end());
  1.1654 +  EXPECT_FALSE(section_map.find("mandarin") != section_map.end());
  1.1655 +  ASSERT_TRUE(section_map.find("cara cara") != section_map.end());
  1.1656 +  EXPECT_THAT(section_map["cara cara"],
  1.1657 +              MatchSection(true, "cara cara", "thorax", 0x04d462e2));
  1.1658 +  ASSERT_TRUE(section_map.find("sixteenprecisely")
  1.1659 +              != section_map.end());
  1.1660 +  ByteBuffer sixteenprecisely_contents(NULL, 0);
  1.1661 +  EXPECT_THAT(section_map["sixteenprecisely"],
  1.1662 +              MatchSection(true, "sixteenprecisely", "thorax",
  1.1663 +                           0x04d462e2 + 7, 12, S_ZEROFILL,
  1.1664 +                           sixteenprecisely_contents));
  1.1665 +
  1.1666 +  ASSERT_TRUE(reader.FindSegment("head", &segment));
  1.1667 +  ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
  1.1668 +
  1.1669 +  ASSERT_TRUE(section_map.find("mandarin") != section_map.end());
  1.1670 +  EXPECT_THAT(section_map["mandarin"],
  1.1671 +              MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11));
  1.1672 +  ASSERT_TRUE(section_map.find("bergamot") != section_map.end());
  1.1673 +  EXPECT_THAT(section_map["bergamot"],
  1.1674 +              MatchSection(false, "bergamot", "head", 0x13e6c8a9));
  1.1675 +}
  1.1676 +
  1.1677 +TEST_F(LoadCommand, FindSegment) {
  1.1678 +  WithConfiguration config(kBigEndian, 32);
  1.1679 +
  1.1680 +  LoadedSection segment1, segment2, segment3;
  1.1681 +  segment1.address() = 0xb8ae5752;
  1.1682 +  segment1.Append("Some contents!");
  1.1683 +  segment2.address() = 0xd6b0ce83;
  1.1684 +  segment2.Append("Different stuff.");
  1.1685 +  segment3.address() = 0x7374fd2a;
  1.1686 +  segment3.Append("Further materials.");
  1.1687 +
  1.1688 +  SegmentLoadCommand cmd1, cmd2, cmd3;
  1.1689 +  cmd1.Header("first",  segment1, 0xfadb6932, 0x175bf529, 0x0de790ad);
  1.1690 +  cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef);
  1.1691 +  cmd3.Header("third",  segment3, 0xe172b39e, 0x86012f07, 0x080ac94d);
  1.1692 +
  1.1693 +  LoadCommands commands;
  1.1694 +  commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
  1.1695 +
  1.1696 +  MachOFile file;
  1.1697 +  file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3);
  1.1698 +
  1.1699 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1700 +
  1.1701 +  Segment actual_segment;
  1.1702 +
  1.1703 +  EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment));
  1.1704 +
  1.1705 +  EXPECT_TRUE(reader.FindSegment("second", &actual_segment));
  1.1706 +  EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr);
  1.1707 +}
  1.1708 +
  1.1709 +
  1.1710 +// Symtab tests.
  1.1711 +
  1.1712 +// A StringAssembler is a class for generating .stabstr sections to present
  1.1713 +// as input to the STABS parser.
  1.1714 +class StringAssembler: public SizedSection {
  1.1715 + public:
  1.1716 +  // Add the string S to this StringAssembler, and return the string's
  1.1717 +  // offset within this compilation unit's strings.
  1.1718 +  size_t Add(const string &s) {
  1.1719 +    size_t offset = Size();
  1.1720 +    AppendCString(s);
  1.1721 +    return offset;
  1.1722 +  }
  1.1723 +};
  1.1724 +
  1.1725 +// A SymbolAssembler is a class for generating .stab sections to present as
  1.1726 +// test input for the STABS parser.
  1.1727 +class SymbolAssembler: public SizedSection {
  1.1728 + public:
  1.1729 +  // Create a SymbolAssembler that uses StringAssembler for its strings.
  1.1730 +  explicit SymbolAssembler(StringAssembler *string_assembler) 
  1.1731 +      : string_assembler_(string_assembler),
  1.1732 +        entry_count_(0) { }
  1.1733 +
  1.1734 +  // Append a STAB entry to the end of this section with the given
  1.1735 +  // characteristics. NAME is the offset of this entry's name string within
  1.1736 +  // its compilation unit's portion of the .stabstr section; this can be a
  1.1737 +  // value generated by a StringAssembler. Return a reference to this
  1.1738 +  // SymbolAssembler.
  1.1739 +  SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
  1.1740 +                          Label value, Label name) {
  1.1741 +    D32(name);
  1.1742 +    D8(type);
  1.1743 +    D8(other);
  1.1744 +    D16(descriptor);
  1.1745 +    Append(endianness(), word_size_ / 8, value);
  1.1746 +    entry_count_++;
  1.1747 +    return *this;
  1.1748 +  }
  1.1749 +
  1.1750 +  // As above, but automatically add NAME to our StringAssembler.
  1.1751 +  SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
  1.1752 +                       Label value, const string &name) {
  1.1753 +    return Symbol(type, other, descriptor, value, string_assembler_->Add(name));
  1.1754 +  }
  1.1755 +
  1.1756 + private:
  1.1757 +  // The strings for our STABS entries.
  1.1758 +  StringAssembler *string_assembler_;
  1.1759 +
  1.1760 +  // The number of entries in this compilation unit so far.
  1.1761 +  size_t entry_count_;
  1.1762 +};
  1.1763 +
  1.1764 +class Symtab: public ReaderFixture, public Test { };
  1.1765 +
  1.1766 +TEST_F(Symtab, Symtab32) {
  1.1767 +  WithConfiguration config(kLittleEndian, 32);
  1.1768 +
  1.1769 +  StringAssembler strings;
  1.1770 +  SymbolAssembler symbols(&strings);
  1.1771 +  symbols
  1.1772 +      .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu")
  1.1773 +      .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith");
  1.1774 +
  1.1775 +  SizedSection symtab_command;
  1.1776 +  symtab_command
  1.1777 +      .D32(LC_SYMTAB)                    // command
  1.1778 +      .D32(symtab_command.final_size())  // size
  1.1779 +      .D32(symbols.start())              // file offset of symbols
  1.1780 +      .D32(2)                            // symbol count
  1.1781 +      .D32(strings.start())              // file offset of strings
  1.1782 +      .D32(strings.final_size());        // strings size
  1.1783 +
  1.1784 +  LoadCommands load_commands;
  1.1785 +  load_commands.Place(&symtab_command);
  1.1786 +
  1.1787 +  MachOFile file;
  1.1788 +  file.Header(&load_commands).Place(&symbols).Place(&strings);
  1.1789 +
  1.1790 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1791 +
  1.1792 +  ByteBuffer symbols_found, strings_found;
  1.1793 +  EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
  1.1794 +      .WillOnce(DoAll(SaveArg<0>(&symbols_found),
  1.1795 +                      SaveArg<1>(&strings_found),
  1.1796 +                      Return(true)));
  1.1797 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1798 +
  1.1799 +  EXPECT_EQ(24U, symbols_found.Size());
  1.1800 +  EXPECT_EQ(14U, strings_found.Size());
  1.1801 +}
  1.1802 +
  1.1803 +TEST_F(Symtab, Symtab64) {
  1.1804 +  WithConfiguration config(kBigEndian, 64);
  1.1805 +
  1.1806 +  StringAssembler strings;
  1.1807 +  SymbolAssembler symbols(&strings);
  1.1808 +  symbols
  1.1809 +      .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
  1.1810 +      .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
  1.1811 +
  1.1812 +  SizedSection symtab_command;
  1.1813 +  symtab_command
  1.1814 +      .D32(LC_SYMTAB)                    // command
  1.1815 +      .D32(symtab_command.final_size())  // size
  1.1816 +      .D32(symbols.start())              // file offset of symbols
  1.1817 +      .D32(2)                            // symbol count
  1.1818 +      .D32(strings.start())              // file offset of strings
  1.1819 +      .D32(strings.final_size());        // strings size
  1.1820 +
  1.1821 +  LoadCommands load_commands;
  1.1822 +  load_commands.Place(&symtab_command);
  1.1823 +
  1.1824 +  MachOFile file;
  1.1825 +  file.Header(&load_commands).Place(&symbols).Place(&strings);
  1.1826 +
  1.1827 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1828 +
  1.1829 +  ByteBuffer symbols_found, strings_found;
  1.1830 +  EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
  1.1831 +      .WillOnce(DoAll(SaveArg<0>(&symbols_found),
  1.1832 +                      SaveArg<1>(&strings_found),
  1.1833 +                      Return(true)));
  1.1834 +  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
  1.1835 +
  1.1836 +  EXPECT_EQ(32U, symbols_found.Size());
  1.1837 +  EXPECT_EQ(8U,  strings_found.Size());
  1.1838 +}
  1.1839 +
  1.1840 +TEST_F(Symtab, SymtabMisplacedSymbols) {
  1.1841 +  WithConfiguration config(kBigEndian, 32);
  1.1842 +
  1.1843 +  StringAssembler strings;
  1.1844 +  SymbolAssembler symbols(&strings);
  1.1845 +  symbols
  1.1846 +      .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
  1.1847 +      .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
  1.1848 +
  1.1849 +  SizedSection symtab_command;
  1.1850 +  symtab_command
  1.1851 +      .D32(LC_SYMTAB)                    // command
  1.1852 +      .D32(symtab_command.final_size())  // size
  1.1853 +      .D32(symbols.start())              // file offset of symbols
  1.1854 +      .D32(3)                            // symbol count (too many)
  1.1855 +      .D32(strings.start())              // file offset of strings
  1.1856 +      .D32(strings.final_size());        // strings size
  1.1857 +
  1.1858 +  LoadCommands load_commands;
  1.1859 +  load_commands.Place(&symtab_command);
  1.1860 +
  1.1861 +  MachOFile file;
  1.1862 +  // Put symbols at end, so the excessive length will be noticed.
  1.1863 +  file.Header(&load_commands).Place(&strings).Place(&symbols);
  1.1864 +
  1.1865 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1866 +
  1.1867 +  EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
  1.1868 +  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1.1869 +}
  1.1870 +
  1.1871 +TEST_F(Symtab, SymtabMisplacedStrings) {
  1.1872 +  WithConfiguration config(kLittleEndian, 32);
  1.1873 +
  1.1874 +  StringAssembler strings;
  1.1875 +  SymbolAssembler symbols(&strings);
  1.1876 +  symbols
  1.1877 +      .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
  1.1878 +      .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
  1.1879 +
  1.1880 +  SizedSection symtab_command;
  1.1881 +  symtab_command
  1.1882 +      .D32(LC_SYMTAB)                    // command
  1.1883 +      .D32(symtab_command.final_size())  // size
  1.1884 +      .D32(symbols.start())              // file offset of symbols
  1.1885 +      .D32(2)                            // symbol count
  1.1886 +      .D32(strings.start())              // file offset of strings
  1.1887 +      .D32(strings.final_size() + 1);    // strings size (too long)
  1.1888 +
  1.1889 +  LoadCommands load_commands;
  1.1890 +  load_commands.Place(&symtab_command);
  1.1891 +
  1.1892 +  MachOFile file;
  1.1893 +  // Put strings at end, so the excessive length will be noticed.
  1.1894 +  file.Header(&load_commands).Place(&symbols).Place(&strings);
  1.1895 +
  1.1896 +  ReadFile(&file, true, CPU_TYPE_ANY, 0);
  1.1897 +
  1.1898 +  EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
  1.1899 +  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
  1.1900 +}
  1.1901 +

mercurial