Home | History | Annotate | Download | only in mac
      1 // Copyright (c) 2010 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // Original author: Jim Blandy <jimb (at) mozilla.com> <jimb (at) red-bean.com>
     31 
     32 // macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader
     33 // and google_breakpad::Mach_O::Reader.
     34 
     35 #include <map>
     36 #include <string>
     37 #include <vector>
     38 
     39 #include "breakpad_googletest_includes.h"
     40 #include "common/mac/macho_reader.h"
     41 #include "common/test_assembler.h"
     42 
     43 namespace mach_o = google_breakpad::mach_o;
     44 namespace test_assembler = google_breakpad::test_assembler;
     45 
     46 using mach_o::FatReader;
     47 using mach_o::FileFlags;
     48 using mach_o::FileType;
     49 using mach_o::LoadCommandType;
     50 using mach_o::Reader;
     51 using mach_o::Section;
     52 using mach_o::SectionMap;
     53 using mach_o::Segment;
     54 using test_assembler::Endianness;
     55 using test_assembler::Label;
     56 using test_assembler::kBigEndian;
     57 using test_assembler::kLittleEndian;
     58 using test_assembler::kUnsetEndian;
     59 using google_breakpad::ByteBuffer;
     60 using std::map;
     61 using std::string;
     62 using std::vector;
     63 using testing::AllOf;
     64 using testing::DoAll;
     65 using testing::Field;
     66 using testing::InSequence;
     67 using testing::Matcher;
     68 using testing::Return;
     69 using testing::SaveArg;
     70 using testing::Test;
     71 using testing::_;
     72 
     73 
     74 // Mock classes for the reader's various reporters and handlers.
     76 
     77 class MockFatReaderReporter: public FatReader::Reporter {
     78  public:
     79   MockFatReaderReporter(const string &filename)
     80       : FatReader::Reporter(filename) { }
     81   MOCK_METHOD0(BadHeader, void());
     82   MOCK_METHOD0(MisplacedObjectFile, void());
     83   MOCK_METHOD0(TooShort, void());
     84 };
     85 
     86 class MockReaderReporter: public Reader::Reporter {
     87  public:
     88   MockReaderReporter(const string &filename) : Reader::Reporter(filename) { }
     89   MOCK_METHOD0(BadHeader, void());
     90   MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type,
     91                                      cpu_subtype_t cpu_subtype,
     92                                      cpu_type_t expected_cpu_type,
     93                                      cpu_subtype_t expected_cpu_subtype));
     94   MOCK_METHOD0(HeaderTruncated, void());
     95   MOCK_METHOD0(LoadCommandRegionTruncated, void());
     96   MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i,
     97                                          LoadCommandType type));
     98   MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type));
     99   MOCK_METHOD1(SectionsMissing, void(const string &name));
    100   MOCK_METHOD1(MisplacedSegmentData, void(const string &name));
    101   MOCK_METHOD2(MisplacedSectionData, void(const string &section,
    102                                           const string &segment));
    103   MOCK_METHOD0(MisplacedSymbolTable, void());
    104   MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type));
    105 };
    106 
    107 class MockLoadCommandHandler: public Reader::LoadCommandHandler {
    108  public:
    109   MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &));
    110   MOCK_METHOD1(SegmentCommand, bool(const Segment &));
    111   MOCK_METHOD2(SymtabCommand,  bool(const ByteBuffer &, const ByteBuffer &));
    112 };
    113 
    114 class MockSectionHandler: public Reader::SectionHandler {
    115  public:
    116   MOCK_METHOD1(HandleSection, bool(const Section &section));
    117 };
    118 
    119 
    120 // Tests for mach_o::FatReader.
    122 
    123 // Since the effect of these functions is to write to stderr, the
    124 // results of these tests must be inspected by hand.
    125 TEST(FatReaderReporter, BadHeader) {
    126   FatReader::Reporter reporter("filename");
    127   reporter.BadHeader();
    128 }
    129 
    130 TEST(FatReaderReporter, MisplacedObjectFile) {
    131   FatReader::Reporter reporter("filename");
    132   reporter.MisplacedObjectFile();
    133 }
    134 
    135 TEST(FatReaderReporter, TooShort) {
    136   FatReader::Reporter reporter("filename");
    137   reporter.TooShort();
    138 }
    139 
    140 TEST(MachOReaderReporter, BadHeader) {
    141   Reader::Reporter reporter("filename");
    142   reporter.BadHeader();
    143 }
    144 
    145 TEST(MachOReaderReporter, CPUTypeMismatch) {
    146   Reader::Reporter reporter("filename");
    147   reporter.CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
    148                            CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
    149 }
    150 
    151 TEST(MachOReaderReporter, HeaderTruncated) {
    152   Reader::Reporter reporter("filename");
    153   reporter.HeaderTruncated();
    154 }
    155 
    156 TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
    157   Reader::Reporter reporter("filename");
    158   reporter.LoadCommandRegionTruncated();
    159 }
    160 
    161 TEST(MachOReaderReporter, LoadCommandsOverrun) {
    162   Reader::Reporter reporter("filename");
    163   reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
    164   reporter.LoadCommandsOverrun(10, 9, 0);
    165 }
    166 
    167 TEST(MachOReaderReporter, LoadCommandTooShort) {
    168   Reader::Reporter reporter("filename");
    169   reporter.LoadCommandTooShort(11, LC_SYMTAB);
    170 }
    171 
    172 TEST(MachOReaderReporter, SectionsMissing) {
    173   Reader::Reporter reporter("filename");
    174   reporter.SectionsMissing("segment name");
    175 }
    176 
    177 TEST(MachOReaderReporter, MisplacedSegmentData) {
    178   Reader::Reporter reporter("filename");
    179   reporter.MisplacedSegmentData("segment name");
    180 }
    181 
    182 TEST(MachOReaderReporter, MisplacedSectionData) {
    183   Reader::Reporter reporter("filename");
    184   reporter.MisplacedSectionData("section name", "segment name");
    185 }
    186 
    187 TEST(MachOReaderReporter, MisplacedSymbolTable) {
    188   Reader::Reporter reporter("filename");
    189   reporter.MisplacedSymbolTable();
    190 }
    191 
    192 TEST(MachOReaderReporter, UnsupportedCPUType) {
    193   Reader::Reporter reporter("filename");
    194   reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
    195 }
    196 
    197 struct FatReaderFixture {
    198   FatReaderFixture()
    199       : fat(kBigEndian),
    200         reporter("reporter filename"),
    201         reader(&reporter), object_files(), object_files_size() {
    202     EXPECT_CALL(reporter, BadHeader()).Times(0);
    203     EXPECT_CALL(reporter, TooShort()).Times(0);
    204 
    205     // here, start, and Mark are file offsets in 'fat'.
    206     fat.start() = 0;
    207   }
    208   // Append a 'fat_arch' entry to 'fat', with the given field values.
    209   void AppendFatArch(cpu_type_t type, cpu_subtype_t subtype,
    210                      Label offset, Label size, uint32_t align) {
    211     fat
    212         .B32(type)
    213         .B32(subtype)
    214         .B32(offset)
    215         .B32(size)
    216         .B32(align);
    217   }
    218   // Append |n| dummy 'fat_arch' entries to 'fat'. The cpu type and
    219   // subtype have unrealistic values.
    220   void AppendDummyArchEntries(int n) {
    221     for (int i = 0; i < n; i++)
    222       AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1);
    223   }
    224   void ReadFat(bool expect_parse_success = true) {
    225     ASSERT_TRUE(fat.GetContents(&contents));
    226     fat_bytes = reinterpret_cast<const uint8_t *>(contents.data());
    227     if (expect_parse_success) {
    228       EXPECT_TRUE(reader.Read(fat_bytes, contents.size()));
    229       object_files = reader.object_files(&object_files_size);
    230     }
    231     else
    232       EXPECT_FALSE(reader.Read(fat_bytes, contents.size()));
    233   }
    234   test_assembler::Section fat;
    235   MockFatReaderReporter reporter;
    236   FatReader reader;
    237   string contents;
    238   const uint8_t *fat_bytes;
    239   const struct fat_arch *object_files;
    240   size_t object_files_size;
    241 };
    242 
    243 class FatReaderTest: public FatReaderFixture, public Test { };
    244 
    245 TEST_F(FatReaderTest, BadMagic) {
    246   EXPECT_CALL(reporter, BadHeader()).Times(1);
    247   fat
    248       .B32(0xcafed00d)           // magic number (incorrect)
    249       .B32(10);                  // number of architectures
    250   AppendDummyArchEntries(10);
    251   ReadFat(false);
    252 }
    253 
    254 TEST_F(FatReaderTest, HeaderTooShort) {
    255   EXPECT_CALL(reporter, TooShort()).Times(1);
    256   fat
    257       .B32(0xcafebabe);             // magic number
    258   ReadFat(false);
    259 }
    260 
    261 TEST_F(FatReaderTest, ObjectListTooShort) {
    262   EXPECT_CALL(reporter, TooShort()).Times(1);
    263   fat
    264       .B32(0xcafebabe)              // magic number
    265       .B32(10);                     // number of architectures
    266   AppendDummyArchEntries(9);        // nine dummy architecture entries...
    267   fat                               // and a tenth, missing a byte at the end
    268       .B32(0x3d46c8fc)              // cpu type
    269       .B32(0x8a7bfb01)              // cpu subtype
    270       .B32(0)                       // offset
    271       .B32(0)                       // size
    272       .Append(3, '*');              // one byte short of a four-byte alignment
    273   ReadFat(false);
    274 }
    275 
    276 TEST_F(FatReaderTest, DataTooShort) {
    277   EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1);
    278   Label arch_data;
    279   fat
    280       .B32(0xcafebabe)              // magic number
    281       .B32(1);                      // number of architectures
    282   AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0);
    283   fat
    284       .Mark(&arch_data)             // file data begins here
    285       .Append(30, '*');             // only 30 bytes, not 40 as header claims
    286   ReadFat(false);
    287 }
    288 
    289 TEST_F(FatReaderTest, NoObjectFiles) {
    290   fat
    291       .B32(0xcafebabe)              // magic number
    292       .B32(0);                      // number of architectures
    293   ReadFat();
    294   EXPECT_EQ(0U, object_files_size);
    295 }
    296 
    297 TEST_F(FatReaderTest, OneObjectFile) {
    298   Label obj1_offset;
    299   fat
    300       .B32(0xcafebabe)              // magic number
    301       .B32(1);                      // number of architectures
    302   // First object file list entry
    303   AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2);
    304   // First object file data
    305   fat
    306       .Mark(&obj1_offset)
    307       .Append(0x42, '*');           // dummy contents
    308   ReadFat();
    309   ASSERT_EQ(1U, object_files_size);
    310   EXPECT_EQ(0x5e3a6e91, object_files[0].cputype);
    311   EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype);
    312   EXPECT_EQ(obj1_offset.Value(), object_files[0].offset);
    313   EXPECT_EQ(0x42U, object_files[0].size);
    314   EXPECT_EQ(0x355b15b2U, object_files[0].align);
    315 }
    316 
    317 TEST_F(FatReaderTest, ThreeObjectFiles) {
    318   Label obj1, obj2, obj3;
    319   fat
    320       .B32(0xcafebabe)              // magic number
    321       .B32(3);                      // number of architectures
    322   // Three object file list entries.
    323   AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8);
    324   AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd);
    325   AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7);
    326   fat
    327       // First object file data
    328       .Mark(&obj1)
    329       .Append(0xfb4, '*')           // dummy contents
    330       // Second object file data
    331       .Mark(&obj2)
    332       .Append(0xc31, '%')           // dummy contents
    333       // Third object file data
    334       .Mark(&obj3)
    335       .Append(0x4b3, '^');          // dummy contents
    336 
    337   ReadFat();
    338 
    339   ASSERT_EQ(3U, object_files_size);
    340 
    341   // First object file.
    342   EXPECT_EQ(0x0cb92c30, object_files[0].cputype);
    343   EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype);
    344   EXPECT_EQ(obj1.Value(), object_files[0].offset);
    345   EXPECT_EQ(0xfb4U, object_files[0].size);
    346   EXPECT_EQ(0x2615dbe8U, object_files[0].align);
    347 
    348   // Second object file.
    349   EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype);
    350   EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype);
    351   EXPECT_EQ(obj2.Value(), object_files[1].offset);
    352   EXPECT_EQ(0xc31U, object_files[1].size);
    353   EXPECT_EQ(0x83af6ffdU, object_files[1].align);
    354 
    355   // Third object file.
    356   EXPECT_EQ(0x3717276d, object_files[2].cputype);
    357   EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype);
    358   EXPECT_EQ(obj3.Value(), object_files[2].offset);
    359   EXPECT_EQ(0x4b3U, object_files[2].size);
    360   EXPECT_EQ(0x035267d7U, object_files[2].align);
    361 }
    362 
    363 TEST_F(FatReaderTest, BigEndianMachO32) {
    364   fat.set_endianness(kBigEndian);
    365   fat
    366       .D32(0xfeedface)                  // Mach-O file magic number
    367       .D32(0x1a9d0518)                  // cpu type
    368       .D32(0x1b779357)                  // cpu subtype
    369       .D32(0x009df67e)                  // file type
    370       .D32(0)                           // no load commands
    371       .D32(0)                           // the load commands occupy no bytes
    372       .D32(0x21987a99);                 // flags
    373 
    374   ReadFat();
    375 
    376   // FatReader should treat a Mach-O file as if it were a fat binary file
    377   // containing one object file --- the whole thing.
    378   ASSERT_EQ(1U, object_files_size);
    379   EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
    380   EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
    381   EXPECT_EQ(0U, object_files[0].offset);
    382   EXPECT_EQ(contents.size(), object_files[0].size);
    383 }
    384 
    385 TEST_F(FatReaderTest, BigEndianMachO64) {
    386   fat.set_endianness(kBigEndian);
    387   fat
    388       .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
    389       .D32(0x5aff8487)                  // cpu type
    390       .D32(0x4c6a57f7)                  // cpu subtype
    391       .D32(0x4392d2c8)                  // file type
    392       .D32(0)                           // no load commands
    393       .D32(0)                           // the load commands occupy no bytes
    394       .D32(0x1b033eea);                 // flags
    395 
    396   ReadFat();
    397 
    398   // FatReader should treat a Mach-O file as if it were a fat binary file
    399   // containing one object file --- the whole thing.
    400   ASSERT_EQ(1U, object_files_size);
    401   EXPECT_EQ(0x5aff8487, object_files[0].cputype);
    402   EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
    403   EXPECT_EQ(0U, object_files[0].offset);
    404   EXPECT_EQ(contents.size(), object_files[0].size);
    405 }
    406 
    407 TEST_F(FatReaderTest, LittleEndianMachO32) {
    408   fat.set_endianness(kLittleEndian);
    409   fat
    410       .D32(0xfeedface)                  // Mach-O file magic number
    411       .D32(0x1a9d0518)                  // cpu type
    412       .D32(0x1b779357)                  // cpu subtype
    413       .D32(0x009df67e)                  // file type
    414       .D32(0)                           // no load commands
    415       .D32(0)                           // the load commands occupy no bytes
    416       .D32(0x21987a99);                 // flags
    417 
    418   ReadFat();
    419 
    420   // FatReader should treat a Mach-O file as if it were a fat binary file
    421   // containing one object file --- the whole thing.
    422   ASSERT_EQ(1U, object_files_size);
    423   EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
    424   EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
    425   EXPECT_EQ(0U, object_files[0].offset);
    426   EXPECT_EQ(contents.size(), object_files[0].size);
    427 }
    428 
    429 TEST_F(FatReaderTest, LittleEndianMachO64) {
    430   fat.set_endianness(kLittleEndian);
    431   fat
    432       .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
    433       .D32(0x5aff8487)                  // cpu type
    434       .D32(0x4c6a57f7)                  // cpu subtype
    435       .D32(0x4392d2c8)                  // file type
    436       .D32(0)                           // no load commands
    437       .D32(0)                           // the load commands occupy no bytes
    438       .D32(0x1b033eea);                 // flags
    439 
    440   ReadFat();
    441 
    442   // FatReader should treat a Mach-O file as if it were a fat binary file
    443   // containing one object file --- the whole thing.
    444   ASSERT_EQ(1U, object_files_size);
    445   EXPECT_EQ(0x5aff8487, object_files[0].cputype);
    446   EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
    447   EXPECT_EQ(0U, object_files[0].offset);
    448   EXPECT_EQ(contents.size(), object_files[0].size);
    449 }
    450 
    451 TEST_F(FatReaderTest, IncompleteMach) {
    452   fat.set_endianness(kLittleEndian);
    453   fat
    454       .D32(0xfeedfacf)                  // Mach-O 64-bit file magic number
    455       .D32(0x5aff8487);                 // cpu type
    456       // Truncated!
    457 
    458   EXPECT_CALL(reporter, TooShort()).WillOnce(Return());
    459 
    460   ReadFat(false);
    461 }
    462 
    463 
    464 // General mach_o::Reader tests.
    466 
    467 // Dynamically scoped configuration data.
    468 class WithConfiguration {
    469  public:
    470   // Establish the given parameters as the default for SizedSections
    471   // created within the dynamic scope of this instance.
    472   WithConfiguration(Endianness endianness, size_t word_size)
    473       : endianness_(endianness), word_size_(word_size), saved_(current_) {
    474     current_ = this;
    475   }
    476   ~WithConfiguration() { current_ = saved_; }
    477   static Endianness endianness() {
    478     assert(current_);
    479     return current_->endianness_;
    480   }
    481   static size_t word_size() {
    482     assert(current_);
    483     return current_->word_size_;
    484   }
    485 
    486  private:
    487   // The innermost WithConfiguration in whose dynamic scope we are
    488   // currently executing.
    489   static WithConfiguration *current_;
    490 
    491   // The innermost WithConfiguration whose dynamic scope encloses this
    492   // WithConfiguration.
    493   Endianness endianness_;
    494   size_t word_size_;
    495   WithConfiguration *saved_;
    496 };
    497 
    498 WithConfiguration *WithConfiguration::current_ = NULL;
    499 
    500 // A test_assembler::Section with a size that we can cite. The start(),
    501 // Here() and Mark() member functions of a SizedSection always represent
    502 // offsets within the overall file.
    503 class SizedSection: public test_assembler::Section {
    504  public:
    505   // Construct a section of the given endianness and word size.
    506   explicit SizedSection(Endianness endianness, size_t word_size)
    507       : test_assembler::Section(endianness), word_size_(word_size) {
    508     assert(word_size_ == 32 || word_size_ == 64);
    509   }
    510   SizedSection()
    511       : test_assembler::Section(WithConfiguration::endianness()),
    512         word_size_(WithConfiguration::word_size()) {
    513     assert(word_size_ == 32 || word_size_ == 64);
    514   }
    515 
    516   // Access/set this section's word size.
    517   size_t word_size() const { return word_size_; }
    518   void set_word_size(size_t word_size) {
    519     assert(word_size_ == 32 || word_size_ == 64);
    520     word_size_ = word_size;
    521   }
    522 
    523   // Return a label representing the size this section will have when it
    524   // is Placed in some containing section.
    525   Label final_size() const { return final_size_; }
    526 
    527   // Append SECTION to the end of this section, and call its Finish member.
    528   // Return a reference to this section.
    529   SizedSection &Place(SizedSection *section) {
    530     assert(section->endianness() == endianness());
    531     section->Finish();
    532     section->start() = Here();
    533     test_assembler::Section::Append(*section);
    534     return *this;
    535   }
    536 
    537  protected:
    538   // Mark this section's contents as complete. For plain SizedSections, we
    539   // set SECTION's start to its position in this section, and its final_size
    540   // label to its current size. Derived classes can extend this as needed
    541   // for their additional semantics.
    542   virtual void Finish() {
    543     final_size_ = Size();
    544   }
    545 
    546   // The word size for this data: either 32 or 64.
    547   size_t word_size_;
    548 
    549  private:
    550   // This section's final size, set when we are placed in some other
    551   // SizedSection.
    552   Label final_size_;
    553 };
    554 
    555 // A SizedSection that is loaded into memory at a particular address.
    556 class LoadedSection: public SizedSection {
    557  public:
    558   explicit LoadedSection(Label address = Label()) : address_(address) { }
    559 
    560   // Return a label representing this section's address.
    561   Label address() const { return address_; }
    562 
    563   // Placing a loaded section within a loaded section sets the relationship
    564   // between their addresses.
    565   LoadedSection &Place(LoadedSection *section) {
    566     section->address() = address() + Size();
    567     SizedSection::Place(section);
    568     return *this;
    569   }
    570 
    571  protected:
    572   // The address at which this section's contents will be loaded.
    573   Label address_;
    574 };
    575 
    576 // A SizedSection representing a segment load command.
    577 class SegmentLoadCommand: public SizedSection {
    578  public:
    579   SegmentLoadCommand() : section_count_(0) { }
    580 
    581   // Append a segment load command header with the given characteristics.
    582   // The load command will refer to CONTENTS, which must be Placed in the
    583   // file separately, at the desired position. Return a reference to this
    584   // section.
    585   SegmentLoadCommand &Header(const string &name, const LoadedSection &contents,
    586                              uint32_t maxprot, uint32_t initprot,
    587                              uint32_t flags) {
    588     assert(contents.word_size() == word_size());
    589     D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64);
    590     D32(final_size());
    591     AppendCString(name, 16);
    592     Append(endianness(), word_size() / 8, contents.address());
    593     Append(endianness(), word_size() / 8, vmsize_);
    594     Append(endianness(), word_size() / 8, contents.start());
    595     Append(endianness(), word_size() / 8, contents.final_size());
    596     D32(maxprot);
    597     D32(initprot);
    598     D32(final_section_count_);
    599     D32(flags);
    600 
    601     content_final_size_ = contents.final_size();
    602 
    603     return *this;
    604   }
    605 
    606   // Return a label representing the size of this segment when loaded into
    607   // memory. If this label is still undefined by the time we place this
    608   // segment, it defaults to the final size of the segment's in-file
    609   // contents. Return a reference to this load command.
    610   Label &vmsize() { return vmsize_; }
    611 
    612   // Add a section entry with the given characteristics to this segment
    613   // load command. Return a reference to this. The section entry will refer
    614   // to CONTENTS, which must be Placed in the segment's contents
    615   // separately, at the desired position.
    616   SegmentLoadCommand &AppendSectionEntry(const string &section_name,
    617                                          const string &segment_name,
    618                                          uint32_t alignment, uint32_t flags,
    619                                          const LoadedSection &contents) {
    620     AppendCString(section_name, 16);
    621     AppendCString(segment_name, 16);
    622     Append(endianness(), word_size() / 8, contents.address());
    623     Append(endianness(), word_size() / 8, contents.final_size());
    624     D32(contents.start());
    625     D32(alignment);
    626     D32(0);                  // relocations start
    627     D32(0);                  // relocations size
    628     D32(flags);
    629     D32(0x93656b95);         // reserved1
    630     D32(0xc35a2473);         // reserved2
    631     if (word_size() == 64)
    632       D32(0x70284b95);       // reserved3
    633 
    634     section_count_++;
    635 
    636     return *this;
    637   }
    638 
    639  protected:
    640   void Finish() {
    641     final_section_count_ = section_count_;
    642     if (!vmsize_.IsKnownConstant())
    643       vmsize_ = content_final_size_;
    644     SizedSection::Finish();
    645   }
    646 
    647  private:
    648   // The number of sections that have been added to this segment so far.
    649   size_t section_count_;
    650 
    651   // A label representing the final number of sections this segment will hold.
    652   Label final_section_count_;
    653 
    654   // The size of the contents for this segment present in the file.
    655   Label content_final_size_;
    656 
    657   // A label representing the size of this segment when loaded; this can be
    658   // larger than the size of its file contents, the difference being
    659   // zero-filled. If not set explicitly by calling set_vmsize, this is set
    660   // equal to the size of the contents.
    661   Label vmsize_;
    662 };
    663 
    664 // A SizedSection holding a list of Mach-O load commands.
    665 class LoadCommands: public SizedSection {
    666  public:
    667   LoadCommands() : command_count_(0) { }
    668 
    669   // Return a label representing the final load command count.
    670   Label final_command_count() const { return final_command_count_; }
    671 
    672   // Increment the command count; return a reference to this section.
    673   LoadCommands &CountCommand() {
    674     command_count_++;
    675     return *this;
    676   }
    677 
    678   // Place COMMAND, containing a load command, at the end of this section.
    679   // Return a reference to this section.
    680   LoadCommands &Place(SizedSection *section) {
    681     SizedSection::Place(section);
    682     CountCommand();
    683     return *this;
    684   }
    685 
    686  protected:
    687   // Mark this load command list as complete.
    688   void Finish() {
    689     SizedSection::Finish();
    690     final_command_count_ = command_count_;
    691   }
    692 
    693  private:
    694   // The number of load commands we have added to this file so far.
    695   size_t command_count_;
    696 
    697   // A label representing the final command count.
    698   Label final_command_count_;
    699 };
    700 
    701 // A SizedSection holding the contents of a Mach-O file. Within a
    702 // MachOFile, the start, Here, and Mark members refer to file offsets.
    703 class MachOFile: public SizedSection {
    704  public:
    705   MachOFile() {
    706     start() = 0;
    707   }
    708 
    709   // Create a Mach-O file header using the given characteristics and load
    710   // command list. This Places COMMANDS immediately after the header.
    711   // Return a reference to this section.
    712   MachOFile &Header(LoadCommands *commands,
    713                     cpu_type_t cpu_type = CPU_TYPE_X86,
    714                     cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL,
    715                     FileType file_type = MH_EXECUTE,
    716                     uint32_t file_flags = (MH_TWOLEVEL |
    717                                            MH_DYLDLINK |
    718                                            MH_NOUNDEFS)) {
    719     D32(word_size() == 32 ? 0xfeedface : 0xfeedfacf);  // magic number
    720     D32(cpu_type);                              // cpu type
    721     D32(cpu_subtype);                           // cpu subtype
    722     D32(file_type);                             // file type
    723     D32(commands->final_command_count());       // number of load commands
    724     D32(commands->final_size());                // their size in bytes
    725     D32(file_flags);                            // flags
    726     if (word_size() == 64)
    727       D32(0x55638b90);                          // reserved
    728     Place(commands);
    729     return *this;
    730   }
    731 };
    732 
    733 
    734 struct ReaderFixture {
    735   ReaderFixture()
    736       : reporter("reporter filename"),
    737         reader(&reporter) {
    738     EXPECT_CALL(reporter, BadHeader()).Times(0);
    739     EXPECT_CALL(reporter, CPUTypeMismatch(_, _, _, _)).Times(0);
    740     EXPECT_CALL(reporter, HeaderTruncated()).Times(0);
    741     EXPECT_CALL(reporter, LoadCommandRegionTruncated()).Times(0);
    742     EXPECT_CALL(reporter, LoadCommandsOverrun(_, _, _)).Times(0);
    743     EXPECT_CALL(reporter, LoadCommandTooShort(_, _)).Times(0);
    744     EXPECT_CALL(reporter, SectionsMissing(_)).Times(0);
    745     EXPECT_CALL(reporter, MisplacedSegmentData(_)).Times(0);
    746     EXPECT_CALL(reporter, MisplacedSectionData(_, _)).Times(0);
    747     EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(0);
    748     EXPECT_CALL(reporter, UnsupportedCPUType(_)).Times(0);
    749 
    750     EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0);
    751     EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
    752   }
    753 
    754   void ReadFile(MachOFile *file,
    755                 bool expect_parse_success,
    756                 cpu_type_t expected_cpu_type,
    757                 cpu_subtype_t expected_cpu_subtype) {
    758     ASSERT_TRUE(file->GetContents(&file_contents));
    759     file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data());
    760     if (expect_parse_success) {
    761       EXPECT_TRUE(reader.Read(file_bytes,
    762                               file_contents.size(),
    763                               expected_cpu_type,
    764                               expected_cpu_subtype));
    765     } else {
    766       EXPECT_FALSE(reader.Read(file_bytes,
    767                                file_contents.size(),
    768                                expected_cpu_type,
    769                                expected_cpu_subtype));
    770     }
    771   }
    772 
    773   string file_contents;
    774   const uint8_t *file_bytes;
    775   MockReaderReporter reporter;
    776   Reader reader;
    777   MockLoadCommandHandler load_command_handler;
    778   MockSectionHandler section_handler;
    779 };
    780 
    781 class ReaderTest: public ReaderFixture, public Test { };
    782 
    783 TEST_F(ReaderTest, BadMagic) {
    784   WithConfiguration config(kLittleEndian, 32);
    785   const cpu_type_t kCPUType = 0x46b760df;
    786   const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
    787   MachOFile file;
    788   file
    789       .D32(0x67bdebe1)                  // Not a proper magic number.
    790       .D32(kCPUType)                    // cpu type
    791       .D32(kCPUSubType)                 // cpu subtype
    792       .D32(0x149fc717)                  // file type
    793       .D32(0)                           // no load commands
    794       .D32(0)                           // they occupy no bytes
    795       .D32(0x80e71d64)                  // flags
    796       .D32(0);                          // reserved
    797   EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
    798   ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
    799 }
    800 
    801 TEST_F(ReaderTest, MismatchedMagic) {
    802   WithConfiguration config(kLittleEndian, 32);
    803   const cpu_type_t kCPUType = CPU_TYPE_I386;
    804   const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
    805   MachOFile file;
    806   file
    807       .D32(MH_CIGAM)                    // Right magic, but winds up wrong
    808                                         // due to bitswapping
    809       .D32(kCPUType)                    // cpu type
    810       .D32(kCPUSubType)                 // cpu subtype
    811       .D32(0x149fc717)                  // file type
    812       .D32(0)                           // no load commands
    813       .D32(0)                           // they occupy no bytes
    814       .D32(0x80e71d64)                  // flags
    815       .D32(0);                          // reserved
    816   EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
    817   ReadFile(&file, false, kCPUType, kCPUSubType);
    818 }
    819 
    820 TEST_F(ReaderTest, ShortMagic) {
    821   WithConfiguration config(kBigEndian, 32);
    822   MachOFile file;
    823   file
    824       .D16(0xfeed);                     // magic number
    825                                         // truncated!
    826   EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
    827   ReadFile(&file, false, CPU_TYPE_ANY, 0);
    828 }
    829 
    830 TEST_F(ReaderTest, ShortHeader) {
    831   WithConfiguration config(kBigEndian, 32);
    832   const cpu_type_t kCPUType = CPU_TYPE_ANY;
    833   const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
    834   MachOFile file;
    835   file
    836       .D32(0xfeedface)                  // magic number
    837       .D32(kCPUType)                    // cpu type
    838       .D32(kCPUSubType)                 // cpu subtype
    839       .D32(0x149fc717)                  // file type
    840       .D32(0)                           // no load commands
    841       .D32(0);                          // they occupy no bytes
    842   EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
    843   ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
    844 }
    845 
    846 TEST_F(ReaderTest, MismatchedCPU) {
    847   WithConfiguration config(kBigEndian, 32);
    848   const cpu_type_t kCPUType = CPU_TYPE_I386;
    849   const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
    850   MachOFile file;
    851   file
    852       .D32(MH_MAGIC)                    // Right magic for PPC (once bitswapped)
    853       .D32(kCPUType)                    // cpu type
    854       .D32(kCPUSubType)                 // cpu subtype
    855       .D32(0x149fc717)                  // file type
    856       .D32(0)                           // no load commands
    857       .D32(0)                           // they occupy no bytes
    858       .D32(0x80e71d64)                  // flags
    859       .D32(0);                          // reserved
    860   EXPECT_CALL(reporter,
    861               CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
    862                               CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL))
    863     .WillOnce(Return());
    864   ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
    865 }
    866 
    867 TEST_F(ReaderTest, LittleEndian32Bit) {
    868   WithConfiguration config(kLittleEndian, 32);
    869   const cpu_type_t kCPUType = 0x46b760df;
    870   const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
    871   MachOFile file;
    872   file
    873       .D32(0xfeedface)                  // magic number
    874       .D32(kCPUType)                    // cpu type
    875       .D32(kCPUSubType)                 // cpu subtype
    876       .D32(0x149fc717)                  // file type
    877       .D32(0)                           // no load commands
    878       .D32(0)                           // they occupy no bytes
    879       .D32(0x80e71d64)                  // flags
    880       .D32(0);                          // reserved
    881            ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
    882   EXPECT_FALSE(reader.bits_64());
    883   EXPECT_FALSE(reader.big_endian());
    884   EXPECT_EQ(kCPUType,               reader.cpu_type());
    885   EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
    886   EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
    887   EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
    888 }
    889 
    890 TEST_F(ReaderTest, LittleEndian64Bit) {
    891   WithConfiguration config(kLittleEndian, 64);
    892   const cpu_type_t kCPUType = 0x46b760df;
    893   const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
    894   MachOFile file;
    895   file
    896       .D32(0xfeedfacf)                  // magic number
    897       .D32(kCPUType)                    // cpu type
    898       .D32(kCPUSubType)                 // cpu subtype
    899       .D32(0x149fc717)                  // file type
    900       .D32(0)                           // no load commands
    901       .D32(0)                           // they occupy no bytes
    902       .D32(0x80e71d64)                  // flags
    903       .D32(0);                          // reserved
    904   ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
    905   EXPECT_TRUE(reader.bits_64());
    906   EXPECT_FALSE(reader.big_endian());
    907   EXPECT_EQ(kCPUType,               reader.cpu_type());
    908   EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
    909   EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
    910   EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
    911 }
    912 
    913 TEST_F(ReaderTest, BigEndian32Bit) {
    914   WithConfiguration config(kBigEndian, 32);
    915   const cpu_type_t kCPUType = 0x46b760df;
    916   const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
    917   MachOFile file;
    918   file
    919       .D32(0xfeedface)                  // magic number
    920       .D32(kCPUType)                    // cpu type
    921       .D32(kCPUSubType)                 // cpu subtype
    922       .D32(0x149fc717)                  // file type
    923       .D32(0)                           // no load commands
    924       .D32(0)                           // they occupy no bytes
    925       .D32(0x80e71d64)                  // flags
    926       .D32(0);                          // reserved
    927   ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
    928   EXPECT_FALSE(reader.bits_64());
    929   EXPECT_TRUE(reader.big_endian());
    930   EXPECT_EQ(kCPUType,               reader.cpu_type());
    931   EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
    932   EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
    933   EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
    934 }
    935 
    936 TEST_F(ReaderTest, BigEndian64Bit) {
    937   WithConfiguration config(kBigEndian, 64);
    938   const cpu_type_t kCPUType = 0x46b760df;
    939   const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
    940   MachOFile file;
    941   file
    942       .D32(0xfeedfacf)                  // magic number
    943       .D32(kCPUType)                    // cpu type
    944       .D32(kCPUSubType)                 // cpu subtype
    945       .D32(0x149fc717)                  // file type
    946       .D32(0)                           // no load commands
    947       .D32(0)                           // they occupy no bytes
    948       .D32(0x80e71d64)                  // flags
    949       .D32(0);                          // reserved
    950   ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
    951   EXPECT_TRUE(reader.bits_64());
    952   EXPECT_TRUE(reader.big_endian());
    953   EXPECT_EQ(kCPUType,               reader.cpu_type());
    954   EXPECT_EQ(kCPUSubType,            reader.cpu_subtype());
    955   EXPECT_EQ(FileType(0x149fc717),   reader.file_type());
    956   EXPECT_EQ(FileFlags(0x80e71d64),  reader.flags());
    957 }
    958 
    959 
    960 // Load command tests.
    962 
    963 class LoadCommand: public ReaderFixture, public Test { };
    964 
    965 TEST_F(LoadCommand, RegionTruncated) {
    966   WithConfiguration config(kBigEndian, 64);
    967   const cpu_type_t kCPUType = 0x46b760df;
    968   const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
    969   MachOFile file;
    970   file
    971       .D32(0xfeedfacf)                  // magic number
    972       .D32(kCPUType)                    // cpu type
    973       .D32(kCPUSubType)                 // cpu subtype
    974       .D32(0x149fc717)                  // file type
    975       .D32(1)                           // one load command
    976       .D32(40)                          // occupying 40 bytes
    977       .D32(0x80e71d64)                  // flags
    978       .D32(0)                           // reserved
    979       .Append(20, 0);                   // load command region, not as long as
    980                                         // Mach-O header promised
    981 
    982   EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return());
    983 
    984   ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
    985 }
    986 
    987 TEST_F(LoadCommand, None) {
    988   WithConfiguration config(kLittleEndian, 32);
    989   LoadCommands load_commands;
    990   MachOFile file;
    991   file.Header(&load_commands);
    992 
    993   ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL);
    994 
    995   EXPECT_FALSE(reader.bits_64());
    996   EXPECT_FALSE(reader.big_endian());
    997   EXPECT_EQ(CPU_TYPE_X86,         reader.cpu_type());
    998   EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
    999   EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
   1000   EXPECT_EQ(FileFlags(MH_TWOLEVEL |
   1001                       MH_DYLDLINK |
   1002                       MH_NOUNDEFS),
   1003             FileFlags(reader.flags()));
   1004 
   1005   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1006 }
   1007 
   1008 TEST_F(LoadCommand, Unknown) {
   1009   WithConfiguration config(kBigEndian, 32);
   1010   LoadCommands load_commands;
   1011   load_commands
   1012       .CountCommand()
   1013       .D32(0x33293d4a)                  // unknown load command
   1014       .D32(40)                          // total size in bytes
   1015       .Append(32, '*');                 // dummy data
   1016   MachOFile file;
   1017   file.Header(&load_commands);
   1018 
   1019   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1020 
   1021   EXPECT_FALSE(reader.bits_64());
   1022   EXPECT_TRUE(reader.big_endian());
   1023   EXPECT_EQ(CPU_TYPE_X86,         reader.cpu_type());
   1024   EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
   1025   EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
   1026   EXPECT_EQ(FileFlags(MH_TWOLEVEL |
   1027                       MH_DYLDLINK |
   1028                       MH_NOUNDEFS),
   1029             reader.flags());
   1030 
   1031   ByteBuffer expected;
   1032   expected.start = file_bytes + load_commands.start().Value();
   1033   expected.end = expected.start + load_commands.final_size().Value();
   1034   EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a,
   1035                                                    expected))
   1036       .WillOnce(Return(true));
   1037 
   1038   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1039 }
   1040 
   1041 TEST_F(LoadCommand, TypeIncomplete) {
   1042   WithConfiguration config(kLittleEndian, 32);
   1043   LoadCommands load_commands;
   1044   load_commands
   1045       .CountCommand()
   1046       .Append(3, 0);                    // load command type, incomplete
   1047 
   1048   MachOFile file;
   1049   file.Header(&load_commands);
   1050 
   1051   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1052 
   1053   EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0))
   1054       .WillOnce(Return());
   1055   EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
   1056 }
   1057 
   1058 TEST_F(LoadCommand, LengthIncomplete) {
   1059   WithConfiguration config(kBigEndian, 64);
   1060   LoadCommands load_commands;
   1061   load_commands
   1062       .CountCommand()
   1063       .D32(LC_SEGMENT);                 // load command
   1064                                                 // no length
   1065   MachOFile file;
   1066   file.Header(&load_commands);
   1067 
   1068   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1069 
   1070   EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
   1071       .WillOnce(Return());
   1072   EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
   1073 }
   1074 
   1075 TEST_F(LoadCommand, ContentIncomplete) {
   1076   WithConfiguration config(kLittleEndian, 64);
   1077   LoadCommands load_commands;
   1078   load_commands
   1079       .CountCommand()
   1080       .D32(LC_SEGMENT)          // load command
   1081       .D32(40)                          // total size in bytes
   1082       .Append(28, '*');                 // not enough dummy data
   1083   MachOFile file;
   1084   file.Header(&load_commands);
   1085 
   1086   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1087 
   1088   EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
   1089       .WillOnce(Return());
   1090   EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
   1091 }
   1092 
   1093 TEST_F(LoadCommand, SegmentBE32) {
   1094   WithConfiguration config(kBigEndian, 32);
   1095   LoadedSection segment;
   1096   segment.address() = 0x1891139c;
   1097   segment.Append(42, '*');              // segment contents
   1098   SegmentLoadCommand segment_command;
   1099   segment_command
   1100       .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd);
   1101   segment_command.vmsize() = 0xcb76584fU;
   1102   LoadCommands load_commands;
   1103   load_commands.Place(&segment_command);
   1104   MachOFile file;
   1105   file
   1106       .Header(&load_commands)
   1107       .Place(&segment);
   1108 
   1109   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1110 
   1111   Segment actual_segment;
   1112   EXPECT_CALL(load_command_handler, SegmentCommand(_))
   1113     .WillOnce(DoAll(SaveArg<0>(&actual_segment),
   1114                     Return(true)));
   1115   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1116 
   1117   EXPECT_EQ(false,                        actual_segment.bits_64);
   1118   EXPECT_EQ("froon",                      actual_segment.name);
   1119   EXPECT_EQ(0x1891139cU,                  actual_segment.vmaddr);
   1120   EXPECT_EQ(0xcb76584fU,                  actual_segment.vmsize);
   1121   EXPECT_EQ(0x94d6dd22U,                  actual_segment.maxprot);
   1122   EXPECT_EQ(0x8bdbc319U,                  actual_segment.initprot);
   1123   EXPECT_EQ(0x990a16ddU,                  actual_segment.flags);
   1124   EXPECT_EQ(0U,                           actual_segment.nsects);
   1125   EXPECT_EQ(0U,                           actual_segment.section_list.Size());
   1126   EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
   1127 }
   1128 
   1129 TEST_F(LoadCommand, SegmentLE32) {
   1130   WithConfiguration config(kLittleEndian, 32);
   1131   LoadedSection segment;
   1132   segment.address() = 0x4b877866;
   1133   segment.Append(42, '*');              // segment contents
   1134   SegmentLoadCommand segment_command;
   1135   segment_command
   1136       .Header("sixteenprecisely", segment,
   1137               0x350759ed, 0x6cf5a62e, 0x990a16dd);
   1138   segment_command.vmsize() = 0xcb76584fU;
   1139   LoadCommands load_commands;
   1140   load_commands.Place(&segment_command);
   1141   MachOFile file;
   1142   file
   1143       .Header(&load_commands)
   1144       .Place(&segment);
   1145 
   1146   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1147 
   1148   Segment actual_segment;
   1149   EXPECT_CALL(load_command_handler, SegmentCommand(_))
   1150     .WillOnce(DoAll(SaveArg<0>(&actual_segment),
   1151                     Return(true)));
   1152   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1153 
   1154   EXPECT_EQ(false,                        actual_segment.bits_64);
   1155   EXPECT_EQ("sixteenprecisely",           actual_segment.name);
   1156   EXPECT_EQ(0x4b877866U,                  actual_segment.vmaddr);
   1157   EXPECT_EQ(0xcb76584fU,                  actual_segment.vmsize);
   1158   EXPECT_EQ(0x350759edU,                  actual_segment.maxprot);
   1159   EXPECT_EQ(0x6cf5a62eU,                  actual_segment.initprot);
   1160   EXPECT_EQ(0x990a16ddU,                  actual_segment.flags);
   1161   EXPECT_EQ(0U,                           actual_segment.nsects);
   1162   EXPECT_EQ(0U,                           actual_segment.section_list.Size());
   1163   EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
   1164 }
   1165 
   1166 TEST_F(LoadCommand, SegmentBE64) {
   1167   WithConfiguration config(kBigEndian, 64);
   1168   LoadedSection segment;
   1169   segment.address() = 0x79f484f77009e511ULL;
   1170   segment.Append(42, '*');              // segment contents
   1171   SegmentLoadCommand segment_command;
   1172   segment_command
   1173       .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220);
   1174   segment_command.vmsize() = 0x8d92397ce6248abaULL;
   1175   LoadCommands load_commands;
   1176   load_commands.Place(&segment_command);
   1177   MachOFile file;
   1178   file
   1179       .Header(&load_commands)
   1180       .Place(&segment);
   1181 
   1182   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1183 
   1184   Segment actual_segment;
   1185   EXPECT_CALL(load_command_handler, SegmentCommand(_))
   1186     .WillOnce(DoAll(SaveArg<0>(&actual_segment),
   1187                     Return(true)));
   1188   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1189 
   1190   EXPECT_EQ(true,                         actual_segment.bits_64);
   1191   EXPECT_EQ("froon",                      actual_segment.name);
   1192   EXPECT_EQ(0x79f484f77009e511ULL,        actual_segment.vmaddr);
   1193   EXPECT_EQ(0x8d92397ce6248abaULL,        actual_segment.vmsize);
   1194   EXPECT_EQ(0x42b45da5U,                  actual_segment.maxprot);
   1195   EXPECT_EQ(0x8bdbc319U,                  actual_segment.initprot);
   1196   EXPECT_EQ(0xb2335220U,                  actual_segment.flags);
   1197   EXPECT_EQ(0U,                           actual_segment.nsects);
   1198   EXPECT_EQ(0U,                           actual_segment.section_list.Size());
   1199   EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
   1200 }
   1201 
   1202 TEST_F(LoadCommand, SegmentLE64) {
   1203   WithConfiguration config(kLittleEndian, 64);
   1204   LoadedSection segment;
   1205   segment.address() = 0x50c0501dc5922d35ULL;
   1206   segment.Append(42, '*');              // segment contents
   1207   SegmentLoadCommand segment_command;
   1208   segment_command
   1209       .Header("sixteenprecisely", segment,
   1210               0x917c339d, 0xdbc446fa, 0xb650b563);
   1211   segment_command.vmsize() = 0x84ae73e7c75469bfULL;
   1212   LoadCommands load_commands;
   1213   load_commands.Place(&segment_command);
   1214   MachOFile file;
   1215   file
   1216       .Header(&load_commands)
   1217       .Place(&segment);
   1218 
   1219   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1220 
   1221   Segment actual_segment;
   1222   EXPECT_CALL(load_command_handler, SegmentCommand(_))
   1223     .WillOnce(DoAll(SaveArg<0>(&actual_segment),
   1224                     Return(true)));
   1225   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1226 
   1227   EXPECT_EQ(true,                         actual_segment.bits_64);
   1228   EXPECT_EQ("sixteenprecisely",           actual_segment.name);
   1229   EXPECT_EQ(0x50c0501dc5922d35ULL,        actual_segment.vmaddr);
   1230   EXPECT_EQ(0x84ae73e7c75469bfULL,        actual_segment.vmsize);
   1231   EXPECT_EQ(0x917c339dU,                  actual_segment.maxprot);
   1232   EXPECT_EQ(0xdbc446faU,                  actual_segment.initprot);
   1233   EXPECT_EQ(0xb650b563U,                  actual_segment.flags);
   1234   EXPECT_EQ(0U,                           actual_segment.nsects);
   1235   EXPECT_EQ(0U,                           actual_segment.section_list.Size());
   1236   EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
   1237 }
   1238 
   1239 TEST_F(LoadCommand, SegmentCommandTruncated) {
   1240   WithConfiguration config(kBigEndian, 32);
   1241   LoadedSection segment_contents;
   1242   segment_contents.Append(20, '*');     	// lah di dah
   1243   SizedSection command;
   1244   command
   1245       .D32(LC_SEGMENT)          	// command type
   1246       .D32(command.final_size())                // command size
   1247       .AppendCString("too-short", 16)           // segment name
   1248       .D32(0x9c759211)                          // vmaddr
   1249       .D32(segment_contents.final_size())       // vmsize
   1250       .D32(segment_contents.start())            // file offset
   1251       .D32(segment_contents.final_size())       // file size
   1252       .D32(0x56f28446)                          // max protection
   1253       .D32(0xe7910dcb)                          // initial protection
   1254       .D32(0)                                   // no sections
   1255       .Append(3, 0);                            // flags (one byte short!)
   1256   LoadCommands load_commands;
   1257   load_commands.Place(&command);
   1258   MachOFile file;
   1259   file
   1260       .Header(&load_commands)
   1261       .Place(&segment_contents);
   1262 
   1263   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1264 
   1265   EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT))
   1266       .WillOnce(Return());
   1267 
   1268   EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
   1269 }
   1270 
   1271 TEST_F(LoadCommand, SegmentBadContentOffset) {
   1272   WithConfiguration config(kLittleEndian, 32);
   1273   // Instead of letting a Place call set the segment's file offset and size,
   1274   // set them ourselves, to check that the parser catches invalid offsets
   1275   // instead of handing us bogus pointers.
   1276   LoadedSection segment;
   1277   segment.address() = 0x4db5489c;
   1278   segment.start() = 0x7e189e76;         // beyond end of file
   1279   segment.final_size() = 0x98b9c3ab;
   1280   SegmentLoadCommand segment_command;
   1281   segment_command
   1282       .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f);
   1283   LoadCommands load_commands;
   1284   load_commands.Place(&segment_command);
   1285   MachOFile file;
   1286   file.Header(&load_commands);
   1287 
   1288   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1289 
   1290   EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen"))
   1291       .WillOnce(Return());
   1292 
   1293   EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
   1294 }
   1295 
   1296 TEST_F(LoadCommand, ThreeLoadCommands) {
   1297   WithConfiguration config(kBigEndian, 32);
   1298   LoadedSection seg1, seg2, seg3;
   1299   SegmentLoadCommand cmd1, cmd2, cmd3;
   1300 
   1301   seg1.Append(128, '@');
   1302   seg1.address() = 0xa7f61ef6;
   1303   cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87);
   1304   // Include some dummy data at the end of the load command. Since we
   1305   // didn't claim to have any sections, the reader should ignore this. But
   1306   // making sure the commands have different lengths ensures that we're
   1307   // using the right command's length to advance the LoadCommandIterator.
   1308   cmd1.Append(128, '!');
   1309 
   1310   seg2.Append(42, '*');
   1311   seg2.address() = 0xc70fc909;
   1312   cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30);
   1313   // More dummy data at the end of the load command.
   1314   cmd2.Append(32, '^');
   1315 
   1316   seg3.Append(42, '%');
   1317   seg3.address() = 0x46b3ab05;
   1318   cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b);
   1319   // More dummy data at the end of the load command.
   1320   cmd3.Append(64, '&');
   1321 
   1322   LoadCommands load_commands;
   1323   load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
   1324 
   1325   MachOFile file;
   1326   file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3);
   1327 
   1328   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1329 
   1330   {
   1331     InSequence s;
   1332     EXPECT_CALL(load_command_handler,
   1333                 SegmentCommand(Field(&Segment::name, "head")))
   1334       .WillOnce(Return(true));
   1335     EXPECT_CALL(load_command_handler,
   1336                 SegmentCommand(Field(&Segment::name, "thorax")))
   1337       .WillOnce(Return(true));
   1338     EXPECT_CALL(load_command_handler,
   1339                 SegmentCommand(Field(&Segment::name, "abdomen")))
   1340       .WillOnce(Return(true));
   1341   }
   1342 
   1343   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1344 }
   1345 
   1346 static inline Matcher<const Section &> MatchSection(
   1347     Matcher<bool> bits_64,
   1348     Matcher<const string &> section_name,
   1349     Matcher<const string &> segment_name,
   1350     Matcher<uint64_t> address,
   1351     Matcher<uint32_t> alignment,
   1352     Matcher<uint32_t> flags,
   1353     Matcher<const ByteBuffer &> contents) {
   1354   return AllOf(AllOf(Field(&Section::bits_64, bits_64),
   1355                      Field(&Section::section_name, section_name),
   1356                      Field(&Section::segment_name, segment_name),
   1357                      Field(&Section::address, address)),
   1358                AllOf(Field(&Section::align, alignment),
   1359                      Field(&Section::flags, flags),
   1360                      Field(&Section::contents, contents)));
   1361 }
   1362 
   1363 static inline Matcher<const Section &> MatchSection(
   1364     Matcher<bool> bits_64,
   1365     Matcher<const string &> section_name,
   1366     Matcher<const string &> segment_name,
   1367     Matcher<uint64_t> address) {
   1368   return AllOf(Field(&Section::bits_64, bits_64),
   1369                Field(&Section::section_name, section_name),
   1370                Field(&Section::segment_name, segment_name),
   1371                Field(&Section::address, address));
   1372 }
   1373 
   1374 TEST_F(LoadCommand, OneSegmentTwoSections) {
   1375   WithConfiguration config(kBigEndian, 64);
   1376 
   1377   // Create some sections with some data.
   1378   LoadedSection section1, section2;
   1379   section1.Append("buddha's hand");
   1380   section2.Append("kumquat");
   1381 
   1382   // Create a segment to hold them.
   1383   LoadedSection segment;
   1384   segment.address() = 0xe1d0eeec;
   1385   segment.Place(&section2).Place(&section1);
   1386 
   1387   SegmentLoadCommand segment_command;
   1388   segment_command
   1389       .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2)
   1390       .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1)
   1391       .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2);
   1392 
   1393   LoadCommands commands;
   1394   commands.Place(&segment_command);
   1395 
   1396   MachOFile file;
   1397   file.Header(&commands).Place(&segment);
   1398 
   1399   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1400 
   1401   Segment actual_segment;
   1402   EXPECT_CALL(load_command_handler, SegmentCommand(_))
   1403       .WillOnce(DoAll(SaveArg<0>(&actual_segment),
   1404                       Return(true)));
   1405   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1406 
   1407   {
   1408     InSequence s;
   1409     ByteBuffer contents1;
   1410     contents1.start = file_bytes + section1.start().Value();
   1411     contents1.end = contents1.start + section1.final_size().Value();
   1412     EXPECT_EQ("buddha's hand",
   1413               string(reinterpret_cast<const char *>(contents1.start),
   1414                      contents1.Size()));
   1415     EXPECT_CALL(section_handler,
   1416                 HandleSection(MatchSection(true, "mandarin", "kishu",
   1417                                            section1.address().Value(), 12,
   1418                                            0x8cd4604bU, contents1)))
   1419       .WillOnce(Return(true));
   1420 
   1421     ByteBuffer contents2;
   1422     contents2.start = file_bytes + section2.start().Value();
   1423     contents2.end = contents2.start + section2.final_size().Value();
   1424     EXPECT_EQ("kumquat",
   1425               string(reinterpret_cast<const char *>(contents2.start),
   1426                      contents2.Size()));
   1427     EXPECT_CALL(section_handler,
   1428                 HandleSection(MatchSection(true, "bergamot", "cara cara",
   1429                                            section2.address().Value(), 12,
   1430                                            0x98746efaU, contents2)))
   1431       .WillOnce(Return(true));
   1432   }
   1433 
   1434   EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
   1435 }
   1436 
   1437 TEST_F(LoadCommand, MisplacedSectionBefore) {
   1438   WithConfiguration config(kLittleEndian, 64);
   1439 
   1440   // The segment.
   1441   LoadedSection segment;
   1442   segment.address() = 0x696d83cc;
   1443   segment.Append(10, '0');
   1444 
   1445   // The contents of the following sections don't matter, because
   1446   // we're not really going to Place them in segment; we're just going
   1447   // to set all their labels by hand to get the (impossible)
   1448   // configurations we want.
   1449 
   1450   // A section whose starting offset is before that of its section.
   1451   LoadedSection before;
   1452   before.Append(10, '1');
   1453   before.start()   = segment.start() - 1;
   1454   before.address() = segment.address() - 1;
   1455   before.final_size() = before.Size();
   1456 
   1457   SegmentLoadCommand command;
   1458   command
   1459     .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
   1460     .AppendSectionEntry("before",     "segment", 0, 0x686c6921, before);
   1461 
   1462   LoadCommands commands;
   1463   commands.Place(&command);
   1464 
   1465   MachOFile file;
   1466   file.Header(&commands).Place(&segment);
   1467 
   1468   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1469 
   1470   Segment actual_segment;
   1471   EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
   1472 
   1473   EXPECT_CALL(reporter, MisplacedSectionData("before", "segment"))
   1474     .WillOnce(Return());
   1475   EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
   1476 }
   1477 
   1478 TEST_F(LoadCommand, MisplacedSectionAfter) {
   1479   WithConfiguration config(kLittleEndian, 64);
   1480 
   1481   // The segment.
   1482   LoadedSection segment;
   1483   segment.address() = 0x696d83cc;
   1484   segment.Append(10, '0');
   1485 
   1486   // The contents of the following sections don't matter, because
   1487   // we're not really going to Place them in segment; we're just going
   1488   // to set all their labels by hand to get the (impossible)
   1489   // configurations we want.
   1490 
   1491   // A section whose starting offset is after the end of its section.
   1492   LoadedSection after;
   1493   after.Append(10, '2');
   1494   after.start()    = segment.start() + 11;
   1495   after.address()   = segment.address() + 11;
   1496   after.final_size() = after.Size();
   1497 
   1498   SegmentLoadCommand command;
   1499   command
   1500     .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
   1501     .AppendSectionEntry("after",      "segment", 0, 0x2ee50124, after);
   1502 
   1503   LoadCommands commands;
   1504   commands.Place(&command);
   1505 
   1506   MachOFile file;
   1507   file.Header(&commands).Place(&segment);
   1508 
   1509   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1510 
   1511   Segment actual_segment;
   1512   EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
   1513 
   1514   EXPECT_CALL(reporter, MisplacedSectionData("after", "segment"))
   1515     .WillOnce(Return());
   1516   EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
   1517 }
   1518 
   1519 TEST_F(LoadCommand, MisplacedSectionTooBig) {
   1520   WithConfiguration config(kLittleEndian, 64);
   1521 
   1522   // The segment.
   1523   LoadedSection segment;
   1524   segment.address() = 0x696d83cc;
   1525   segment.Append(10, '0');
   1526 
   1527   // The contents of the following sections don't matter, because
   1528   // we're not really going to Place them in segment; we're just going
   1529   // to set all their labels by hand to get the (impossible)
   1530   // configurations we want.
   1531 
   1532   // A section that extends beyond the end of its section.
   1533   LoadedSection too_big;
   1534   too_big.Append(10, '3');
   1535   too_big.start()   = segment.start() + 1;
   1536   too_big.address() = segment.address() + 1;
   1537   too_big.final_size() = too_big.Size();
   1538 
   1539   SegmentLoadCommand command;
   1540   command
   1541     .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
   1542     .AppendSectionEntry("too big",    "segment", 0, 0x8b53ae5c, too_big);
   1543 
   1544   LoadCommands commands;
   1545   commands.Place(&command);
   1546 
   1547   MachOFile file;
   1548   file.Header(&commands).Place(&segment);
   1549 
   1550   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1551 
   1552   Segment actual_segment;
   1553   EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
   1554 
   1555   EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment"))
   1556     .WillOnce(Return());
   1557   EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
   1558 }
   1559 
   1560 
   1561 // The segments in a .dSYM bundle's Mach-O file have their file offset
   1562 // and size set to zero, but the sections don't.  The reader shouldn't
   1563 // report an error in this case.
   1564 TEST_F(LoadCommand, ZappedSegment) {
   1565   WithConfiguration config(kBigEndian, 32);
   1566 
   1567   // The segment.
   1568   LoadedSection segment;
   1569   segment.address() = 0x696d83cc;
   1570   segment.start() = 0;
   1571   segment.final_size() = 0;
   1572 
   1573   // The section.
   1574   LoadedSection section;
   1575   section.address() = segment.address();
   1576   section.start() = 0;
   1577   section.final_size() = 1000;          // extends beyond its segment
   1578 
   1579   SegmentLoadCommand command;
   1580   command
   1581     .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c)
   1582     .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section);
   1583 
   1584   LoadCommands commands;
   1585   commands.Place(&command);
   1586 
   1587   MachOFile file;
   1588   file.Header(&commands);
   1589 
   1590   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1591 
   1592   Segment actual_segment;
   1593   EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment));
   1594 
   1595   ByteBuffer zapped_extent(NULL, 0);
   1596   EXPECT_CALL(section_handler,
   1597               HandleSection(MatchSection(false, "twitching", "zapped",
   1598                                          0x696d83cc, 0, 0x93b3bd42,
   1599                                          zapped_extent)))
   1600     .WillOnce(Return(true));
   1601 
   1602   EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
   1603 }
   1604 
   1605 TEST_F(LoadCommand, MapSegmentSections) {
   1606   WithConfiguration config(kLittleEndian, 32);
   1607 
   1608   // Create some sections with some data.
   1609   LoadedSection section1, section2, section3, section4;
   1610   section1.Append("buddha's hand");
   1611   section2.start() = 0;                 // Section 2 is an S_ZEROFILL section.
   1612   section2.final_size() = 0;
   1613   section3.Append("shasta gold");
   1614   section4.Append("satsuma");
   1615 
   1616   // Create two segments to hold them.
   1617   LoadedSection segment1, segment2;
   1618   segment1.address() = 0x13e6c8a9;
   1619   segment1.Place(&section3).Place(&section1);
   1620   segment2.set_word_size(64);
   1621   segment2.address() = 0x04d462e2;
   1622   segment2.Place(&section4);
   1623   section2.address() = segment2.address() + segment2.Size();
   1624 
   1625   SegmentLoadCommand segment_command1, segment_command2;
   1626   segment_command1
   1627       .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64)
   1628       .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1)
   1629       .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3);
   1630   segment_command2.set_word_size(64);
   1631   segment_command2
   1632       .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33)
   1633       .AppendSectionEntry("sixteenprecisely", "thorax",
   1634                           12, S_ZEROFILL, section2)
   1635       .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4);
   1636 
   1637   LoadCommands commands;
   1638   commands.Place(&segment_command1).Place(&segment_command2);
   1639 
   1640   MachOFile file;
   1641   file.Header(&commands).Place(&segment1).Place(&segment2);
   1642 
   1643   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1644 
   1645   Segment segment;
   1646   SectionMap section_map;
   1647 
   1648   EXPECT_FALSE(reader.FindSegment("smoot", &segment));
   1649 
   1650   ASSERT_TRUE(reader.FindSegment("thorax", &segment));
   1651   ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
   1652 
   1653   EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome")
   1654                != section_map.end());
   1655   EXPECT_FALSE(section_map.find("mandarin") != section_map.end());
   1656   ASSERT_TRUE(section_map.find("cara cara") != section_map.end());
   1657   EXPECT_THAT(section_map["cara cara"],
   1658               MatchSection(true, "cara cara", "thorax", 0x04d462e2));
   1659   ASSERT_TRUE(section_map.find("sixteenprecisely")
   1660               != section_map.end());
   1661   ByteBuffer sixteenprecisely_contents(NULL, 0);
   1662   EXPECT_THAT(section_map["sixteenprecisely"],
   1663               MatchSection(true, "sixteenprecisely", "thorax",
   1664                            0x04d462e2 + 7, 12, S_ZEROFILL,
   1665                            sixteenprecisely_contents));
   1666 
   1667   ASSERT_TRUE(reader.FindSegment("head", &segment));
   1668   ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
   1669 
   1670   ASSERT_TRUE(section_map.find("mandarin") != section_map.end());
   1671   EXPECT_THAT(section_map["mandarin"],
   1672               MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11));
   1673   ASSERT_TRUE(section_map.find("bergamot") != section_map.end());
   1674   EXPECT_THAT(section_map["bergamot"],
   1675               MatchSection(false, "bergamot", "head", 0x13e6c8a9));
   1676 }
   1677 
   1678 TEST_F(LoadCommand, FindSegment) {
   1679   WithConfiguration config(kBigEndian, 32);
   1680 
   1681   LoadedSection segment1, segment2, segment3;
   1682   segment1.address() = 0xb8ae5752;
   1683   segment1.Append("Some contents!");
   1684   segment2.address() = 0xd6b0ce83;
   1685   segment2.Append("Different stuff.");
   1686   segment3.address() = 0x7374fd2a;
   1687   segment3.Append("Further materials.");
   1688 
   1689   SegmentLoadCommand cmd1, cmd2, cmd3;
   1690   cmd1.Header("first",  segment1, 0xfadb6932, 0x175bf529, 0x0de790ad);
   1691   cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef);
   1692   cmd3.Header("third",  segment3, 0xe172b39e, 0x86012f07, 0x080ac94d);
   1693 
   1694   LoadCommands commands;
   1695   commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
   1696 
   1697   MachOFile file;
   1698   file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3);
   1699 
   1700   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1701 
   1702   Segment actual_segment;
   1703 
   1704   EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment));
   1705 
   1706   EXPECT_TRUE(reader.FindSegment("second", &actual_segment));
   1707   EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr);
   1708 }
   1709 
   1710 
   1711 // Symtab tests.
   1713 
   1714 // A StringAssembler is a class for generating .stabstr sections to present
   1715 // as input to the STABS parser.
   1716 class StringAssembler: public SizedSection {
   1717  public:
   1718   // Add the string S to this StringAssembler, and return the string's
   1719   // offset within this compilation unit's strings.
   1720   size_t Add(const string &s) {
   1721     size_t offset = Size();
   1722     AppendCString(s);
   1723     return offset;
   1724   }
   1725 };
   1726 
   1727 // A SymbolAssembler is a class for generating .stab sections to present as
   1728 // test input for the STABS parser.
   1729 class SymbolAssembler: public SizedSection {
   1730  public:
   1731   // Create a SymbolAssembler that uses StringAssembler for its strings.
   1732   explicit SymbolAssembler(StringAssembler *string_assembler)
   1733       : string_assembler_(string_assembler),
   1734         entry_count_(0) { }
   1735 
   1736   // Append a STAB entry to the end of this section with the given
   1737   // characteristics. NAME is the offset of this entry's name string within
   1738   // its compilation unit's portion of the .stabstr section; this can be a
   1739   // value generated by a StringAssembler. Return a reference to this
   1740   // SymbolAssembler.
   1741   SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
   1742                           Label value, Label name) {
   1743     D32(name);
   1744     D8(type);
   1745     D8(other);
   1746     D16(descriptor);
   1747     Append(endianness(), word_size_ / 8, value);
   1748     entry_count_++;
   1749     return *this;
   1750   }
   1751 
   1752   // As above, but automatically add NAME to our StringAssembler.
   1753   SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
   1754                        Label value, const string &name) {
   1755     return Symbol(type, other, descriptor, value, string_assembler_->Add(name));
   1756   }
   1757 
   1758  private:
   1759   // The strings for our STABS entries.
   1760   StringAssembler *string_assembler_;
   1761 
   1762   // The number of entries in this compilation unit so far.
   1763   size_t entry_count_;
   1764 };
   1765 
   1766 class Symtab: public ReaderFixture, public Test { };
   1767 
   1768 TEST_F(Symtab, Symtab32) {
   1769   WithConfiguration config(kLittleEndian, 32);
   1770 
   1771   StringAssembler strings;
   1772   SymbolAssembler symbols(&strings);
   1773   symbols
   1774       .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu")
   1775       .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith");
   1776 
   1777   SizedSection symtab_command;
   1778   symtab_command
   1779       .D32(LC_SYMTAB)                    // command
   1780       .D32(symtab_command.final_size())  // size
   1781       .D32(symbols.start())              // file offset of symbols
   1782       .D32(2)                            // symbol count
   1783       .D32(strings.start())              // file offset of strings
   1784       .D32(strings.final_size());        // strings size
   1785 
   1786   LoadCommands load_commands;
   1787   load_commands.Place(&symtab_command);
   1788 
   1789   MachOFile file;
   1790   file.Header(&load_commands).Place(&symbols).Place(&strings);
   1791 
   1792   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1793 
   1794   ByteBuffer symbols_found, strings_found;
   1795   EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
   1796       .WillOnce(DoAll(SaveArg<0>(&symbols_found),
   1797                       SaveArg<1>(&strings_found),
   1798                       Return(true)));
   1799   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1800 
   1801   EXPECT_EQ(24U, symbols_found.Size());
   1802   EXPECT_EQ(14U, strings_found.Size());
   1803 }
   1804 
   1805 TEST_F(Symtab, Symtab64) {
   1806   WithConfiguration config(kBigEndian, 64);
   1807 
   1808   StringAssembler strings;
   1809   SymbolAssembler symbols(&strings);
   1810   symbols
   1811       .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
   1812       .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
   1813 
   1814   SizedSection symtab_command;
   1815   symtab_command
   1816       .D32(LC_SYMTAB)                    // command
   1817       .D32(symtab_command.final_size())  // size
   1818       .D32(symbols.start())              // file offset of symbols
   1819       .D32(2)                            // symbol count
   1820       .D32(strings.start())              // file offset of strings
   1821       .D32(strings.final_size());        // strings size
   1822 
   1823   LoadCommands load_commands;
   1824   load_commands.Place(&symtab_command);
   1825 
   1826   MachOFile file;
   1827   file.Header(&load_commands).Place(&symbols).Place(&strings);
   1828 
   1829   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1830 
   1831   ByteBuffer symbols_found, strings_found;
   1832   EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
   1833       .WillOnce(DoAll(SaveArg<0>(&symbols_found),
   1834                       SaveArg<1>(&strings_found),
   1835                       Return(true)));
   1836   EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
   1837 
   1838   EXPECT_EQ(32U, symbols_found.Size());
   1839   EXPECT_EQ(8U,  strings_found.Size());
   1840 }
   1841 
   1842 TEST_F(Symtab, SymtabMisplacedSymbols) {
   1843   WithConfiguration config(kBigEndian, 32);
   1844 
   1845   StringAssembler strings;
   1846   SymbolAssembler symbols(&strings);
   1847   symbols
   1848       .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
   1849       .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
   1850 
   1851   SizedSection symtab_command;
   1852   symtab_command
   1853       .D32(LC_SYMTAB)                    // command
   1854       .D32(symtab_command.final_size())  // size
   1855       .D32(symbols.start())              // file offset of symbols
   1856       .D32(3)                            // symbol count (too many)
   1857       .D32(strings.start())              // file offset of strings
   1858       .D32(strings.final_size());        // strings size
   1859 
   1860   LoadCommands load_commands;
   1861   load_commands.Place(&symtab_command);
   1862 
   1863   MachOFile file;
   1864   // Put symbols at end, so the excessive length will be noticed.
   1865   file.Header(&load_commands).Place(&strings).Place(&symbols);
   1866 
   1867   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1868 
   1869   EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
   1870   EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
   1871 }
   1872 
   1873 TEST_F(Symtab, SymtabMisplacedStrings) {
   1874   WithConfiguration config(kLittleEndian, 32);
   1875 
   1876   StringAssembler strings;
   1877   SymbolAssembler symbols(&strings);
   1878   symbols
   1879       .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
   1880       .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
   1881 
   1882   SizedSection symtab_command;
   1883   symtab_command
   1884       .D32(LC_SYMTAB)                    // command
   1885       .D32(symtab_command.final_size())  // size
   1886       .D32(symbols.start())              // file offset of symbols
   1887       .D32(2)                            // symbol count
   1888       .D32(strings.start())              // file offset of strings
   1889       .D32(strings.final_size() + 1);    // strings size (too long)
   1890 
   1891   LoadCommands load_commands;
   1892   load_commands.Place(&symtab_command);
   1893 
   1894   MachOFile file;
   1895   // Put strings at end, so the excessive length will be noticed.
   1896   file.Header(&load_commands).Place(&symbols).Place(&strings);
   1897 
   1898   ReadFile(&file, true, CPU_TYPE_ANY, 0);
   1899 
   1900   EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
   1901   EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
   1902 }
   1903 
   1904