PageRenderTime 139ms CodeModel.GetById 19ms app.highlight 110ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/common/mac/macho_reader_unittest.cc

http://github.com/tomahawk-player/tomahawk
C++ | 1815 lines | 1378 code | 261 blank | 176 comment | 28 complexity | eb99e21c8389469df2b7230f41511ef9 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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@mozilla.com> <jimb@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
  43namespace mach_o = google_breakpad::mach_o;
  44namespace test_assembler = google_breakpad::test_assembler;
  45
  46using mach_o::FatReader;
  47using mach_o::FileFlags;
  48using mach_o::FileType;
  49using mach_o::LoadCommandType;
  50using mach_o::Reader;
  51using mach_o::Section;
  52using mach_o::SectionMap;
  53using mach_o::Segment;
  54using test_assembler::Endianness;
  55using test_assembler::Label;
  56using test_assembler::kBigEndian;
  57using test_assembler::kLittleEndian;
  58using test_assembler::kUnsetEndian;
  59using google_breakpad::ByteBuffer;
  60using std::map;
  61using std::string;
  62using std::vector;
  63using testing::AllOf;
  64using testing::DoAll;
  65using testing::Field;
  66using testing::InSequence;
  67using testing::Matcher;
  68using testing::Return;
  69using testing::SaveArg;
  70using testing::Test;
  71using testing::_;
  72
  73
  74// Mock classes for the reader's various reporters and handlers.
  75
  76class 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};
  84
  85class 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};
 105
 106class 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};
 112
 113class MockSectionHandler: public Reader::SectionHandler {
 114 public:
 115  MOCK_METHOD1(HandleSection, bool(const Section &section));
 116};
 117
 118
 119// Tests for mach_o::FatReader.
 120
 121// Since the effect of these functions is to write to stderr, the
 122// results of these tests must be inspected by hand.
 123TEST(FatReaderReporter, BadHeader) {
 124  FatReader::Reporter reporter("filename");
 125  reporter.BadHeader();
 126}
 127
 128TEST(FatReaderReporter, MisplacedObjectFile) {
 129  FatReader::Reporter reporter("filename");
 130  reporter.MisplacedObjectFile();
 131}
 132
 133TEST(FatReaderReporter, TooShort) {
 134  FatReader::Reporter reporter("filename");
 135  reporter.TooShort();
 136}
 137
 138TEST(MachOReaderReporter, BadHeader) {
 139  Reader::Reporter reporter("filename");
 140  reporter.BadHeader();
 141}
 142
 143TEST(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}
 148
 149TEST(MachOReaderReporter, HeaderTruncated) {
 150  Reader::Reporter reporter("filename");
 151  reporter.HeaderTruncated();
 152}
 153
 154TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
 155  Reader::Reporter reporter("filename");
 156  reporter.LoadCommandRegionTruncated();
 157}
 158
 159TEST(MachOReaderReporter, LoadCommandsOverrun) {
 160  Reader::Reporter reporter("filename");
 161  reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
 162  reporter.LoadCommandsOverrun(10, 9, 0);
 163}
 164
 165TEST(MachOReaderReporter, LoadCommandTooShort) {
 166  Reader::Reporter reporter("filename");
 167  reporter.LoadCommandTooShort(11, LC_SYMTAB);
 168}
 169
 170TEST(MachOReaderReporter, SectionsMissing) {
 171  Reader::Reporter reporter("filename");
 172  reporter.SectionsMissing("segment name");
 173}
 174
 175TEST(MachOReaderReporter, MisplacedSegmentData) {
 176  Reader::Reporter reporter("filename");
 177  reporter.MisplacedSegmentData("segment name");
 178}
 179
 180TEST(MachOReaderReporter, MisplacedSectionData) {
 181  Reader::Reporter reporter("filename");
 182  reporter.MisplacedSectionData("section name", "segment name");
 183}
 184
 185TEST(MachOReaderReporter, MisplacedSymbolTable) {
 186  Reader::Reporter reporter("filename");
 187  reporter.MisplacedSymbolTable();
 188}
 189
 190TEST(MachOReaderReporter, UnsupportedCPUType) {
 191  Reader::Reporter reporter("filename");
 192  reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
 193}
 194
 195struct 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);
 202
 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};
 240
 241class FatReaderTest: public FatReaderFixture, public Test { };
 242
 243TEST_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}
 251
 252TEST_F(FatReaderTest, HeaderTooShort) {
 253  EXPECT_CALL(reporter, TooShort()).Times(1);
 254  fat
 255      .B32(0xcafebabe);             // magic number
 256  ReadFat(false);
 257}
 258
 259TEST_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}
 273
 274TEST_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}
 286
 287TEST_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}
 294
 295TEST_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}
 314
 315TEST_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
 334  
 335  ReadFat();
 336
 337  ASSERT_EQ(3U, object_files_size);
 338
 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);
 345
 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);
 352
 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}
 360
 361TEST_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
 371
 372  ReadFat();
 373
 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}
 382
 383TEST_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
 393
 394  ReadFat();
 395
 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}
 404
 405TEST_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
 415
 416  ReadFat();
 417
 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}
 426
 427TEST_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
 437
 438  ReadFat();
 439
 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}
 448
 449TEST_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!
 455
 456  EXPECT_CALL(reporter, TooShort()).WillOnce(Return());
 457
 458  ReadFat(false);
 459}
 460
 461
 462// General mach_o::Reader tests.
 463
 464// Dynamically scoped configuration data.
 465class 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  }
 482
 483 private:
 484  // The innermost WithConfiguration in whose dynamic scope we are
 485  // currently executing.
 486  static WithConfiguration *current_;
 487
 488  // The innermost WithConfiguration whose dynamic scope encloses this
 489  // WithConfiguration.
 490  Endianness endianness_;
 491  size_t word_size_;
 492  WithConfiguration *saved_;
 493};
 494
 495WithConfiguration *WithConfiguration::current_ = NULL;
 496
 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.
 500class 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  }
 512
 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  }
 519
 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_; }
 523
 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  }
 533
 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  }
 542
 543  // The word size for this data: either 32 or 64.
 544  size_t word_size_;
 545
 546 private:
 547  // This section's final size, set when we are placed in some other
 548  // SizedSection.
 549  Label final_size_;
 550};
 551
 552// A SizedSection that is loaded into memory at a particular address.
 553class LoadedSection: public SizedSection {
 554 public:
 555  explicit LoadedSection(Label address = Label()) : address_(address) { }
 556
 557  // Return a label representing this section's address.
 558  Label address() const { return address_; }
 559
 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  }
 567
 568 protected:
 569  // The address at which this section's contents will be loaded.
 570  Label address_;
 571};
 572  
 573// A SizedSection representing a segment load command.
 574class SegmentLoadCommand: public SizedSection {
 575 public:
 576  SegmentLoadCommand() : section_count_(0) { }
 577
 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);
 597
 598    content_final_size_ = contents.final_size();
 599
 600    return *this;
 601  }
 602
 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_; }
 608
 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
 630
 631    section_count_++;
 632
 633    return *this;
 634  }
 635
 636 protected:
 637  void Finish() {
 638    final_section_count_ = section_count_;
 639    if (!vmsize_.IsKnownConstant())
 640      vmsize_ = content_final_size_;
 641    SizedSection::Finish();
 642  }
 643
 644 private:
 645  // The number of sections that have been added to this segment so far.
 646  size_t section_count_;
 647
 648  // A label representing the final number of sections this segment will hold.
 649  Label final_section_count_;
 650
 651  // The size of the contents for this segment present in the file.
 652  Label content_final_size_;
 653
 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};
 660
 661// A SizedSection holding a list of Mach-O load commands.
 662class LoadCommands: public SizedSection {
 663 public:
 664  LoadCommands() : command_count_(0) { }
 665
 666  // Return a label representing the final load command count.
 667  Label final_command_count() const { return final_command_count_; }
 668
 669  // Increment the command count; return a reference to this section.
 670  LoadCommands &CountCommand() {
 671    command_count_++;
 672    return *this;
 673  }
 674
 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  }
 682
 683 protected:
 684  // Mark this load command list as complete.
 685  void Finish() {
 686    SizedSection::Finish();
 687    final_command_count_ = command_count_;
 688  }
 689
 690 private:
 691  // The number of load commands we have added to this file so far.
 692  size_t command_count_;
 693
 694  // A label representing the final command count.
 695  Label final_command_count_;
 696};
 697
 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.
 700class MachOFile: public SizedSection {
 701 public:
 702  MachOFile() { 
 703    start() = 0;
 704  }
 705
 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};
 729
 730
 731struct 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);
 746
 747    EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0);
 748    EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
 749  }
 750
 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  }
 769
 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};
 777
 778class ReaderTest: public ReaderFixture, public Test { };
 779
 780TEST_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}
 797
 798TEST_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}
 816
 817TEST_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}
 826
 827TEST_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}
 842
 843TEST_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}
 863
 864TEST_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}
 886
 887TEST_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}
 909
 910TEST_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}
 932
 933TEST_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}
 955
 956
 957// Load command tests.
 958
 959class LoadCommand: public ReaderFixture, public Test { };
 960
 961TEST_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
 977
 978  EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return());
 979
 980  ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
 981}
 982
 983TEST_F(LoadCommand, None) {
 984  WithConfiguration config(kLittleEndian, 32);
 985  LoadCommands load_commands;
 986  MachOFile file;
 987  file.Header(&load_commands);
 988
 989  ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL);
 990
 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()));
1000  
1001  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1002}
1003
1004TEST_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);
1014
1015  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1016
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());
1026
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));
1033
1034  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1035}
1036
1037TEST_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
1043
1044  MachOFile file;
1045  file.Header(&load_commands);
1046
1047  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1048
1049  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0))
1050      .WillOnce(Return());
1051  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1052}
1053
1054TEST_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);
1063
1064  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1065
1066  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
1067      .WillOnce(Return());
1068  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1069}
1070
1071TEST_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);
1081
1082  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1083
1084  EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
1085      .WillOnce(Return());
1086  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1087}
1088
1089TEST_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);
1104
1105  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1106
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));
1112
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());
1123}
1124
1125TEST_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);
1141
1142  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1143
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));
1149
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());
1160}
1161
1162TEST_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);
1177
1178  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1179
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));
1185
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());
1196}
1197
1198TEST_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);
1214
1215  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1216
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));
1222
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());
1233}
1234
1235TEST_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);
1258  
1259  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1260
1261  EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT))
1262      .WillOnce(Return());
1263
1264  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1265}
1266
1267TEST_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);
1283
1284  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1285
1286  EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen"))
1287      .WillOnce(Return());
1288
1289  EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
1290}
1291
1292TEST_F(LoadCommand, ThreeLoadCommands) {
1293  WithConfiguration config(kBigEndian, 32);
1294  LoadedSection seg1, seg2, seg3;
1295  SegmentLoadCommand cmd1, cmd2, cmd3;
1296
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, '!');
1305
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, '^');
1311
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, '&');
1317
1318  LoadCommands load_commands;
1319  load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
1320
1321  MachOFile file;
1322  file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3);
1323
1324  ReadFile(&file, true, CPU_TYPE_ANY, 0);
1325
1326  {
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));
1337  }
1338
1339  EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
1340}
1341
1342static 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)));
1357}
1358
1359static inline Matcher<const Section &> M

Large files files are truncated, but you can click here to view the full file