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

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial